aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac80211.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c256
1 files changed, 218 insertions, 38 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 9833cdf6177c..74bc2c8af06d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -77,6 +77,7 @@
77#include "iwl-eeprom-parse.h" 77#include "iwl-eeprom-parse.h"
78#include "fw-api-scan.h" 78#include "fw-api-scan.h"
79#include "iwl-phy-db.h" 79#include "iwl-phy-db.h"
80#include "testmode.h"
80 81
81static const struct ieee80211_iface_limit iwl_mvm_limits[] = { 82static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
82 { 83 {
@@ -138,6 +139,14 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
138 } 139 }
139} 140}
140 141
142static int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm)
143{
144 /* we create the 802.11 header and SSID element */
145 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID)
146 return mvm->fw->ucode_capa.max_probe_length - 24 - 2;
147 return mvm->fw->ucode_capa.max_probe_length - 24 - 34;
148}
149
141int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) 150int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
142{ 151{
143 struct ieee80211_hw *hw = mvm->hw; 152 struct ieee80211_hw *hw = mvm->hw;
@@ -155,10 +164,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
155 IEEE80211_HW_TIMING_BEACON_ONLY | 164 IEEE80211_HW_TIMING_BEACON_ONLY |
156 IEEE80211_HW_CONNECTION_MONITOR | 165 IEEE80211_HW_CONNECTION_MONITOR |
157 IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | 166 IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
158 IEEE80211_HW_SUPPORTS_STATIC_SMPS | 167 IEEE80211_HW_SUPPORTS_STATIC_SMPS;
159 IEEE80211_HW_SUPPORTS_UAPSD;
160 168
161 hw->queues = IWL_MVM_FIRST_AGG_QUEUE; 169 hw->queues = mvm->first_agg_queue;
162 hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; 170 hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
163 hw->rate_control_algorithm = "iwl-mvm-rs"; 171 hw->rate_control_algorithm = "iwl-mvm-rs";
164 172
@@ -171,6 +179,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
171 !iwlwifi_mod_params.sw_crypto) 179 !iwlwifi_mod_params.sw_crypto)
172 hw->flags |= IEEE80211_HW_MFP_CAPABLE; 180 hw->flags |= IEEE80211_HW_MFP_CAPABLE;
173 181
182 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) {
183 hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
184 hw->uapsd_queues = IWL_UAPSD_AC_INFO;
185 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
186 }
187
174 hw->sta_data_size = sizeof(struct iwl_mvm_sta); 188 hw->sta_data_size = sizeof(struct iwl_mvm_sta);
175 hw->vif_data_size = sizeof(struct iwl_mvm_vif); 189 hw->vif_data_size = sizeof(struct iwl_mvm_vif);
176 hw->chanctx_data_size = sizeof(u16); 190 hw->chanctx_data_size = sizeof(u16);
@@ -181,6 +195,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
181 BIT(NL80211_IFTYPE_P2P_GO) | 195 BIT(NL80211_IFTYPE_P2P_GO) |
182 BIT(NL80211_IFTYPE_P2P_DEVICE); 196 BIT(NL80211_IFTYPE_P2P_DEVICE);
183 197
198 /* IBSS has bugs in older versions */
199 if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
200 hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
201
184 hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | 202 hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
185 WIPHY_FLAG_DISABLE_BEACON_HINTS | 203 WIPHY_FLAG_DISABLE_BEACON_HINTS |
186 WIPHY_FLAG_IBSS_RSN; 204 WIPHY_FLAG_IBSS_RSN;
@@ -191,8 +209,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
191 209
192 hw->wiphy->max_remain_on_channel_duration = 10000; 210 hw->wiphy->max_remain_on_channel_duration = 10000;
193 hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; 211 hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
194 hw->uapsd_queues = IWL_UAPSD_AC_INFO;
195 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
196 212
197 /* Extract MAC address */ 213 /* Extract MAC address */
198 memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); 214 memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
@@ -212,9 +228,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
212 228
213 iwl_mvm_reset_phy_ctxts(mvm); 229 iwl_mvm_reset_phy_ctxts(mvm);
214 230
215 /* we create the 802.11 header and a max-length SSID element */ 231 hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
216 hw->wiphy->max_scan_ie_len = 232
217 mvm->fw->ucode_capa.max_probe_length - 24 - 34;
218 hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; 233 hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
219 234
220 if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) 235 if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
@@ -231,6 +246,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
231 else 246 else
232 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 247 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
233 248
249 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) {
250 hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
251 hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
252 hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
253 /* we create the 802.11 header and zero length SSID IE. */
254 hw->wiphy->max_sched_scan_ie_len =
255 SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
256 }
257
234 hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | 258 hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
235 NL80211_FEATURE_P2P_GO_OPPPS; 259 NL80211_FEATURE_P2P_GO_OPPPS;
236 260
@@ -548,7 +572,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
548 * In short: there's not much we can do at this point, other than 572 * In short: there's not much we can do at this point, other than
549 * allocating resources :) 573 * allocating resources :)
550 */ 574 */
551 if (vif->type == NL80211_IFTYPE_AP) { 575 if (vif->type == NL80211_IFTYPE_AP ||
576 vif->type == NL80211_IFTYPE_ADHOC) {
552 u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); 577 u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
553 ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, 578 ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
554 qmask); 579 qmask);
@@ -698,7 +723,14 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
698 * For AP/GO interface, the tear down of the resources allocated to the 723 * For AP/GO interface, the tear down of the resources allocated to the
699 * interface is be handled as part of the stop_ap flow. 724 * interface is be handled as part of the stop_ap flow.
700 */ 725 */
701 if (vif->type == NL80211_IFTYPE_AP) { 726 if (vif->type == NL80211_IFTYPE_AP ||
727 vif->type == NL80211_IFTYPE_ADHOC) {
728#ifdef CONFIG_NL80211_TESTMODE
729 if (vif == mvm->noa_vif) {
730 mvm->noa_vif = NULL;
731 mvm->noa_duration = 0;
732 }
733#endif
702 iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); 734 iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
703 goto out_release; 735 goto out_release;
704 } 736 }
@@ -796,6 +828,27 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
796 return; 828 return;
797 } 829 }
798 iwl_mvm_configure_mcast_filter(mvm, vif); 830 iwl_mvm_configure_mcast_filter(mvm, vif);
831
832 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
833 &mvm->status)) {
834 /*
835 * If we're restarting then the firmware will
836 * obviously have lost synchronisation with
837 * the AP. It will attempt to synchronise by
838 * itself, but we can make it more reliable by
839 * scheduling a session protection time event.
840 *
841 * The firmware needs to receive a beacon to
842 * catch up with synchronisation, use 110% of
843 * the beacon interval.
844 *
845 * Set a large maximum delay to allow for more
846 * than a single interface.
847 */
848 u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
849 iwl_mvm_protect_session(mvm, vif, dur, dur,
850 5 * dur);
851 }
799 } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { 852 } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
800 /* remove AP station now that the MAC is unassoc */ 853 /* remove AP station now that the MAC is unassoc */
801 ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); 854 ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
@@ -811,7 +864,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
811 /* reset rssi values */ 864 /* reset rssi values */
812 mvmvif->bf_data.ave_beacon_signal = 0; 865 mvmvif->bf_data.ave_beacon_signal = 0;
813 866
814 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) { 867 if (!(mvm->fw->ucode_capa.flags &
868 IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) {
815 /* Workaround for FW bug, otherwise FW disables device 869 /* Workaround for FW bug, otherwise FW disables device
816 * power save upon disassociation 870 * power save upon disassociation
817 */ 871 */
@@ -819,7 +873,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
819 if (ret) 873 if (ret)
820 IWL_ERR(mvm, "failed to update power mode\n"); 874 IWL_ERR(mvm, "failed to update power mode\n");
821 } 875 }
822 iwl_mvm_bt_coex_vif_assoc(mvm, vif); 876 iwl_mvm_bt_coex_vif_change(mvm);
823 } else if (changes & BSS_CHANGED_BEACON_INFO) { 877 } else if (changes & BSS_CHANGED_BEACON_INFO) {
824 /* 878 /*
825 * We received a beacon _after_ association so 879 * We received a beacon _after_ association so
@@ -848,7 +902,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
848 } 902 }
849} 903}
850 904
851static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 905static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
906 struct ieee80211_vif *vif)
852{ 907{
853 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 908 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
854 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 909 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -871,7 +926,7 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
871 if (ret) 926 if (ret)
872 goto out_remove; 927 goto out_remove;
873 928
874 mvmvif->ap_active = true; 929 mvmvif->ap_ibss_active = true;
875 930
876 /* Send the bcast station. At this stage the TBTT and DTIM time events 931 /* Send the bcast station. At this stage the TBTT and DTIM time events
877 * are added and applied to the scheduler */ 932 * are added and applied to the scheduler */
@@ -883,10 +938,12 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
883 if (ret) 938 if (ret)
884 goto out_rm_bcast; 939 goto out_rm_bcast;
885 940
886 /* Need to update the P2P Device MAC */ 941 /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
887 if (vif->p2p && mvm->p2p_device_vif) 942 if (vif->p2p && mvm->p2p_device_vif)
888 iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); 943 iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
889 944
945 iwl_mvm_bt_coex_vif_change(mvm);
946
890 mutex_unlock(&mvm->mutex); 947 mutex_unlock(&mvm->mutex);
891 return 0; 948 return 0;
892 949
@@ -901,7 +958,8 @@ out_unlock:
901 return ret; 958 return ret;
902} 959}
903 960
904static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 961static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
962 struct ieee80211_vif *vif)
905{ 963{
906 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 964 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
907 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 965 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -910,9 +968,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
910 968
911 mutex_lock(&mvm->mutex); 969 mutex_lock(&mvm->mutex);
912 970
913 mvmvif->ap_active = false; 971 mvmvif->ap_ibss_active = false;
972
973 iwl_mvm_bt_coex_vif_change(mvm);
914 974
915 /* Need to update the P2P Device MAC */ 975 /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
916 if (vif->p2p && mvm->p2p_device_vif) 976 if (vif->p2p && mvm->p2p_device_vif)
917 iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); 977 iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
918 978
@@ -924,10 +984,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
924 mutex_unlock(&mvm->mutex); 984 mutex_unlock(&mvm->mutex);
925} 985}
926 986
927static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm, 987static void
928 struct ieee80211_vif *vif, 988iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
929 struct ieee80211_bss_conf *bss_conf, 989 struct ieee80211_vif *vif,
930 u32 changes) 990 struct ieee80211_bss_conf *bss_conf,
991 u32 changes)
931{ 992{
932 /* Need to send a new beacon template to the FW */ 993 /* Need to send a new beacon template to the FW */
933 if (changes & BSS_CHANGED_BEACON) { 994 if (changes & BSS_CHANGED_BEACON) {
@@ -950,7 +1011,8 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
950 iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes); 1011 iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes);
951 break; 1012 break;
952 case NL80211_IFTYPE_AP: 1013 case NL80211_IFTYPE_AP:
953 iwl_mvm_bss_info_changed_ap(mvm, vif, bss_conf, changes); 1014 case NL80211_IFTYPE_ADHOC:
1015 iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes);
954 break; 1016 break;
955 default: 1017 default:
956 /* shouldn't happen */ 1018 /* shouldn't happen */
@@ -1163,7 +1225,54 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
1163 1225
1164 mutex_lock(&mvm->mutex); 1226 mutex_lock(&mvm->mutex);
1165 /* Try really hard to protect the session and hear a beacon */ 1227 /* Try really hard to protect the session and hear a beacon */
1166 iwl_mvm_protect_session(mvm, vif, duration, min_duration); 1228 iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
1229 mutex_unlock(&mvm->mutex);
1230}
1231
1232static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
1233 struct ieee80211_vif *vif,
1234 struct cfg80211_sched_scan_request *req,
1235 struct ieee80211_sched_scan_ies *ies)
1236{
1237 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1238 int ret;
1239
1240 mutex_lock(&mvm->mutex);
1241
1242 if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
1243 IWL_DEBUG_SCAN(mvm,
1244 "SCHED SCAN request during internal scan - abort\n");
1245 ret = -EBUSY;
1246 goto out;
1247 }
1248
1249 mvm->scan_status = IWL_MVM_SCAN_SCHED;
1250
1251 ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
1252 if (ret)
1253 goto err;
1254
1255 ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
1256 if (ret)
1257 goto err;
1258
1259 ret = iwl_mvm_sched_scan_start(mvm, req);
1260 if (!ret)
1261 goto out;
1262err:
1263 mvm->scan_status = IWL_MVM_SCAN_NONE;
1264out:
1265 mutex_unlock(&mvm->mutex);
1266 return ret;
1267}
1268
1269static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
1270 struct ieee80211_vif *vif)
1271{
1272 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1273
1274 mutex_lock(&mvm->mutex);
1275 iwl_mvm_sched_scan_stop(mvm);
1167 mutex_unlock(&mvm->mutex); 1276 mutex_unlock(&mvm->mutex);
1168} 1277}
1169 1278
@@ -1207,8 +1316,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
1207 1316
1208 switch (cmd) { 1317 switch (cmd) {
1209 case SET_KEY: 1318 case SET_KEY:
1210 if (vif->type == NL80211_IFTYPE_AP && !sta) { 1319 if ((vif->type == NL80211_IFTYPE_ADHOC ||
1211 /* GTK on AP interface is a TX-only key, return 0 */ 1320 vif->type == NL80211_IFTYPE_AP) && !sta) {
1321 /*
1322 * GTK on AP interface is a TX-only key, return 0;
1323 * on IBSS they're per-station and because we're lazy
1324 * we don't support them for RX, so do the same.
1325 */
1212 ret = 0; 1326 ret = 0;
1213 key->hw_key_idx = STA_KEY_IDX_INVALID; 1327 key->hw_key_idx = STA_KEY_IDX_INVALID;
1214 break; 1328 break;
@@ -1252,6 +1366,9 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
1252{ 1366{
1253 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1367 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1254 1368
1369 if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
1370 return;
1371
1255 iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key); 1372 iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key);
1256} 1373}
1257 1374
@@ -1445,6 +1562,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
1445 iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, 1562 iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
1446 ctx->rx_chains_static, 1563 ctx->rx_chains_static,
1447 ctx->rx_chains_dynamic); 1564 ctx->rx_chains_dynamic);
1565 iwl_mvm_bt_coex_vif_change(mvm);
1448 mutex_unlock(&mvm->mutex); 1566 mutex_unlock(&mvm->mutex);
1449} 1567}
1450 1568
@@ -1464,14 +1582,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
1464 1582
1465 switch (vif->type) { 1583 switch (vif->type) {
1466 case NL80211_IFTYPE_AP: 1584 case NL80211_IFTYPE_AP:
1585 case NL80211_IFTYPE_ADHOC:
1467 /* 1586 /*
1468 * The AP binding flow is handled as part of the start_ap flow 1587 * The AP binding flow is handled as part of the start_ap flow
1469 * (in bss_info_changed). 1588 * (in bss_info_changed), similarly for IBSS.
1470 */ 1589 */
1471 ret = 0; 1590 ret = 0;
1472 goto out_unlock; 1591 goto out_unlock;
1473 case NL80211_IFTYPE_STATION: 1592 case NL80211_IFTYPE_STATION:
1474 case NL80211_IFTYPE_ADHOC:
1475 case NL80211_IFTYPE_MONITOR: 1593 case NL80211_IFTYPE_MONITOR:
1476 break; 1594 break;
1477 default: 1595 default:
@@ -1517,10 +1635,10 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
1517 1635
1518 iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); 1636 iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);
1519 1637
1520 if (vif->type == NL80211_IFTYPE_AP)
1521 goto out_unlock;
1522
1523 switch (vif->type) { 1638 switch (vif->type) {
1639 case NL80211_IFTYPE_AP:
1640 case NL80211_IFTYPE_ADHOC:
1641 goto out_unlock;
1524 case NL80211_IFTYPE_MONITOR: 1642 case NL80211_IFTYPE_MONITOR:
1525 mvmvif->monitor_active = false; 1643 mvmvif->monitor_active = false;
1526 iwl_mvm_update_quotas(mvm, NULL); 1644 iwl_mvm_update_quotas(mvm, NULL);
@@ -1550,14 +1668,72 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
1550 return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); 1668 return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
1551} 1669}
1552 1670
1553static void iwl_mvm_mac_rssi_callback(struct ieee80211_hw *hw, 1671#ifdef CONFIG_NL80211_TESTMODE
1672static const struct nla_policy iwl_mvm_tm_policy[IWL_MVM_TM_ATTR_MAX + 1] = {
1673 [IWL_MVM_TM_ATTR_CMD] = { .type = NLA_U32 },
1674 [IWL_MVM_TM_ATTR_NOA_DURATION] = { .type = NLA_U32 },
1675 [IWL_MVM_TM_ATTR_BEACON_FILTER_STATE] = { .type = NLA_U32 },
1676};
1677
1678static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
1554 struct ieee80211_vif *vif, 1679 struct ieee80211_vif *vif,
1555 enum ieee80211_rssi_event rssi_event) 1680 void *data, int len)
1681{
1682 struct nlattr *tb[IWL_MVM_TM_ATTR_MAX + 1];
1683 int err;
1684 u32 noa_duration;
1685
1686 err = nla_parse(tb, IWL_MVM_TM_ATTR_MAX, data, len, iwl_mvm_tm_policy);
1687 if (err)
1688 return err;
1689
1690 if (!tb[IWL_MVM_TM_ATTR_CMD])
1691 return -EINVAL;
1692
1693 switch (nla_get_u32(tb[IWL_MVM_TM_ATTR_CMD])) {
1694 case IWL_MVM_TM_CMD_SET_NOA:
1695 if (!vif || vif->type != NL80211_IFTYPE_AP || !vif->p2p ||
1696 !vif->bss_conf.enable_beacon ||
1697 !tb[IWL_MVM_TM_ATTR_NOA_DURATION])
1698 return -EINVAL;
1699
1700 noa_duration = nla_get_u32(tb[IWL_MVM_TM_ATTR_NOA_DURATION]);
1701 if (noa_duration >= vif->bss_conf.beacon_int)
1702 return -EINVAL;
1703
1704 mvm->noa_duration = noa_duration;
1705 mvm->noa_vif = vif;
1706
1707 return iwl_mvm_update_quotas(mvm, NULL);
1708 case IWL_MVM_TM_CMD_SET_BEACON_FILTER:
1709 /* must be associated client vif - ignore authorized */
1710 if (!vif || vif->type != NL80211_IFTYPE_STATION ||
1711 !vif->bss_conf.assoc || !vif->bss_conf.dtim_period ||
1712 !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])
1713 return -EINVAL;
1714
1715 if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]))
1716 return iwl_mvm_enable_beacon_filter(mvm, vif);
1717 return iwl_mvm_disable_beacon_filter(mvm, vif);
1718 }
1719
1720 return -EOPNOTSUPP;
1721}
1722
1723static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
1724 struct ieee80211_vif *vif,
1725 void *data, int len)
1556{ 1726{
1557 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1727 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1728 int err;
1558 1729
1559 iwl_mvm_bt_rssi_event(mvm, vif, rssi_event); 1730 mutex_lock(&mvm->mutex);
1731 err = __iwl_mvm_mac_testmode_cmd(mvm, vif, data, len);
1732 mutex_unlock(&mvm->mutex);
1733
1734 return err;
1560} 1735}
1736#endif
1561 1737
1562struct ieee80211_ops iwl_mvm_hw_ops = { 1738struct ieee80211_ops iwl_mvm_hw_ops = {
1563 .tx = iwl_mvm_mac_tx, 1739 .tx = iwl_mvm_mac_tx,
@@ -1578,23 +1754,27 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
1578 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, 1754 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
1579 .conf_tx = iwl_mvm_mac_conf_tx, 1755 .conf_tx = iwl_mvm_mac_conf_tx,
1580 .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, 1756 .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
1757 .sched_scan_start = iwl_mvm_mac_sched_scan_start,
1758 .sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
1581 .set_key = iwl_mvm_mac_set_key, 1759 .set_key = iwl_mvm_mac_set_key,
1582 .update_tkip_key = iwl_mvm_mac_update_tkip_key, 1760 .update_tkip_key = iwl_mvm_mac_update_tkip_key,
1583 .remain_on_channel = iwl_mvm_roc, 1761 .remain_on_channel = iwl_mvm_roc,
1584 .cancel_remain_on_channel = iwl_mvm_cancel_roc, 1762 .cancel_remain_on_channel = iwl_mvm_cancel_roc,
1585 .rssi_callback = iwl_mvm_mac_rssi_callback,
1586
1587 .add_chanctx = iwl_mvm_add_chanctx, 1763 .add_chanctx = iwl_mvm_add_chanctx,
1588 .remove_chanctx = iwl_mvm_remove_chanctx, 1764 .remove_chanctx = iwl_mvm_remove_chanctx,
1589 .change_chanctx = iwl_mvm_change_chanctx, 1765 .change_chanctx = iwl_mvm_change_chanctx,
1590 .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, 1766 .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx,
1591 .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, 1767 .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx,
1592 1768
1593 .start_ap = iwl_mvm_start_ap, 1769 .start_ap = iwl_mvm_start_ap_ibss,
1594 .stop_ap = iwl_mvm_stop_ap, 1770 .stop_ap = iwl_mvm_stop_ap_ibss,
1771 .join_ibss = iwl_mvm_start_ap_ibss,
1772 .leave_ibss = iwl_mvm_stop_ap_ibss,
1595 1773
1596 .set_tim = iwl_mvm_set_tim, 1774 .set_tim = iwl_mvm_set_tim,
1597 1775
1776 CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)
1777
1598#ifdef CONFIG_PM_SLEEP 1778#ifdef CONFIG_PM_SLEEP
1599 /* look at d3.c */ 1779 /* look at d3.c */
1600 .suspend = iwl_mvm_suspend, 1780 .suspend = iwl_mvm_suspend,