diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac80211.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 256 |
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 | ||
81 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { | 82 | static 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 | ||
142 | static 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 | |||
141 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 150 | int 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 | ||
851 | static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 905 | static 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 | ||
904 | static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 961 | static 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 | ||
927 | static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm, | 987 | static void |
928 | struct ieee80211_vif *vif, | 988 | iwl_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 | |||
1232 | static 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; | ||
1262 | err: | ||
1263 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
1264 | out: | ||
1265 | mutex_unlock(&mvm->mutex); | ||
1266 | return ret; | ||
1267 | } | ||
1268 | |||
1269 | static 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 | ||
1553 | static void iwl_mvm_mac_rssi_callback(struct ieee80211_hw *hw, | 1671 | #ifdef CONFIG_NL80211_TESTMODE |
1672 | static 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 | |||
1678 | static 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 | |||
1723 | static 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 | ||
1562 | struct ieee80211_ops iwl_mvm_hw_ops = { | 1738 | struct 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, |