.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * BSS client mode implementation |
---|
3 | 4 | * Copyright 2003-2008, Jouni Malinen <j@w1.fi> |
---|
.. | .. |
---|
7 | 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
---|
8 | 9 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
---|
9 | 10 | * Copyright (C) 2015 - 2017 Intel Deutschland GmbH |
---|
10 | | - * Copyright (C) 2018 Intel Corporation |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or modify |
---|
13 | | - * it under the terms of the GNU General Public License version 2 as |
---|
14 | | - * published by the Free Software Foundation. |
---|
| 11 | + * Copyright (C) 2018 - 2020 Intel Corporation |
---|
15 | 12 | */ |
---|
16 | 13 | |
---|
17 | 14 | #include <linux/delay.h> |
---|
| 15 | +#include <linux/fips.h> |
---|
18 | 16 | #include <linux/if_ether.h> |
---|
19 | 17 | #include <linux/skbuff.h> |
---|
20 | 18 | #include <linux/if_arp.h> |
---|
.. | .. |
---|
39 | 37 | #define IEEE80211_AUTH_TIMEOUT_SAE (HZ * 2) |
---|
40 | 38 | #define IEEE80211_AUTH_MAX_TRIES 3 |
---|
41 | 39 | #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) |
---|
| 40 | +#define IEEE80211_AUTH_WAIT_SAE_RETRY (HZ * 2) |
---|
42 | 41 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
---|
43 | 42 | #define IEEE80211_ASSOC_TIMEOUT_LONG (HZ / 2) |
---|
44 | 43 | #define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10) |
---|
.. | .. |
---|
147 | 146 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, |
---|
148 | 147 | struct ieee80211_supported_band *sband, |
---|
149 | 148 | struct ieee80211_channel *channel, |
---|
| 149 | + u32 vht_cap_info, |
---|
150 | 150 | const struct ieee80211_ht_operation *ht_oper, |
---|
151 | 151 | const struct ieee80211_vht_operation *vht_oper, |
---|
152 | 152 | const struct ieee80211_he_operation *he_oper, |
---|
| 153 | + const struct ieee80211_s1g_oper_ie *s1g_oper, |
---|
153 | 154 | struct cfg80211_chan_def *chandef, bool tracking) |
---|
154 | 155 | { |
---|
155 | 156 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
.. | .. |
---|
157 | 158 | struct ieee80211_sta_ht_cap sta_ht_cap; |
---|
158 | 159 | u32 ht_cfreq, ret; |
---|
159 | 160 | |
---|
160 | | - memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); |
---|
161 | | - ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); |
---|
162 | | - |
---|
163 | 161 | memset(chandef, 0, sizeof(struct cfg80211_chan_def)); |
---|
164 | 162 | chandef->chan = channel; |
---|
165 | 163 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; |
---|
166 | 164 | chandef->center_freq1 = channel->center_freq; |
---|
| 165 | + chandef->freq1_offset = channel->freq_offset; |
---|
| 166 | + |
---|
| 167 | + if (channel->band == NL80211_BAND_6GHZ) { |
---|
| 168 | + if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, chandef)) |
---|
| 169 | + ret = IEEE80211_STA_DISABLE_HT | |
---|
| 170 | + IEEE80211_STA_DISABLE_VHT | |
---|
| 171 | + IEEE80211_STA_DISABLE_HE; |
---|
| 172 | + else |
---|
| 173 | + ret = 0; |
---|
| 174 | + vht_chandef = *chandef; |
---|
| 175 | + goto out; |
---|
| 176 | + } else if (sband->band == NL80211_BAND_S1GHZ) { |
---|
| 177 | + if (!ieee80211_chandef_s1g_oper(s1g_oper, chandef)) { |
---|
| 178 | + sdata_info(sdata, |
---|
| 179 | + "Missing S1G Operation Element? Trying operating == primary\n"); |
---|
| 180 | + chandef->width = ieee80211_s1g_channel_width(channel); |
---|
| 181 | + } |
---|
| 182 | + |
---|
| 183 | + ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_40MHZ | |
---|
| 184 | + IEEE80211_STA_DISABLE_VHT | |
---|
| 185 | + IEEE80211_STA_DISABLE_80P80MHZ | |
---|
| 186 | + IEEE80211_STA_DISABLE_160MHZ; |
---|
| 187 | + goto out; |
---|
| 188 | + } |
---|
| 189 | + |
---|
| 190 | + memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); |
---|
| 191 | + ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); |
---|
167 | 192 | |
---|
168 | 193 | if (!ht_oper || !sta_ht_cap.ht_supported) { |
---|
169 | | - ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; |
---|
| 194 | + ret = IEEE80211_STA_DISABLE_HT | |
---|
| 195 | + IEEE80211_STA_DISABLE_VHT | |
---|
| 196 | + IEEE80211_STA_DISABLE_HE; |
---|
170 | 197 | goto out; |
---|
171 | 198 | } |
---|
172 | 199 | |
---|
.. | .. |
---|
187 | 214 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", |
---|
188 | 215 | channel->center_freq, ht_cfreq, |
---|
189 | 216 | ht_oper->primary_chan, channel->band); |
---|
190 | | - ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; |
---|
| 217 | + ret = IEEE80211_STA_DISABLE_HT | |
---|
| 218 | + IEEE80211_STA_DISABLE_VHT | |
---|
| 219 | + IEEE80211_STA_DISABLE_HE; |
---|
191 | 220 | goto out; |
---|
192 | 221 | } |
---|
193 | 222 | |
---|
.. | .. |
---|
220 | 249 | memcpy(&he_oper_vht_cap, he_oper->optional, 3); |
---|
221 | 250 | he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0); |
---|
222 | 251 | |
---|
223 | | - if (!ieee80211_chandef_vht_oper(&he_oper_vht_cap, |
---|
| 252 | + if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, |
---|
| 253 | + &he_oper_vht_cap, ht_oper, |
---|
224 | 254 | &vht_chandef)) { |
---|
225 | 255 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) |
---|
226 | 256 | sdata_info(sdata, |
---|
.. | .. |
---|
228 | 258 | ret = IEEE80211_STA_DISABLE_HE; |
---|
229 | 259 | goto out; |
---|
230 | 260 | } |
---|
231 | | - } else if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) { |
---|
| 261 | + } else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, |
---|
| 262 | + vht_cap_info, |
---|
| 263 | + vht_oper, ht_oper, |
---|
| 264 | + &vht_chandef)) { |
---|
232 | 265 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
---|
233 | 266 | sdata_info(sdata, |
---|
234 | 267 | "AP VHT information is invalid, disable VHT\n"); |
---|
.. | .. |
---|
301 | 334 | IEEE80211_CHAN_DISABLED)) { |
---|
302 | 335 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { |
---|
303 | 336 | ret = IEEE80211_STA_DISABLE_HT | |
---|
304 | | - IEEE80211_STA_DISABLE_VHT; |
---|
| 337 | + IEEE80211_STA_DISABLE_VHT | |
---|
| 338 | + IEEE80211_STA_DISABLE_HE; |
---|
305 | 339 | break; |
---|
306 | 340 | } |
---|
307 | 341 | |
---|
308 | 342 | ret |= ieee80211_chandef_downgrade(chandef); |
---|
309 | 343 | } |
---|
| 344 | + |
---|
| 345 | + if (!he_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, |
---|
| 346 | + IEEE80211_CHAN_NO_HE)) |
---|
| 347 | + ret |= IEEE80211_STA_DISABLE_HE; |
---|
310 | 348 | |
---|
311 | 349 | if (chandef->width != vht_chandef.width && !tracking) |
---|
312 | 350 | sdata_info(sdata, |
---|
.. | .. |
---|
319 | 357 | static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, |
---|
320 | 358 | struct sta_info *sta, |
---|
321 | 359 | const struct ieee80211_ht_cap *ht_cap, |
---|
| 360 | + const struct ieee80211_vht_cap *vht_cap, |
---|
322 | 361 | const struct ieee80211_ht_operation *ht_oper, |
---|
323 | 362 | const struct ieee80211_vht_operation *vht_oper, |
---|
324 | 363 | const struct ieee80211_he_operation *he_oper, |
---|
| 364 | + const struct ieee80211_s1g_oper_ie *s1g_oper, |
---|
325 | 365 | const u8 *bssid, u32 *changed) |
---|
326 | 366 | { |
---|
327 | 367 | struct ieee80211_local *local = sdata->local; |
---|
.. | .. |
---|
333 | 373 | u16 ht_opmode; |
---|
334 | 374 | u32 flags; |
---|
335 | 375 | enum ieee80211_sta_rx_bandwidth new_sta_bw; |
---|
| 376 | + u32 vht_cap_info = 0; |
---|
336 | 377 | int ret; |
---|
337 | 378 | |
---|
338 | 379 | /* if HT was/is disabled, don't track any bandwidth changes */ |
---|
.. | .. |
---|
361 | 402 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; |
---|
362 | 403 | } |
---|
363 | 404 | |
---|
| 405 | + if (vht_cap) |
---|
| 406 | + vht_cap_info = le32_to_cpu(vht_cap->vht_cap_info); |
---|
| 407 | + |
---|
364 | 408 | /* calculate new channel (type) based on HT/VHT/HE operation IEs */ |
---|
365 | | - flags = ieee80211_determine_chantype(sdata, sband, chan, |
---|
| 409 | + flags = ieee80211_determine_chantype(sdata, sband, chan, vht_cap_info, |
---|
366 | 410 | ht_oper, vht_oper, he_oper, |
---|
367 | | - &chandef, true); |
---|
| 411 | + s1g_oper, &chandef, true); |
---|
368 | 412 | |
---|
369 | 413 | /* |
---|
370 | 414 | * Downgrade the new channel if we associated with restricted |
---|
.. | .. |
---|
387 | 431 | return 0; |
---|
388 | 432 | |
---|
389 | 433 | sdata_info(sdata, |
---|
390 | | - "AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n", |
---|
391 | | - ifmgd->bssid, chandef.chan->center_freq, chandef.width, |
---|
392 | | - chandef.center_freq1, chandef.center_freq2); |
---|
| 434 | + "AP %pM changed bandwidth, new config is %d.%03d MHz, " |
---|
| 435 | + "width %d (%d.%03d/%d MHz)\n", |
---|
| 436 | + ifmgd->bssid, chandef.chan->center_freq, |
---|
| 437 | + chandef.chan->freq_offset, chandef.width, |
---|
| 438 | + chandef.center_freq1, chandef.freq1_offset, |
---|
| 439 | + chandef.center_freq2); |
---|
393 | 440 | |
---|
394 | 441 | if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | |
---|
395 | 442 | IEEE80211_STA_DISABLE_VHT | |
---|
| 443 | + IEEE80211_STA_DISABLE_HE | |
---|
396 | 444 | IEEE80211_STA_DISABLE_40MHZ | |
---|
397 | 445 | IEEE80211_STA_DISABLE_80P80MHZ | |
---|
398 | 446 | IEEE80211_STA_DISABLE_160MHZ)) || |
---|
.. | .. |
---|
500 | 548 | case IEEE80211_SMPS_AUTOMATIC: |
---|
501 | 549 | case IEEE80211_SMPS_NUM_MODES: |
---|
502 | 550 | WARN_ON(1); |
---|
503 | | - /* fall through */ |
---|
| 551 | + fallthrough; |
---|
504 | 552 | case IEEE80211_SMPS_OFF: |
---|
505 | 553 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << |
---|
506 | 554 | IEEE80211_HT_CAP_SM_PS_SHIFT; |
---|
.. | .. |
---|
616 | 664 | { |
---|
617 | 665 | u8 *pos; |
---|
618 | 666 | const struct ieee80211_sta_he_cap *he_cap = NULL; |
---|
| 667 | + struct ieee80211_chanctx_conf *chanctx_conf; |
---|
619 | 668 | u8 he_cap_size; |
---|
| 669 | + bool reg_cap = false; |
---|
| 670 | + |
---|
| 671 | + rcu_read_lock(); |
---|
| 672 | + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
---|
| 673 | + if (!WARN_ON_ONCE(!chanctx_conf)) |
---|
| 674 | + reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy, |
---|
| 675 | + &chanctx_conf->def, |
---|
| 676 | + IEEE80211_CHAN_NO_HE); |
---|
| 677 | + |
---|
| 678 | + rcu_read_unlock(); |
---|
620 | 679 | |
---|
621 | 680 | he_cap = ieee80211_get_he_sta_cap(sband); |
---|
622 | | - if (!he_cap) |
---|
| 681 | + if (!he_cap || !reg_cap) |
---|
623 | 682 | return; |
---|
624 | 683 | |
---|
625 | 684 | /* |
---|
.. | .. |
---|
633 | 692 | he_cap->he_cap_elem.phy_cap_info); |
---|
634 | 693 | pos = skb_put(skb, he_cap_size); |
---|
635 | 694 | ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size); |
---|
| 695 | + |
---|
| 696 | + ieee80211_ie_build_he_6ghz_cap(sdata, skb); |
---|
636 | 697 | } |
---|
637 | 698 | |
---|
638 | 699 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
---|
.. | .. |
---|
642 | 703 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; |
---|
643 | 704 | struct sk_buff *skb; |
---|
644 | 705 | struct ieee80211_mgmt *mgmt; |
---|
645 | | - u8 *pos, qos_info; |
---|
| 706 | + u8 *pos, qos_info, *ie_start; |
---|
646 | 707 | size_t offset = 0, noffset; |
---|
647 | 708 | int i, count, rates_len, supp_rates_len, shift; |
---|
648 | 709 | u16 capab; |
---|
.. | .. |
---|
650 | 711 | struct ieee80211_chanctx_conf *chanctx_conf; |
---|
651 | 712 | struct ieee80211_channel *chan; |
---|
652 | 713 | u32 rates = 0; |
---|
| 714 | + __le16 listen_int; |
---|
| 715 | + struct element *ext_capa = NULL; |
---|
| 716 | + |
---|
| 717 | + /* we know it's writable, cast away the const */ |
---|
| 718 | + if (assoc_data->ie_len) |
---|
| 719 | + ext_capa = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, |
---|
| 720 | + assoc_data->ie, |
---|
| 721 | + assoc_data->ie_len); |
---|
653 | 722 | |
---|
654 | 723 | sdata_assert_lock(sdata); |
---|
655 | 724 | |
---|
.. | .. |
---|
699 | 768 | 2 + 1 + sizeof(struct ieee80211_he_cap_elem) + /* HE */ |
---|
700 | 769 | sizeof(struct ieee80211_he_mcs_nss_supp) + |
---|
701 | 770 | IEEE80211_HE_PPE_THRES_MAX_LEN + |
---|
| 771 | + 2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) + |
---|
702 | 772 | assoc_data->ie_len + /* extra IEs */ |
---|
703 | 773 | (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) + |
---|
704 | 774 | 9, /* WMM */ |
---|
.. | .. |
---|
730 | 800 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
---|
731 | 801 | memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN); |
---|
732 | 802 | |
---|
| 803 | + listen_int = cpu_to_le16(sband->band == NL80211_BAND_S1GHZ ? |
---|
| 804 | + ieee80211_encode_usf(local->hw.conf.listen_interval) : |
---|
| 805 | + local->hw.conf.listen_interval); |
---|
733 | 806 | if (!is_zero_ether_addr(assoc_data->prev_bssid)) { |
---|
734 | 807 | skb_put(skb, 10); |
---|
735 | 808 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
---|
736 | 809 | IEEE80211_STYPE_REASSOC_REQ); |
---|
737 | 810 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); |
---|
738 | | - mgmt->u.reassoc_req.listen_interval = |
---|
739 | | - cpu_to_le16(local->hw.conf.listen_interval); |
---|
| 811 | + mgmt->u.reassoc_req.listen_interval = listen_int; |
---|
740 | 812 | memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid, |
---|
741 | 813 | ETH_ALEN); |
---|
742 | 814 | } else { |
---|
.. | .. |
---|
744 | 816 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
---|
745 | 817 | IEEE80211_STYPE_ASSOC_REQ); |
---|
746 | 818 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); |
---|
747 | | - mgmt->u.assoc_req.listen_interval = |
---|
748 | | - cpu_to_le16(local->hw.conf.listen_interval); |
---|
| 819 | + mgmt->u.assoc_req.listen_interval = listen_int; |
---|
749 | 820 | } |
---|
750 | 821 | |
---|
751 | 822 | /* SSID */ |
---|
752 | 823 | pos = skb_put(skb, 2 + assoc_data->ssid_len); |
---|
| 824 | + ie_start = pos; |
---|
753 | 825 | *pos++ = WLAN_EID_SSID; |
---|
754 | 826 | *pos++ = assoc_data->ssid_len; |
---|
755 | 827 | memcpy(pos, assoc_data->ssid, assoc_data->ssid_len); |
---|
| 828 | + |
---|
| 829 | + if (sband->band == NL80211_BAND_S1GHZ) |
---|
| 830 | + goto skip_rates; |
---|
756 | 831 | |
---|
757 | 832 | /* add all rates which were marked to be used above */ |
---|
758 | 833 | supp_rates_len = rates_len; |
---|
.. | .. |
---|
789 | 864 | } |
---|
790 | 865 | } |
---|
791 | 866 | |
---|
| 867 | +skip_rates: |
---|
792 | 868 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT || |
---|
793 | 869 | capab & WLAN_CAPABILITY_RADIO_MEASURE) { |
---|
794 | 870 | pos = skb_put(skb, 4); |
---|
.. | .. |
---|
799 | 875 | *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def); |
---|
800 | 876 | } |
---|
801 | 877 | |
---|
802 | | - if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { |
---|
| 878 | + /* |
---|
| 879 | + * Per spec, we shouldn't include the list of channels if we advertise |
---|
| 880 | + * support for extended channel switching, but we've always done that; |
---|
| 881 | + * (for now?) apply this restriction only on the (new) 6 GHz band. |
---|
| 882 | + */ |
---|
| 883 | + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT && |
---|
| 884 | + (sband->band != NL80211_BAND_6GHZ || |
---|
| 885 | + !ext_capa || ext_capa->datalen < 1 || |
---|
| 886 | + !(ext_capa->data[0] & WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING))) { |
---|
803 | 887 | /* TODO: get this in reg domain format */ |
---|
804 | 888 | pos = skb_put(skb, 2 * sband->n_channels + 2); |
---|
805 | 889 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; |
---|
.. | .. |
---|
810 | 894 | *pos++ = 1; /* one channel in the subband*/ |
---|
811 | 895 | } |
---|
812 | 896 | } |
---|
| 897 | + |
---|
| 898 | + /* Set MBSSID support for HE AP if needed */ |
---|
| 899 | + if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) && |
---|
| 900 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len && |
---|
| 901 | + ext_capa && ext_capa->datalen >= 3) |
---|
| 902 | + ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; |
---|
813 | 903 | |
---|
814 | 904 | /* if present, add any custom IEs that go before HT */ |
---|
815 | 905 | if (assoc_data->ie_len) { |
---|
.. | .. |
---|
856 | 946 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))) |
---|
857 | 947 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
858 | 948 | |
---|
859 | | - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
---|
| 949 | + if (sband->band != NL80211_BAND_6GHZ && |
---|
| 950 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
---|
860 | 951 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, |
---|
861 | 952 | sband, chan, sdata->smps_mode); |
---|
862 | 953 | |
---|
.. | .. |
---|
910 | 1001 | offset = noffset; |
---|
911 | 1002 | } |
---|
912 | 1003 | |
---|
913 | | - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
---|
| 1004 | + if (sband->band != NL80211_BAND_6GHZ && |
---|
| 1005 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
---|
914 | 1006 | ieee80211_add_vht_ie(sdata, skb, sband, |
---|
915 | 1007 | &assoc_data->ap_vht_cap); |
---|
| 1008 | + |
---|
| 1009 | + /* |
---|
| 1010 | + * If AP doesn't support HT, mark HE as disabled. |
---|
| 1011 | + * If on the 5GHz band, make sure it supports VHT. |
---|
| 1012 | + */ |
---|
| 1013 | + if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || |
---|
| 1014 | + (sband->band == NL80211_BAND_5GHZ && |
---|
| 1015 | + ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
---|
| 1016 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
916 | 1017 | |
---|
917 | 1018 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) |
---|
918 | 1019 | ieee80211_add_he_ie(sdata, skb, sband); |
---|
.. | .. |
---|
938 | 1039 | pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); |
---|
939 | 1040 | } |
---|
940 | 1041 | |
---|
| 1042 | + if (sband->band == NL80211_BAND_S1GHZ) { |
---|
| 1043 | + ieee80211_add_aid_request_ie(sdata, skb); |
---|
| 1044 | + ieee80211_add_s1g_capab_ie(sdata, &sband->s1g_cap, skb); |
---|
| 1045 | + } |
---|
| 1046 | + |
---|
941 | 1047 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
---|
942 | 1048 | if (assoc_data->ie_len) { |
---|
943 | 1049 | noffset = assoc_data->ie_len; |
---|
.. | .. |
---|
949 | 1055 | dev_kfree_skb(skb); |
---|
950 | 1056 | return; |
---|
951 | 1057 | } |
---|
| 1058 | + |
---|
| 1059 | + pos = skb_tail_pointer(skb); |
---|
| 1060 | + kfree(ifmgd->assoc_req_ies); |
---|
| 1061 | + ifmgd->assoc_req_ies = kmemdup(ie_start, pos - ie_start, GFP_ATOMIC); |
---|
| 1062 | + ifmgd->assoc_req_ies_len = pos - ie_start; |
---|
952 | 1063 | |
---|
953 | 1064 | drv_mgd_prepare_tx(local, sdata, 0); |
---|
954 | 1065 | |
---|
.. | .. |
---|
984 | 1095 | struct ieee80211_hdr_3addr *nullfunc; |
---|
985 | 1096 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
986 | 1097 | |
---|
987 | | - /* Don't send NDPs when STA is connected HE */ |
---|
988 | | - if (sdata->vif.type == NL80211_IFTYPE_STATION && |
---|
989 | | - !(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) |
---|
990 | | - return; |
---|
991 | | - |
---|
992 | 1098 | skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, |
---|
993 | 1099 | !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP)); |
---|
994 | 1100 | if (!skb) |
---|
.. | .. |
---|
1010 | 1116 | ieee80211_tx_skb(sdata, skb); |
---|
1011 | 1117 | } |
---|
1012 | 1118 | |
---|
1013 | | -static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, |
---|
1014 | | - struct ieee80211_sub_if_data *sdata) |
---|
| 1119 | +void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, |
---|
| 1120 | + struct ieee80211_sub_if_data *sdata) |
---|
1015 | 1121 | { |
---|
1016 | 1122 | struct sk_buff *skb; |
---|
1017 | 1123 | struct ieee80211_hdr *nullfunc; |
---|
1018 | 1124 | __le16 fc; |
---|
1019 | 1125 | |
---|
1020 | 1126 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
---|
1021 | | - return; |
---|
1022 | | - |
---|
1023 | | - /* Don't send NDPs when connected HE */ |
---|
1024 | | - if (!(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE)) |
---|
1025 | 1127 | return; |
---|
1026 | 1128 | |
---|
1027 | 1129 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); |
---|
.. | .. |
---|
1229 | 1331 | } |
---|
1230 | 1332 | |
---|
1231 | 1333 | static void |
---|
| 1334 | +ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata) |
---|
| 1335 | +{ |
---|
| 1336 | + struct ieee80211_local *local = sdata->local; |
---|
| 1337 | + |
---|
| 1338 | + if (!local->ops->abort_channel_switch) |
---|
| 1339 | + return; |
---|
| 1340 | + |
---|
| 1341 | + mutex_lock(&local->mtx); |
---|
| 1342 | + |
---|
| 1343 | + mutex_lock(&local->chanctx_mtx); |
---|
| 1344 | + ieee80211_vif_unreserve_chanctx(sdata); |
---|
| 1345 | + mutex_unlock(&local->chanctx_mtx); |
---|
| 1346 | + |
---|
| 1347 | + if (sdata->csa_block_tx) |
---|
| 1348 | + ieee80211_wake_vif_queues(local, sdata, |
---|
| 1349 | + IEEE80211_QUEUE_STOP_REASON_CSA); |
---|
| 1350 | + |
---|
| 1351 | + sdata->csa_block_tx = false; |
---|
| 1352 | + sdata->vif.csa_active = false; |
---|
| 1353 | + |
---|
| 1354 | + mutex_unlock(&local->mtx); |
---|
| 1355 | + |
---|
| 1356 | + drv_abort_channel_switch(sdata); |
---|
| 1357 | +} |
---|
| 1358 | + |
---|
| 1359 | +static void |
---|
1232 | 1360 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
---|
1233 | 1361 | u64 timestamp, u32 device_timestamp, |
---|
1234 | 1362 | struct ieee802_11_elems *elems, |
---|
.. | .. |
---|
1242 | 1370 | enum nl80211_band current_band; |
---|
1243 | 1371 | struct ieee80211_csa_ie csa_ie; |
---|
1244 | 1372 | struct ieee80211_channel_switch ch_switch; |
---|
| 1373 | + struct ieee80211_bss *bss; |
---|
1245 | 1374 | int res; |
---|
1246 | 1375 | |
---|
1247 | 1376 | sdata_assert_lock(sdata); |
---|
.. | .. |
---|
1252 | 1381 | if (local->scanning) |
---|
1253 | 1382 | return; |
---|
1254 | 1383 | |
---|
1255 | | - /* disregard subsequent announcements if we are already processing */ |
---|
1256 | | - if (sdata->vif.csa_active) |
---|
1257 | | - return; |
---|
1258 | | - |
---|
1259 | 1384 | current_band = cbss->channel->band; |
---|
| 1385 | + bss = (void *)cbss->priv; |
---|
1260 | 1386 | res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band, |
---|
| 1387 | + bss->vht_cap_info, |
---|
1261 | 1388 | ifmgd->flags, |
---|
1262 | 1389 | ifmgd->associated->bssid, &csa_ie); |
---|
1263 | | - if (res < 0) |
---|
| 1390 | + |
---|
| 1391 | + if (!res) { |
---|
| 1392 | + ch_switch.timestamp = timestamp; |
---|
| 1393 | + ch_switch.device_timestamp = device_timestamp; |
---|
| 1394 | + ch_switch.block_tx = csa_ie.mode; |
---|
| 1395 | + ch_switch.chandef = csa_ie.chandef; |
---|
| 1396 | + ch_switch.count = csa_ie.count; |
---|
| 1397 | + ch_switch.delay = csa_ie.max_switch_time; |
---|
| 1398 | + } |
---|
| 1399 | + |
---|
| 1400 | + if (res < 0) { |
---|
1264 | 1401 | ieee80211_queue_work(&local->hw, |
---|
1265 | 1402 | &ifmgd->csa_connection_drop_work); |
---|
1266 | | - if (res) |
---|
1267 | 1403 | return; |
---|
| 1404 | + } |
---|
| 1405 | + |
---|
| 1406 | + if (beacon && sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) { |
---|
| 1407 | + if (res) |
---|
| 1408 | + ieee80211_sta_abort_chanswitch(sdata); |
---|
| 1409 | + else |
---|
| 1410 | + drv_channel_switch_rx_beacon(sdata, &ch_switch); |
---|
| 1411 | + return; |
---|
| 1412 | + } else if (sdata->vif.csa_active || res) { |
---|
| 1413 | + /* disregard subsequent announcements if already processing */ |
---|
| 1414 | + return; |
---|
| 1415 | + } |
---|
1268 | 1416 | |
---|
1269 | 1417 | if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef, |
---|
1270 | 1418 | IEEE80211_CHAN_DISABLED)) { |
---|
1271 | 1419 | sdata_info(sdata, |
---|
1272 | | - "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", |
---|
| 1420 | + "AP %pM switches to unsupported channel " |
---|
| 1421 | + "(%d.%03d MHz, width:%d, CF1/2: %d.%03d/%d MHz), " |
---|
| 1422 | + "disconnecting\n", |
---|
1273 | 1423 | ifmgd->associated->bssid, |
---|
1274 | 1424 | csa_ie.chandef.chan->center_freq, |
---|
| 1425 | + csa_ie.chandef.chan->freq_offset, |
---|
1275 | 1426 | csa_ie.chandef.width, csa_ie.chandef.center_freq1, |
---|
| 1427 | + csa_ie.chandef.freq1_offset, |
---|
1276 | 1428 | csa_ie.chandef.center_freq2); |
---|
1277 | 1429 | ieee80211_queue_work(&local->hw, |
---|
1278 | 1430 | &ifmgd->csa_connection_drop_work); |
---|
.. | .. |
---|
1280 | 1432 | } |
---|
1281 | 1433 | |
---|
1282 | 1434 | if (cfg80211_chandef_identical(&csa_ie.chandef, |
---|
1283 | | - &sdata->vif.bss_conf.chandef)) { |
---|
| 1435 | + &sdata->vif.bss_conf.chandef) && |
---|
| 1436 | + (!csa_ie.mode || !beacon)) { |
---|
1284 | 1437 | if (ifmgd->csa_ignored_same_chan) |
---|
1285 | 1438 | return; |
---|
1286 | 1439 | sdata_info(sdata, |
---|
.. | .. |
---|
1316 | 1469 | "driver doesn't support chan-switch with channel contexts\n"); |
---|
1317 | 1470 | goto drop_connection; |
---|
1318 | 1471 | } |
---|
1319 | | - |
---|
1320 | | - ch_switch.timestamp = timestamp; |
---|
1321 | | - ch_switch.device_timestamp = device_timestamp; |
---|
1322 | | - ch_switch.block_tx = csa_ie.mode; |
---|
1323 | | - ch_switch.chandef = csa_ie.chandef; |
---|
1324 | | - ch_switch.count = csa_ie.count; |
---|
1325 | 1472 | |
---|
1326 | 1473 | if (drv_pre_channel_switch(sdata, &ch_switch)) { |
---|
1327 | 1474 | sdata_info(sdata, |
---|
.. | .. |
---|
1404 | 1551 | switch (channel->band) { |
---|
1405 | 1552 | default: |
---|
1406 | 1553 | WARN_ON_ONCE(1); |
---|
1407 | | - /* fall through */ |
---|
| 1554 | + fallthrough; |
---|
1408 | 1555 | case NL80211_BAND_2GHZ: |
---|
1409 | 1556 | case NL80211_BAND_60GHZ: |
---|
1410 | 1557 | chan_increment = 1; |
---|
1411 | 1558 | break; |
---|
1412 | 1559 | case NL80211_BAND_5GHZ: |
---|
| 1560 | + case NL80211_BAND_6GHZ: |
---|
1413 | 1561 | chan_increment = 4; |
---|
1414 | 1562 | break; |
---|
1415 | 1563 | } |
---|
.. | .. |
---|
1470 | 1618 | int pwr_level_cisco, pwr_level_80211h; |
---|
1471 | 1619 | int new_ap_level; |
---|
1472 | 1620 | __le16 capab = mgmt->u.probe_resp.capab_info; |
---|
| 1621 | + |
---|
| 1622 | + if (ieee80211_is_s1g_beacon(mgmt->frame_control)) |
---|
| 1623 | + return 0; /* TODO */ |
---|
1473 | 1624 | |
---|
1474 | 1625 | if (country_ie && |
---|
1475 | 1626 | (capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) || |
---|
.. | .. |
---|
1869 | 2020 | struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS]; |
---|
1870 | 2021 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
1871 | 2022 | size_t left; |
---|
1872 | | - int count, ac; |
---|
| 2023 | + int count, mu_edca_count, ac; |
---|
1873 | 2024 | const u8 *pos; |
---|
1874 | 2025 | u8 uapsd_queues = 0; |
---|
1875 | 2026 | |
---|
.. | .. |
---|
1889 | 2040 | uapsd_queues = ifmgd->uapsd_queues; |
---|
1890 | 2041 | |
---|
1891 | 2042 | count = wmm_param[6] & 0x0f; |
---|
1892 | | - if (count == ifmgd->wmm_last_param_set) |
---|
| 2043 | + /* -1 is the initial value of ifmgd->mu_edca_last_param_set. |
---|
| 2044 | + * if mu_edca was preset before and now it disappeared tell |
---|
| 2045 | + * the driver about it. |
---|
| 2046 | + */ |
---|
| 2047 | + mu_edca_count = mu_edca ? mu_edca->mu_qos_info & 0x0f : -1; |
---|
| 2048 | + if (count == ifmgd->wmm_last_param_set && |
---|
| 2049 | + mu_edca_count == ifmgd->mu_edca_last_param_set) |
---|
1893 | 2050 | return false; |
---|
1894 | 2051 | ifmgd->wmm_last_param_set = count; |
---|
| 2052 | + ifmgd->mu_edca_last_param_set = mu_edca_count; |
---|
1895 | 2053 | |
---|
1896 | 2054 | pos = wmm_param + 8; |
---|
1897 | 2055 | left = wmm_param_len - 8; |
---|
.. | .. |
---|
2040 | 2198 | } |
---|
2041 | 2199 | |
---|
2042 | 2200 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
---|
2043 | | - if (sband->band == NL80211_BAND_5GHZ) |
---|
| 2201 | + if (sband->band == NL80211_BAND_5GHZ || |
---|
| 2202 | + sband->band == NL80211_BAND_6GHZ) |
---|
2044 | 2203 | use_short_slot = true; |
---|
2045 | 2204 | |
---|
2046 | 2205 | if (use_protection != bss_conf->use_cts_prot) { |
---|
.. | .. |
---|
2208 | 2367 | !ifmgd->have_beacon) |
---|
2209 | 2368 | drv_mgd_prepare_tx(sdata->local, sdata, 0); |
---|
2210 | 2369 | |
---|
2211 | | - ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, |
---|
2212 | | - reason, tx, frame_buf); |
---|
| 2370 | + ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, |
---|
| 2371 | + ifmgd->bssid, stype, reason, |
---|
| 2372 | + tx, frame_buf); |
---|
2213 | 2373 | } |
---|
2214 | 2374 | |
---|
2215 | 2375 | /* flush out frame - make sure the deauth was actually sent */ |
---|
.. | .. |
---|
2297 | 2457 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
---|
2298 | 2458 | } |
---|
2299 | 2459 | |
---|
2300 | | -void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
---|
2301 | | - struct ieee80211_hdr *hdr) |
---|
2302 | | -{ |
---|
2303 | | - /* |
---|
2304 | | - * We can postpone the mgd.timer whenever receiving unicast frames |
---|
2305 | | - * from AP because we know that the connection is working both ways |
---|
2306 | | - * at that time. But multicast frames (and hence also beacons) must |
---|
2307 | | - * be ignored here, because we need to trigger the timer during |
---|
2308 | | - * data idle periods for sending the periodic probe request to the |
---|
2309 | | - * AP we're connected to. |
---|
2310 | | - */ |
---|
2311 | | - if (is_multicast_ether_addr(hdr->addr1)) |
---|
2312 | | - return; |
---|
2313 | | - |
---|
2314 | | - ieee80211_sta_reset_conn_monitor(sdata); |
---|
2315 | | -} |
---|
2316 | | - |
---|
2317 | 2460 | static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) |
---|
2318 | 2461 | { |
---|
2319 | 2462 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
.. | .. |
---|
2393 | 2536 | { |
---|
2394 | 2537 | ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time); |
---|
2395 | 2538 | |
---|
2396 | | - if (!ieee80211_is_data(hdr->frame_control)) |
---|
2397 | | - return; |
---|
2398 | | - |
---|
2399 | | - if (ieee80211_is_any_nullfunc(hdr->frame_control) && |
---|
2400 | | - sdata->u.mgd.probe_send_count > 0) { |
---|
2401 | | - if (ack) |
---|
2402 | | - ieee80211_sta_reset_conn_monitor(sdata); |
---|
2403 | | - else |
---|
2404 | | - sdata->u.mgd.nullfunc_failed = true; |
---|
2405 | | - ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
---|
| 2539 | + if (!ieee80211_is_any_nullfunc(hdr->frame_control) || |
---|
| 2540 | + !sdata->u.mgd.probe_send_count) |
---|
2406 | 2541 | return; |
---|
2407 | | - } |
---|
2408 | 2542 | |
---|
2409 | 2543 | if (ack) |
---|
2410 | | - ieee80211_sta_reset_conn_monitor(sdata); |
---|
| 2544 | + sdata->u.mgd.probe_send_count = 0; |
---|
| 2545 | + else |
---|
| 2546 | + sdata->u.mgd.nullfunc_failed = true; |
---|
| 2547 | + ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
---|
2411 | 2548 | } |
---|
2412 | 2549 | |
---|
2413 | 2550 | static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata, |
---|
.. | .. |
---|
2459 | 2596 | |
---|
2460 | 2597 | if (ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) { |
---|
2461 | 2598 | ifmgd->nullfunc_failed = false; |
---|
2462 | | - ieee80211_send_nullfunc(sdata->local, sdata, false); |
---|
| 2599 | + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) |
---|
| 2600 | + ifmgd->probe_send_count--; |
---|
| 2601 | + else |
---|
| 2602 | + ieee80211_send_nullfunc(sdata->local, sdata, false); |
---|
2463 | 2603 | } else { |
---|
2464 | 2604 | int ssid_len; |
---|
2465 | 2605 | |
---|
.. | .. |
---|
2759 | 2899 | { |
---|
2760 | 2900 | struct ieee80211_local *local = sdata->local; |
---|
2761 | 2901 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; |
---|
| 2902 | + const struct element *challenge; |
---|
2762 | 2903 | u8 *pos; |
---|
2763 | | - struct ieee802_11_elems elems; |
---|
2764 | 2904 | u32 tx_flags = 0; |
---|
2765 | 2905 | |
---|
2766 | 2906 | pos = mgmt->u.auth.variable; |
---|
2767 | | - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems); |
---|
2768 | | - if (!elems.challenge) |
---|
| 2907 | + challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos, |
---|
| 2908 | + len - (pos - (u8 *)mgmt)); |
---|
| 2909 | + if (!challenge) |
---|
2769 | 2910 | return; |
---|
2770 | 2911 | auth_data->expected_transaction = 4; |
---|
2771 | 2912 | drv_mgd_prepare_tx(sdata->local, sdata, 0); |
---|
.. | .. |
---|
2773 | 2914 | tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | |
---|
2774 | 2915 | IEEE80211_TX_INTFL_MLME_CONN_TX; |
---|
2775 | 2916 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, |
---|
2776 | | - elems.challenge - 2, elems.challenge_len + 2, |
---|
| 2917 | + (void *)challenge, |
---|
| 2918 | + challenge->datalen + sizeof(*challenge), |
---|
2777 | 2919 | auth_data->bss->bssid, auth_data->bss->bssid, |
---|
2778 | 2920 | auth_data->key, auth_data->key_len, |
---|
2779 | 2921 | auth_data->key_idx, tx_flags); |
---|
| 2922 | +} |
---|
| 2923 | + |
---|
| 2924 | +static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata, |
---|
| 2925 | + const u8 *bssid) |
---|
| 2926 | +{ |
---|
| 2927 | + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
| 2928 | + struct sta_info *sta; |
---|
| 2929 | + bool result = true; |
---|
| 2930 | + |
---|
| 2931 | + sdata_info(sdata, "authenticated\n"); |
---|
| 2932 | + ifmgd->auth_data->done = true; |
---|
| 2933 | + ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
---|
| 2934 | + ifmgd->auth_data->timeout_started = true; |
---|
| 2935 | + run_again(sdata, ifmgd->auth_data->timeout); |
---|
| 2936 | + |
---|
| 2937 | + /* move station state to auth */ |
---|
| 2938 | + mutex_lock(&sdata->local->sta_mtx); |
---|
| 2939 | + sta = sta_info_get(sdata, bssid); |
---|
| 2940 | + if (!sta) { |
---|
| 2941 | + WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); |
---|
| 2942 | + result = false; |
---|
| 2943 | + goto out; |
---|
| 2944 | + } |
---|
| 2945 | + if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { |
---|
| 2946 | + sdata_info(sdata, "failed moving %pM to auth\n", bssid); |
---|
| 2947 | + result = false; |
---|
| 2948 | + goto out; |
---|
| 2949 | + } |
---|
| 2950 | + |
---|
| 2951 | +out: |
---|
| 2952 | + mutex_unlock(&sdata->local->sta_mtx); |
---|
| 2953 | + return result; |
---|
2780 | 2954 | } |
---|
2781 | 2955 | |
---|
2782 | 2956 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
---|
.. | .. |
---|
2785 | 2959 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
2786 | 2960 | u8 bssid[ETH_ALEN]; |
---|
2787 | 2961 | u16 auth_alg, auth_transaction, status_code; |
---|
2788 | | - struct sta_info *sta; |
---|
2789 | 2962 | struct ieee80211_event event = { |
---|
2790 | 2963 | .type = MLME_EVENT, |
---|
2791 | 2964 | .u.mlme.data = AUTH_EVENT, |
---|
.. | .. |
---|
2809 | 2982 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
---|
2810 | 2983 | |
---|
2811 | 2984 | if (auth_alg != ifmgd->auth_data->algorithm || |
---|
2812 | | - auth_transaction != ifmgd->auth_data->expected_transaction) { |
---|
| 2985 | + (auth_alg != WLAN_AUTH_SAE && |
---|
| 2986 | + auth_transaction != ifmgd->auth_data->expected_transaction) || |
---|
| 2987 | + (auth_alg == WLAN_AUTH_SAE && |
---|
| 2988 | + (auth_transaction < ifmgd->auth_data->expected_transaction || |
---|
| 2989 | + auth_transaction > 2))) { |
---|
2813 | 2990 | sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n", |
---|
2814 | 2991 | mgmt->sa, auth_alg, ifmgd->auth_data->algorithm, |
---|
2815 | 2992 | auth_transaction, |
---|
.. | .. |
---|
2818 | 2995 | } |
---|
2819 | 2996 | |
---|
2820 | 2997 | if (status_code != WLAN_STATUS_SUCCESS) { |
---|
| 2998 | + cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
---|
| 2999 | + |
---|
| 3000 | + if (auth_alg == WLAN_AUTH_SAE && |
---|
| 3001 | + (status_code == WLAN_STATUS_ANTI_CLOG_REQUIRED || |
---|
| 3002 | + (auth_transaction == 1 && |
---|
| 3003 | + (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || |
---|
| 3004 | + status_code == WLAN_STATUS_SAE_PK)))) { |
---|
| 3005 | + /* waiting for userspace now */ |
---|
| 3006 | + ifmgd->auth_data->waiting = true; |
---|
| 3007 | + ifmgd->auth_data->timeout = |
---|
| 3008 | + jiffies + IEEE80211_AUTH_WAIT_SAE_RETRY; |
---|
| 3009 | + ifmgd->auth_data->timeout_started = true; |
---|
| 3010 | + run_again(sdata, ifmgd->auth_data->timeout); |
---|
| 3011 | + return; |
---|
| 3012 | + } |
---|
| 3013 | + |
---|
2821 | 3014 | sdata_info(sdata, "%pM denied authentication (status %d)\n", |
---|
2822 | 3015 | mgmt->sa, status_code); |
---|
2823 | 3016 | ieee80211_destroy_auth_data(sdata, false); |
---|
2824 | | - cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
---|
2825 | 3017 | event.u.mlme.status = MLME_DENIED; |
---|
2826 | 3018 | event.u.mlme.reason = status_code; |
---|
2827 | 3019 | drv_event_callback(sdata->local, sdata, &event); |
---|
.. | .. |
---|
2852 | 3044 | |
---|
2853 | 3045 | event.u.mlme.status = MLME_SUCCESS; |
---|
2854 | 3046 | drv_event_callback(sdata->local, sdata, &event); |
---|
2855 | | - sdata_info(sdata, "authenticated\n"); |
---|
2856 | | - ifmgd->auth_data->done = true; |
---|
2857 | | - ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
---|
2858 | | - ifmgd->auth_data->timeout_started = true; |
---|
2859 | | - run_again(sdata, ifmgd->auth_data->timeout); |
---|
2860 | | - |
---|
2861 | | - if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && |
---|
2862 | | - ifmgd->auth_data->expected_transaction != 2) { |
---|
2863 | | - /* |
---|
2864 | | - * Report auth frame to user space for processing since another |
---|
2865 | | - * round of Authentication frames is still needed. |
---|
2866 | | - */ |
---|
2867 | | - cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
---|
2868 | | - return; |
---|
| 3047 | + if (ifmgd->auth_data->algorithm != WLAN_AUTH_SAE || |
---|
| 3048 | + (auth_transaction == 2 && |
---|
| 3049 | + ifmgd->auth_data->expected_transaction == 2)) { |
---|
| 3050 | + if (!ieee80211_mark_sta_auth(sdata, bssid)) |
---|
| 3051 | + return; /* ignore frame -- wait for timeout */ |
---|
| 3052 | + } else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && |
---|
| 3053 | + auth_transaction == 2) { |
---|
| 3054 | + sdata_info(sdata, "SAE peer confirmed\n"); |
---|
| 3055 | + ifmgd->auth_data->peer_confirmed = true; |
---|
2869 | 3056 | } |
---|
2870 | | - |
---|
2871 | | - /* move station state to auth */ |
---|
2872 | | - mutex_lock(&sdata->local->sta_mtx); |
---|
2873 | | - sta = sta_info_get(sdata, bssid); |
---|
2874 | | - if (!sta) { |
---|
2875 | | - WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); |
---|
2876 | | - goto out_err; |
---|
2877 | | - } |
---|
2878 | | - if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { |
---|
2879 | | - sdata_info(sdata, "failed moving %pM to auth\n", bssid); |
---|
2880 | | - goto out_err; |
---|
2881 | | - } |
---|
2882 | | - mutex_unlock(&sdata->local->sta_mtx); |
---|
2883 | 3057 | |
---|
2884 | 3058 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
---|
2885 | | - return; |
---|
2886 | | - out_err: |
---|
2887 | | - mutex_unlock(&sdata->local->sta_mtx); |
---|
2888 | | - /* ignore frame -- wait for timeout */ |
---|
2889 | 3059 | } |
---|
2890 | 3060 | |
---|
2891 | 3061 | #define case_WLAN(type) \ |
---|
.. | .. |
---|
3041 | 3211 | *have_higher_than_11mbit = true; |
---|
3042 | 3212 | |
---|
3043 | 3213 | /* |
---|
3044 | | - * Skip HT and VHT BSS membership selectors since they're not |
---|
3045 | | - * rates. |
---|
| 3214 | + * Skip HT, VHT and HE BSS membership selectors since they're |
---|
| 3215 | + * not rates. |
---|
3046 | 3216 | * |
---|
3047 | 3217 | * Note: Even though the membership selector and the basic |
---|
3048 | 3218 | * rate flag share the same bit, they are not exactly |
---|
3049 | 3219 | * the same. |
---|
3050 | 3220 | */ |
---|
3051 | 3221 | if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) || |
---|
3052 | | - supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) |
---|
| 3222 | + supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) || |
---|
| 3223 | + supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY)) |
---|
3053 | 3224 | continue; |
---|
3054 | 3225 | |
---|
3055 | 3226 | for (j = 0; j < sband->n_bitrates; j++) { |
---|
.. | .. |
---|
3073 | 3244 | } |
---|
3074 | 3245 | } |
---|
3075 | 3246 | |
---|
| 3247 | +static bool ieee80211_twt_req_supported(const struct sta_info *sta, |
---|
| 3248 | + const struct ieee802_11_elems *elems) |
---|
| 3249 | +{ |
---|
| 3250 | + if (elems->ext_capab_len < 10) |
---|
| 3251 | + return false; |
---|
| 3252 | + |
---|
| 3253 | + if (!(elems->ext_capab[9] & WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT)) |
---|
| 3254 | + return false; |
---|
| 3255 | + |
---|
| 3256 | + return sta->sta.he_cap.he_cap_elem.mac_cap_info[0] & |
---|
| 3257 | + IEEE80211_HE_MAC_CAP0_TWT_RES; |
---|
| 3258 | +} |
---|
| 3259 | + |
---|
| 3260 | +static int ieee80211_recalc_twt_req(struct ieee80211_sub_if_data *sdata, |
---|
| 3261 | + struct sta_info *sta, |
---|
| 3262 | + struct ieee802_11_elems *elems) |
---|
| 3263 | +{ |
---|
| 3264 | + bool twt = ieee80211_twt_req_supported(sta, elems); |
---|
| 3265 | + |
---|
| 3266 | + if (sdata->vif.bss_conf.twt_requester != twt) { |
---|
| 3267 | + sdata->vif.bss_conf.twt_requester = twt; |
---|
| 3268 | + return BSS_CHANGED_TWT; |
---|
| 3269 | + } |
---|
| 3270 | + return 0; |
---|
| 3271 | +} |
---|
| 3272 | + |
---|
3076 | 3273 | static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, |
---|
3077 | 3274 | struct cfg80211_bss *cbss, |
---|
3078 | | - struct ieee80211_mgmt *mgmt, size_t len) |
---|
| 3275 | + struct ieee80211_mgmt *mgmt, size_t len, |
---|
| 3276 | + struct ieee802_11_elems *elems) |
---|
3079 | 3277 | { |
---|
3080 | 3278 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
3081 | 3279 | struct ieee80211_local *local = sdata->local; |
---|
3082 | 3280 | struct ieee80211_supported_band *sband; |
---|
3083 | 3281 | struct sta_info *sta; |
---|
3084 | | - u8 *pos; |
---|
3085 | 3282 | u16 capab_info, aid; |
---|
3086 | | - struct ieee802_11_elems elems; |
---|
3087 | 3283 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
---|
3088 | 3284 | const struct cfg80211_bss_ies *bss_ies = NULL; |
---|
3089 | 3285 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; |
---|
| 3286 | + bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; |
---|
| 3287 | + bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ; |
---|
3090 | 3288 | u32 changed = 0; |
---|
| 3289 | + u8 *pos; |
---|
3091 | 3290 | int err; |
---|
3092 | 3291 | bool ret; |
---|
3093 | 3292 | |
---|
3094 | 3293 | /* AssocResp and ReassocResp have identical structure */ |
---|
3095 | 3294 | |
---|
| 3295 | + pos = mgmt->u.assoc_resp.variable; |
---|
3096 | 3296 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); |
---|
| 3297 | + if (is_s1g) { |
---|
| 3298 | + pos = (u8 *) mgmt->u.s1g_assoc_resp.variable; |
---|
| 3299 | + aid = 0; /* TODO */ |
---|
| 3300 | + } |
---|
3097 | 3301 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
---|
| 3302 | + ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems, |
---|
| 3303 | + mgmt->bssid, NULL); |
---|
| 3304 | + |
---|
| 3305 | + if (elems->aid_resp) |
---|
| 3306 | + aid = le16_to_cpu(elems->aid_resp->aid); |
---|
3098 | 3307 | |
---|
3099 | 3308 | /* |
---|
3100 | 3309 | * The 5 MSB of the AID field are reserved |
---|
.. | .. |
---|
3111 | 3320 | ifmgd->broken_ap = true; |
---|
3112 | 3321 | } |
---|
3113 | 3322 | |
---|
3114 | | - pos = mgmt->u.assoc_resp.variable; |
---|
3115 | | - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems); |
---|
3116 | | - |
---|
3117 | | - if (!elems.supp_rates) { |
---|
| 3323 | + if (!is_s1g && !elems->supp_rates) { |
---|
3118 | 3324 | sdata_info(sdata, "no SuppRates element in AssocResp\n"); |
---|
3119 | 3325 | return false; |
---|
3120 | 3326 | } |
---|
3121 | 3327 | |
---|
3122 | | - ifmgd->aid = aid; |
---|
| 3328 | + sdata->vif.bss_conf.aid = aid; |
---|
3123 | 3329 | ifmgd->tdls_chan_switch_prohibited = |
---|
3124 | | - elems.ext_capab && elems.ext_capab_len >= 5 && |
---|
3125 | | - (elems.ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); |
---|
| 3330 | + elems->ext_capab && elems->ext_capab_len >= 5 && |
---|
| 3331 | + (elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); |
---|
3126 | 3332 | |
---|
3127 | 3333 | /* |
---|
3128 | 3334 | * Some APs are erroneously not including some information in their |
---|
.. | .. |
---|
3131 | 3337 | * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", |
---|
3132 | 3338 | * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. |
---|
3133 | 3339 | */ |
---|
3134 | | - if ((assoc_data->wmm && !elems.wmm_param) || |
---|
3135 | | - (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
---|
3136 | | - (!elems.ht_cap_elem || !elems.ht_operation)) || |
---|
3137 | | - (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
---|
3138 | | - (!elems.vht_cap_elem || !elems.vht_operation))) { |
---|
| 3340 | + if (!is_6ghz && |
---|
| 3341 | + ((assoc_data->wmm && !elems->wmm_param) || |
---|
| 3342 | + (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
---|
| 3343 | + (!elems->ht_cap_elem || !elems->ht_operation)) || |
---|
| 3344 | + (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
---|
| 3345 | + (!elems->vht_cap_elem || !elems->vht_operation)))) { |
---|
3139 | 3346 | const struct cfg80211_bss_ies *ies; |
---|
3140 | 3347 | struct ieee802_11_elems bss_elems; |
---|
3141 | 3348 | |
---|
.. | .. |
---|
3149 | 3356 | return false; |
---|
3150 | 3357 | |
---|
3151 | 3358 | ieee802_11_parse_elems(bss_ies->data, bss_ies->len, |
---|
3152 | | - false, &bss_elems); |
---|
| 3359 | + false, &bss_elems, |
---|
| 3360 | + mgmt->bssid, |
---|
| 3361 | + assoc_data->bss->bssid); |
---|
3153 | 3362 | if (assoc_data->wmm && |
---|
3154 | | - !elems.wmm_param && bss_elems.wmm_param) { |
---|
3155 | | - elems.wmm_param = bss_elems.wmm_param; |
---|
| 3363 | + !elems->wmm_param && bss_elems.wmm_param) { |
---|
| 3364 | + elems->wmm_param = bss_elems.wmm_param; |
---|
3156 | 3365 | sdata_info(sdata, |
---|
3157 | 3366 | "AP bug: WMM param missing from AssocResp\n"); |
---|
3158 | 3367 | } |
---|
.. | .. |
---|
3161 | 3370 | * Also check if we requested HT/VHT, otherwise the AP doesn't |
---|
3162 | 3371 | * have to include the IEs in the (re)association response. |
---|
3163 | 3372 | */ |
---|
3164 | | - if (!elems.ht_cap_elem && bss_elems.ht_cap_elem && |
---|
| 3373 | + if (!elems->ht_cap_elem && bss_elems.ht_cap_elem && |
---|
3165 | 3374 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { |
---|
3166 | | - elems.ht_cap_elem = bss_elems.ht_cap_elem; |
---|
| 3375 | + elems->ht_cap_elem = bss_elems.ht_cap_elem; |
---|
3167 | 3376 | sdata_info(sdata, |
---|
3168 | 3377 | "AP bug: HT capability missing from AssocResp\n"); |
---|
3169 | 3378 | } |
---|
3170 | | - if (!elems.ht_operation && bss_elems.ht_operation && |
---|
| 3379 | + if (!elems->ht_operation && bss_elems.ht_operation && |
---|
3171 | 3380 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { |
---|
3172 | | - elems.ht_operation = bss_elems.ht_operation; |
---|
| 3381 | + elems->ht_operation = bss_elems.ht_operation; |
---|
3173 | 3382 | sdata_info(sdata, |
---|
3174 | 3383 | "AP bug: HT operation missing from AssocResp\n"); |
---|
3175 | 3384 | } |
---|
3176 | | - if (!elems.vht_cap_elem && bss_elems.vht_cap_elem && |
---|
| 3385 | + if (!elems->vht_cap_elem && bss_elems.vht_cap_elem && |
---|
3177 | 3386 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { |
---|
3178 | | - elems.vht_cap_elem = bss_elems.vht_cap_elem; |
---|
| 3387 | + elems->vht_cap_elem = bss_elems.vht_cap_elem; |
---|
3179 | 3388 | sdata_info(sdata, |
---|
3180 | 3389 | "AP bug: VHT capa missing from AssocResp\n"); |
---|
3181 | 3390 | } |
---|
3182 | | - if (!elems.vht_operation && bss_elems.vht_operation && |
---|
| 3391 | + if (!elems->vht_operation && bss_elems.vht_operation && |
---|
3183 | 3392 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { |
---|
3184 | | - elems.vht_operation = bss_elems.vht_operation; |
---|
| 3393 | + elems->vht_operation = bss_elems.vht_operation; |
---|
3185 | 3394 | sdata_info(sdata, |
---|
3186 | 3395 | "AP bug: VHT operation missing from AssocResp\n"); |
---|
3187 | 3396 | } |
---|
| 3397 | + kfree(bss_elems.nontx_profile); |
---|
3188 | 3398 | } |
---|
3189 | 3399 | |
---|
3190 | 3400 | /* |
---|
3191 | 3401 | * We previously checked these in the beacon/probe response, so |
---|
3192 | 3402 | * they should be present here. This is just a safety net. |
---|
3193 | 3403 | */ |
---|
3194 | | - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
---|
3195 | | - (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { |
---|
| 3404 | + if (!is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
---|
| 3405 | + (!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) { |
---|
3196 | 3406 | sdata_info(sdata, |
---|
3197 | 3407 | "HT AP is missing WMM params or HT capability/operation\n"); |
---|
3198 | 3408 | ret = false; |
---|
3199 | 3409 | goto out; |
---|
3200 | 3410 | } |
---|
3201 | 3411 | |
---|
3202 | | - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
---|
3203 | | - (!elems.vht_cap_elem || !elems.vht_operation)) { |
---|
| 3412 | + if (!is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
---|
| 3413 | + (!elems->vht_cap_elem || !elems->vht_operation)) { |
---|
3204 | 3414 | sdata_info(sdata, |
---|
3205 | 3415 | "VHT AP is missing VHT capability/operation\n"); |
---|
| 3416 | + ret = false; |
---|
| 3417 | + goto out; |
---|
| 3418 | + } |
---|
| 3419 | + |
---|
| 3420 | + if (is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && |
---|
| 3421 | + !elems->he_6ghz_capa) { |
---|
| 3422 | + sdata_info(sdata, |
---|
| 3423 | + "HE 6 GHz AP is missing HE 6 GHz band capability\n"); |
---|
3206 | 3424 | ret = false; |
---|
3207 | 3425 | goto out; |
---|
3208 | 3426 | } |
---|
.. | .. |
---|
3226 | 3444 | goto out; |
---|
3227 | 3445 | } |
---|
3228 | 3446 | |
---|
3229 | | - /* |
---|
3230 | | - * If AP doesn't support HT, or it doesn't have HE mandatory IEs, mark |
---|
3231 | | - * HE as disabled. If on the 5GHz band, make sure it supports VHT. |
---|
3232 | | - */ |
---|
3233 | | - if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || |
---|
3234 | | - (sband->band == NL80211_BAND_5GHZ && |
---|
3235 | | - ifmgd->flags & IEEE80211_STA_DISABLE_VHT) || |
---|
3236 | | - (!elems.he_cap && !elems.he_operation)) |
---|
3237 | | - ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
3238 | | - |
---|
3239 | 3447 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && |
---|
3240 | | - (!elems.he_cap || !elems.he_operation)) { |
---|
| 3448 | + (!elems->he_cap || !elems->he_operation)) { |
---|
3241 | 3449 | mutex_unlock(&sdata->local->sta_mtx); |
---|
3242 | 3450 | sdata_info(sdata, |
---|
3243 | 3451 | "HE AP is missing HE capability/operation\n"); |
---|
.. | .. |
---|
3246 | 3454 | } |
---|
3247 | 3455 | |
---|
3248 | 3456 | /* Set up internal HT/VHT capabilities */ |
---|
3249 | | - if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
---|
| 3457 | + if (elems->ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
---|
3250 | 3458 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
---|
3251 | | - elems.ht_cap_elem, sta); |
---|
| 3459 | + elems->ht_cap_elem, sta); |
---|
3252 | 3460 | |
---|
3253 | | - if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
---|
| 3461 | + if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
---|
3254 | 3462 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
---|
3255 | | - elems.vht_cap_elem, sta); |
---|
| 3463 | + elems->vht_cap_elem, sta); |
---|
3256 | 3464 | |
---|
3257 | | - if (elems.he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && |
---|
3258 | | - elems.he_cap) { |
---|
| 3465 | + if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && |
---|
| 3466 | + elems->he_cap) { |
---|
3259 | 3467 | ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, |
---|
3260 | | - elems.he_cap, |
---|
3261 | | - elems.he_cap_len, |
---|
| 3468 | + elems->he_cap, |
---|
| 3469 | + elems->he_cap_len, |
---|
| 3470 | + elems->he_6ghz_capa, |
---|
3262 | 3471 | sta); |
---|
3263 | 3472 | |
---|
3264 | 3473 | bss_conf->he_support = sta->sta.he_cap.has_he; |
---|
| 3474 | + if (elems->rsnx && elems->rsnx_len && |
---|
| 3475 | + (elems->rsnx[0] & WLAN_RSNX_CAPA_PROTECTED_TWT) && |
---|
| 3476 | + wiphy_ext_feature_isset(local->hw.wiphy, |
---|
| 3477 | + NL80211_EXT_FEATURE_PROTECTED_TWT)) |
---|
| 3478 | + bss_conf->twt_protected = true; |
---|
| 3479 | + else |
---|
| 3480 | + bss_conf->twt_protected = false; |
---|
| 3481 | + |
---|
| 3482 | + changed |= ieee80211_recalc_twt_req(sdata, sta, elems); |
---|
3265 | 3483 | } else { |
---|
3266 | 3484 | bss_conf->he_support = false; |
---|
| 3485 | + bss_conf->twt_requester = false; |
---|
| 3486 | + bss_conf->twt_protected = false; |
---|
3267 | 3487 | } |
---|
3268 | 3488 | |
---|
3269 | 3489 | if (bss_conf->he_support) { |
---|
3270 | | - bss_conf->bss_color = |
---|
3271 | | - le32_get_bits(elems.he_operation->he_oper_params, |
---|
| 3490 | + bss_conf->he_bss_color.color = |
---|
| 3491 | + le32_get_bits(elems->he_operation->he_oper_params, |
---|
3272 | 3492 | IEEE80211_HE_OPERATION_BSS_COLOR_MASK); |
---|
| 3493 | + bss_conf->he_bss_color.partial = |
---|
| 3494 | + le32_get_bits(elems->he_operation->he_oper_params, |
---|
| 3495 | + IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR); |
---|
| 3496 | + bss_conf->he_bss_color.enabled = |
---|
| 3497 | + !le32_get_bits(elems->he_operation->he_oper_params, |
---|
| 3498 | + IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED); |
---|
| 3499 | + |
---|
| 3500 | + if (bss_conf->he_bss_color.enabled) |
---|
| 3501 | + changed |= BSS_CHANGED_HE_BSS_COLOR; |
---|
3273 | 3502 | |
---|
3274 | 3503 | bss_conf->htc_trig_based_pkt_ext = |
---|
3275 | | - le32_get_bits(elems.he_operation->he_oper_params, |
---|
| 3504 | + le32_get_bits(elems->he_operation->he_oper_params, |
---|
3276 | 3505 | IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK); |
---|
3277 | 3506 | bss_conf->frame_time_rts_th = |
---|
3278 | | - le32_get_bits(elems.he_operation->he_oper_params, |
---|
| 3507 | + le32_get_bits(elems->he_operation->he_oper_params, |
---|
3279 | 3508 | IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); |
---|
3280 | 3509 | |
---|
3281 | 3510 | bss_conf->multi_sta_back_32bit = |
---|
.. | .. |
---|
3286 | 3515 | sta->sta.he_cap.he_cap_elem.mac_cap_info[2] & |
---|
3287 | 3516 | IEEE80211_HE_MAC_CAP2_ACK_EN; |
---|
3288 | 3517 | |
---|
3289 | | - bss_conf->uora_exists = !!elems.uora_element; |
---|
3290 | | - if (elems.uora_element) |
---|
3291 | | - bss_conf->uora_ocw_range = elems.uora_element[0]; |
---|
| 3518 | + bss_conf->uora_exists = !!elems->uora_element; |
---|
| 3519 | + if (elems->uora_element) |
---|
| 3520 | + bss_conf->uora_ocw_range = elems->uora_element[0]; |
---|
3292 | 3521 | |
---|
| 3522 | + ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation); |
---|
| 3523 | + ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr); |
---|
3293 | 3524 | /* TODO: OPEN: what happens if BSS color disable is set? */ |
---|
| 3525 | + } |
---|
| 3526 | + |
---|
| 3527 | + if (cbss->transmitted_bss) { |
---|
| 3528 | + bss_conf->nontransmitted = true; |
---|
| 3529 | + ether_addr_copy(bss_conf->transmitter_bssid, |
---|
| 3530 | + cbss->transmitted_bss->bssid); |
---|
| 3531 | + bss_conf->bssid_indicator = cbss->max_bssid_indicator; |
---|
| 3532 | + bss_conf->bssid_index = cbss->bssid_index; |
---|
| 3533 | + } else { |
---|
| 3534 | + bss_conf->nontransmitted = false; |
---|
| 3535 | + memset(bss_conf->transmitter_bssid, 0, |
---|
| 3536 | + sizeof(bss_conf->transmitter_bssid)); |
---|
| 3537 | + bss_conf->bssid_indicator = 0; |
---|
| 3538 | + bss_conf->bssid_index = 0; |
---|
3294 | 3539 | } |
---|
3295 | 3540 | |
---|
3296 | 3541 | /* |
---|
.. | .. |
---|
3305 | 3550 | * NSS calculation (that would be done in rate_control_rate_init()) |
---|
3306 | 3551 | * and use the # of streams from that element. |
---|
3307 | 3552 | */ |
---|
3308 | | - if (elems.opmode_notif && |
---|
3309 | | - !(*elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { |
---|
| 3553 | + if (elems->opmode_notif && |
---|
| 3554 | + !(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { |
---|
3310 | 3555 | u8 nss; |
---|
3311 | 3556 | |
---|
3312 | | - nss = *elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; |
---|
| 3557 | + nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; |
---|
3313 | 3558 | nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; |
---|
3314 | 3559 | nss += 1; |
---|
3315 | 3560 | sta->sta.rx_nss = nss; |
---|
.. | .. |
---|
3324 | 3569 | sta->sta.mfp = false; |
---|
3325 | 3570 | } |
---|
3326 | 3571 | |
---|
3327 | | - sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS; |
---|
| 3572 | + sta->sta.wme = (elems->wmm_param || elems->s1g_capab) && |
---|
| 3573 | + local->hw.queues >= IEEE80211_NUM_ACS; |
---|
3328 | 3574 | |
---|
3329 | 3575 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
---|
3330 | 3576 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
---|
.. | .. |
---|
3339 | 3585 | goto out; |
---|
3340 | 3586 | } |
---|
3341 | 3587 | |
---|
| 3588 | + if (sdata->wdev.use_4addr) |
---|
| 3589 | + drv_sta_set_4addr(local, sdata, &sta->sta, true); |
---|
| 3590 | + |
---|
3342 | 3591 | mutex_unlock(&sdata->local->sta_mtx); |
---|
3343 | 3592 | |
---|
3344 | 3593 | /* |
---|
.. | .. |
---|
3348 | 3597 | * 4-bit value. |
---|
3349 | 3598 | */ |
---|
3350 | 3599 | ifmgd->wmm_last_param_set = -1; |
---|
| 3600 | + ifmgd->mu_edca_last_param_set = -1; |
---|
3351 | 3601 | |
---|
3352 | 3602 | if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { |
---|
3353 | 3603 | ieee80211_set_wmm_default(sdata, false, false); |
---|
3354 | | - } else if (!ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, |
---|
3355 | | - elems.wmm_param_len, |
---|
3356 | | - elems.mu_edca_param_set)) { |
---|
| 3604 | + } else if (!ieee80211_sta_wmm_params(local, sdata, elems->wmm_param, |
---|
| 3605 | + elems->wmm_param_len, |
---|
| 3606 | + elems->mu_edca_param_set)) { |
---|
3357 | 3607 | /* still enable QoS since we might have HT/VHT */ |
---|
3358 | 3608 | ieee80211_set_wmm_default(sdata, false, true); |
---|
3359 | 3609 | /* set the disable-WMM flag in this case to disable |
---|
.. | .. |
---|
3367 | 3617 | } |
---|
3368 | 3618 | changed |= BSS_CHANGED_QOS; |
---|
3369 | 3619 | |
---|
3370 | | - if (elems.max_idle_period_ie) { |
---|
| 3620 | + if (elems->max_idle_period_ie) { |
---|
3371 | 3621 | bss_conf->max_idle_period = |
---|
3372 | | - le16_to_cpu(elems.max_idle_period_ie->max_idle_period); |
---|
| 3622 | + le16_to_cpu(elems->max_idle_period_ie->max_idle_period); |
---|
3373 | 3623 | bss_conf->protected_keep_alive = |
---|
3374 | | - !!(elems.max_idle_period_ie->idle_options & |
---|
| 3624 | + !!(elems->max_idle_period_ie->idle_options & |
---|
3375 | 3625 | WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE); |
---|
3376 | 3626 | changed |= BSS_CHANGED_KEEP_ALIVE; |
---|
3377 | 3627 | } else { |
---|
.. | .. |
---|
3379 | 3629 | bss_conf->protected_keep_alive = false; |
---|
3380 | 3630 | } |
---|
3381 | 3631 | |
---|
3382 | | - /* set AID and assoc capability, |
---|
| 3632 | + /* set assoc capability (AID was already set earlier), |
---|
3383 | 3633 | * ieee80211_set_associated() will tell the driver */ |
---|
3384 | | - bss_conf->aid = aid; |
---|
3385 | 3634 | bss_conf->assoc_capability = capab_info; |
---|
3386 | 3635 | ieee80211_set_associated(sdata, cbss, changed); |
---|
3387 | 3636 | |
---|
.. | .. |
---|
3396 | 3645 | * Start timer to probe the connection to the AP now. |
---|
3397 | 3646 | * Also start the timer that will detect beacon loss. |
---|
3398 | 3647 | */ |
---|
3399 | | - ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
---|
3400 | 3648 | ieee80211_sta_reset_beacon_monitor(sdata); |
---|
| 3649 | + ieee80211_sta_reset_conn_monitor(sdata); |
---|
3401 | 3650 | |
---|
3402 | 3651 | ret = true; |
---|
3403 | 3652 | out: |
---|
.. | .. |
---|
3416 | 3665 | int ac, uapsd_queues = -1; |
---|
3417 | 3666 | u8 *pos; |
---|
3418 | 3667 | bool reassoc; |
---|
3419 | | - struct cfg80211_bss *bss; |
---|
| 3668 | + struct cfg80211_bss *cbss; |
---|
3420 | 3669 | struct ieee80211_event event = { |
---|
3421 | 3670 | .type = MLME_EVENT, |
---|
3422 | 3671 | .u.mlme.data = ASSOC_EVENT, |
---|
.. | .. |
---|
3426 | 3675 | |
---|
3427 | 3676 | if (!assoc_data) |
---|
3428 | 3677 | return; |
---|
| 3678 | + |
---|
3429 | 3679 | if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid)) |
---|
3430 | 3680 | return; |
---|
| 3681 | + |
---|
| 3682 | + cbss = assoc_data->bss; |
---|
3431 | 3683 | |
---|
3432 | 3684 | /* |
---|
3433 | 3685 | * AssocResp and ReassocResp have identical structure, so process both |
---|
.. | .. |
---|
3440 | 3692 | reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control); |
---|
3441 | 3693 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
---|
3442 | 3694 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
---|
| 3695 | + pos = mgmt->u.assoc_resp.variable; |
---|
3443 | 3696 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); |
---|
| 3697 | + if (cbss->channel->band == NL80211_BAND_S1GHZ) { |
---|
| 3698 | + pos = (u8 *) mgmt->u.s1g_assoc_resp.variable; |
---|
| 3699 | + aid = 0; /* TODO */ |
---|
| 3700 | + } |
---|
3444 | 3701 | |
---|
3445 | 3702 | sdata_info(sdata, |
---|
3446 | 3703 | "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", |
---|
.. | .. |
---|
3451 | 3708 | fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) |
---|
3452 | 3709 | return; |
---|
3453 | 3710 | |
---|
3454 | | - pos = mgmt->u.assoc_resp.variable; |
---|
3455 | | - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems); |
---|
| 3711 | + ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, |
---|
| 3712 | + mgmt->bssid, NULL); |
---|
3456 | 3713 | |
---|
3457 | 3714 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && |
---|
3458 | 3715 | elems.timeout_int && |
---|
.. | .. |
---|
3470 | 3727 | return; |
---|
3471 | 3728 | } |
---|
3472 | 3729 | |
---|
3473 | | - bss = assoc_data->bss; |
---|
3474 | | - |
---|
3475 | 3730 | if (status_code != WLAN_STATUS_SUCCESS) { |
---|
3476 | 3731 | sdata_info(sdata, "%pM denied association (code=%d)\n", |
---|
3477 | 3732 | mgmt->sa, status_code); |
---|
.. | .. |
---|
3480 | 3735 | event.u.mlme.reason = status_code; |
---|
3481 | 3736 | drv_event_callback(sdata->local, sdata, &event); |
---|
3482 | 3737 | } else { |
---|
3483 | | - if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { |
---|
| 3738 | + if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) { |
---|
3484 | 3739 | /* oops -- internal error -- send timeout for now */ |
---|
3485 | 3740 | ieee80211_destroy_assoc_data(sdata, false, false); |
---|
3486 | | - cfg80211_assoc_timeout(sdata->dev, bss); |
---|
| 3741 | + cfg80211_assoc_timeout(sdata->dev, cbss); |
---|
3487 | 3742 | return; |
---|
3488 | 3743 | } |
---|
3489 | 3744 | event.u.mlme.status = MLME_SUCCESS; |
---|
.. | .. |
---|
3504 | 3759 | uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; |
---|
3505 | 3760 | } |
---|
3506 | 3761 | |
---|
3507 | | - cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues); |
---|
| 3762 | + cfg80211_rx_assoc_resp(sdata->dev, cbss, (u8 *)mgmt, len, uapsd_queues, |
---|
| 3763 | + ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len); |
---|
3508 | 3764 | } |
---|
3509 | 3765 | |
---|
3510 | 3766 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
---|
3511 | 3767 | struct ieee80211_mgmt *mgmt, size_t len, |
---|
3512 | | - struct ieee80211_rx_status *rx_status, |
---|
3513 | | - struct ieee802_11_elems *elems) |
---|
| 3768 | + struct ieee80211_rx_status *rx_status) |
---|
3514 | 3769 | { |
---|
3515 | 3770 | struct ieee80211_local *local = sdata->local; |
---|
3516 | 3771 | struct ieee80211_bss *bss; |
---|
.. | .. |
---|
3518 | 3773 | |
---|
3519 | 3774 | sdata_assert_lock(sdata); |
---|
3520 | 3775 | |
---|
3521 | | - channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
---|
| 3776 | + channel = ieee80211_get_channel_khz(local->hw.wiphy, |
---|
| 3777 | + ieee80211_rx_status_to_khz(rx_status)); |
---|
3522 | 3778 | if (!channel) |
---|
3523 | 3779 | return; |
---|
3524 | 3780 | |
---|
3525 | | - bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
---|
3526 | | - channel); |
---|
| 3781 | + bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel); |
---|
3527 | 3782 | if (bss) { |
---|
3528 | 3783 | sdata->vif.bss_conf.beacon_rate = bss->beacon_rate; |
---|
3529 | 3784 | ieee80211_rx_bss_put(local, bss); |
---|
.. | .. |
---|
3537 | 3792 | struct ieee80211_mgmt *mgmt = (void *)skb->data; |
---|
3538 | 3793 | struct ieee80211_if_managed *ifmgd; |
---|
3539 | 3794 | struct ieee80211_rx_status *rx_status = (void *) skb->cb; |
---|
| 3795 | + struct ieee80211_channel *channel; |
---|
3540 | 3796 | size_t baselen, len = skb->len; |
---|
3541 | | - struct ieee802_11_elems elems; |
---|
3542 | 3797 | |
---|
3543 | 3798 | ifmgd = &sdata->u.mgd; |
---|
3544 | 3799 | |
---|
3545 | 3800 | sdata_assert_lock(sdata); |
---|
3546 | 3801 | |
---|
3547 | | - if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) |
---|
| 3802 | + /* |
---|
| 3803 | + * According to Draft P802.11ax D6.0 clause 26.17.2.3.2: |
---|
| 3804 | + * "If a 6 GHz AP receives a Probe Request frame and responds with |
---|
| 3805 | + * a Probe Response frame [..], the Address 1 field of the Probe |
---|
| 3806 | + * Response frame shall be set to the broadcast address [..]" |
---|
| 3807 | + * So, on 6GHz band we should also accept broadcast responses. |
---|
| 3808 | + */ |
---|
| 3809 | + channel = ieee80211_get_channel(sdata->local->hw.wiphy, |
---|
| 3810 | + rx_status->freq); |
---|
| 3811 | + if (!channel) |
---|
| 3812 | + return; |
---|
| 3813 | + |
---|
| 3814 | + if (!ether_addr_equal(mgmt->da, sdata->vif.addr) && |
---|
| 3815 | + (channel->band != NL80211_BAND_6GHZ || |
---|
| 3816 | + !is_broadcast_ether_addr(mgmt->da))) |
---|
3548 | 3817 | return; /* ignore ProbeResp to foreign address */ |
---|
3549 | 3818 | |
---|
3550 | 3819 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
---|
3551 | 3820 | if (baselen > len) |
---|
3552 | 3821 | return; |
---|
3553 | 3822 | |
---|
3554 | | - ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
---|
3555 | | - false, &elems); |
---|
3556 | | - |
---|
3557 | | - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
---|
| 3823 | + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); |
---|
3558 | 3824 | |
---|
3559 | 3825 | if (ifmgd->associated && |
---|
3560 | 3826 | ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) |
---|
.. | .. |
---|
3681 | 3947 | } |
---|
3682 | 3948 | } |
---|
3683 | 3949 | |
---|
| 3950 | +static bool ieee80211_rx_our_beacon(const u8 *tx_bssid, |
---|
| 3951 | + struct cfg80211_bss *bss) |
---|
| 3952 | +{ |
---|
| 3953 | + if (ether_addr_equal(tx_bssid, bss->bssid)) |
---|
| 3954 | + return true; |
---|
| 3955 | + if (!bss->transmitted_bss) |
---|
| 3956 | + return false; |
---|
| 3957 | + return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid); |
---|
| 3958 | +} |
---|
| 3959 | + |
---|
3684 | 3960 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
---|
3685 | | - struct ieee80211_mgmt *mgmt, size_t len, |
---|
| 3961 | + struct ieee80211_hdr *hdr, size_t len, |
---|
3686 | 3962 | struct ieee80211_rx_status *rx_status) |
---|
3687 | 3963 | { |
---|
3688 | 3964 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
3689 | 3965 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
---|
| 3966 | + struct ieee80211_mgmt *mgmt = (void *) hdr; |
---|
3690 | 3967 | size_t baselen; |
---|
3691 | 3968 | struct ieee802_11_elems elems; |
---|
3692 | 3969 | struct ieee80211_local *local = sdata->local; |
---|
.. | .. |
---|
3696 | 3973 | u32 changed = 0; |
---|
3697 | 3974 | bool erp_valid; |
---|
3698 | 3975 | u8 erp_value = 0; |
---|
3699 | | - u32 ncrc; |
---|
3700 | | - u8 *bssid; |
---|
| 3976 | + u32 ncrc = 0; |
---|
| 3977 | + u8 *bssid, *variable = mgmt->u.beacon.variable; |
---|
3701 | 3978 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
---|
3702 | 3979 | |
---|
3703 | 3980 | sdata_assert_lock(sdata); |
---|
3704 | 3981 | |
---|
3705 | 3982 | /* Process beacon from the current BSS */ |
---|
3706 | | - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
---|
| 3983 | + bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type); |
---|
| 3984 | + if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { |
---|
| 3985 | + struct ieee80211_ext *ext = (void *) mgmt; |
---|
| 3986 | + |
---|
| 3987 | + if (ieee80211_is_s1g_short_beacon(ext->frame_control)) |
---|
| 3988 | + variable = ext->u.s1g_short_beacon.variable; |
---|
| 3989 | + else |
---|
| 3990 | + variable = ext->u.s1g_beacon.variable; |
---|
| 3991 | + } |
---|
| 3992 | + |
---|
| 3993 | + baselen = (u8 *) variable - (u8 *) mgmt; |
---|
3707 | 3994 | if (baselen > len) |
---|
3708 | 3995 | return; |
---|
3709 | 3996 | |
---|
.. | .. |
---|
3714 | 4001 | return; |
---|
3715 | 4002 | } |
---|
3716 | 4003 | |
---|
3717 | | - if (rx_status->freq != chanctx_conf->def.chan->center_freq) { |
---|
| 4004 | + if (ieee80211_rx_status_to_khz(rx_status) != |
---|
| 4005 | + ieee80211_channel_to_khz(chanctx_conf->def.chan)) { |
---|
3718 | 4006 | rcu_read_unlock(); |
---|
3719 | 4007 | return; |
---|
3720 | 4008 | } |
---|
.. | .. |
---|
3722 | 4010 | rcu_read_unlock(); |
---|
3723 | 4011 | |
---|
3724 | 4012 | if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && |
---|
3725 | | - ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { |
---|
3726 | | - ieee802_11_parse_elems(mgmt->u.beacon.variable, |
---|
3727 | | - len - baselen, false, &elems); |
---|
| 4013 | + ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) { |
---|
| 4014 | + ieee802_11_parse_elems(variable, |
---|
| 4015 | + len - baselen, false, &elems, |
---|
| 4016 | + bssid, |
---|
| 4017 | + ifmgd->assoc_data->bss->bssid); |
---|
3728 | 4018 | |
---|
3729 | | - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
---|
3730 | | - if (elems.tim && !elems.parse_error) { |
---|
3731 | | - const struct ieee80211_tim_ie *tim_ie = elems.tim; |
---|
3732 | | - ifmgd->dtim_period = tim_ie->dtim_period; |
---|
3733 | | - } |
---|
| 4019 | + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); |
---|
| 4020 | + |
---|
| 4021 | + if (elems.dtim_period) |
---|
| 4022 | + ifmgd->dtim_period = elems.dtim_period; |
---|
3734 | 4023 | ifmgd->have_beacon = true; |
---|
3735 | 4024 | ifmgd->assoc_data->need_beacon = false; |
---|
3736 | 4025 | if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { |
---|
.. | .. |
---|
3738 | 4027 | le64_to_cpu(mgmt->u.beacon.timestamp); |
---|
3739 | 4028 | sdata->vif.bss_conf.sync_device_ts = |
---|
3740 | 4029 | rx_status->device_timestamp; |
---|
3741 | | - if (elems.tim) |
---|
3742 | | - sdata->vif.bss_conf.sync_dtim_count = |
---|
3743 | | - elems.tim->dtim_count; |
---|
3744 | | - else |
---|
3745 | | - sdata->vif.bss_conf.sync_dtim_count = 0; |
---|
| 4030 | + sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; |
---|
3746 | 4031 | } |
---|
| 4032 | + |
---|
| 4033 | + if (elems.mbssid_config_ie) |
---|
| 4034 | + bss_conf->profile_periodicity = |
---|
| 4035 | + elems.mbssid_config_ie->profile_periodicity; |
---|
| 4036 | + else |
---|
| 4037 | + bss_conf->profile_periodicity = 0; |
---|
| 4038 | + |
---|
| 4039 | + if (elems.ext_capab_len >= 11 && |
---|
| 4040 | + (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) |
---|
| 4041 | + bss_conf->ema_ap = true; |
---|
| 4042 | + else |
---|
| 4043 | + bss_conf->ema_ap = false; |
---|
| 4044 | + |
---|
3747 | 4045 | /* continue assoc process */ |
---|
3748 | 4046 | ifmgd->assoc_data->timeout = jiffies; |
---|
3749 | 4047 | ifmgd->assoc_data->timeout_started = true; |
---|
3750 | 4048 | run_again(sdata, ifmgd->assoc_data->timeout); |
---|
| 4049 | + kfree(elems.nontx_profile); |
---|
3751 | 4050 | return; |
---|
3752 | 4051 | } |
---|
3753 | 4052 | |
---|
3754 | 4053 | if (!ifmgd->associated || |
---|
3755 | | - !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) |
---|
| 4054 | + !ieee80211_rx_our_beacon(bssid, ifmgd->associated)) |
---|
3756 | 4055 | return; |
---|
3757 | 4056 | bssid = ifmgd->associated->bssid; |
---|
3758 | 4057 | |
---|
.. | .. |
---|
3772 | 4071 | */ |
---|
3773 | 4072 | ieee80211_sta_reset_beacon_monitor(sdata); |
---|
3774 | 4073 | |
---|
3775 | | - ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
---|
3776 | | - ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
---|
| 4074 | + /* TODO: CRC urrently not calculated on S1G Beacon Compatibility |
---|
| 4075 | + * element (which carries the beacon interval). Don't forget to add a |
---|
| 4076 | + * bit to care_about_ies[] above if mac80211 is interested in a |
---|
| 4077 | + * changing S1G element. |
---|
| 4078 | + */ |
---|
| 4079 | + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) |
---|
| 4080 | + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
---|
| 4081 | + ncrc = ieee802_11_parse_elems_crc(variable, |
---|
3777 | 4082 | len - baselen, false, &elems, |
---|
3778 | | - care_about_ies, ncrc); |
---|
| 4083 | + care_about_ies, ncrc, |
---|
| 4084 | + mgmt->bssid, bssid); |
---|
3779 | 4085 | |
---|
3780 | 4086 | if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && |
---|
3781 | | - ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) { |
---|
| 4087 | + ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { |
---|
3782 | 4088 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
---|
3783 | 4089 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
---|
3784 | 4090 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; |
---|
.. | .. |
---|
3806 | 4112 | struct ieee80211_p2p_noa_attr noa = {}; |
---|
3807 | 4113 | int ret; |
---|
3808 | 4114 | |
---|
3809 | | - ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable, |
---|
| 4115 | + ret = cfg80211_get_p2p_attr(variable, |
---|
3810 | 4116 | len - baselen, |
---|
3811 | 4117 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, |
---|
3812 | 4118 | (u8 *) &noa, sizeof(noa)); |
---|
.. | .. |
---|
3842 | 4148 | * the driver will use them. The synchronized view is currently |
---|
3843 | 4149 | * guaranteed only in certain callbacks. |
---|
3844 | 4150 | */ |
---|
3845 | | - if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { |
---|
| 4151 | + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) && |
---|
| 4152 | + !ieee80211_is_s1g_beacon(hdr->frame_control)) { |
---|
3846 | 4153 | sdata->vif.bss_conf.sync_tsf = |
---|
3847 | 4154 | le64_to_cpu(mgmt->u.beacon.timestamp); |
---|
3848 | 4155 | sdata->vif.bss_conf.sync_device_ts = |
---|
3849 | 4156 | rx_status->device_timestamp; |
---|
3850 | | - if (elems.tim) |
---|
3851 | | - sdata->vif.bss_conf.sync_dtim_count = |
---|
3852 | | - elems.tim->dtim_count; |
---|
3853 | | - else |
---|
3854 | | - sdata->vif.bss_conf.sync_dtim_count = 0; |
---|
| 4157 | + sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; |
---|
3855 | 4158 | } |
---|
3856 | 4159 | |
---|
3857 | | - if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
---|
| 4160 | + if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) || |
---|
| 4161 | + ieee80211_is_s1g_short_beacon(mgmt->frame_control)) |
---|
3858 | 4162 | return; |
---|
3859 | 4163 | ifmgd->beacon_crc = ncrc; |
---|
3860 | 4164 | ifmgd->beacon_crc_valid = true; |
---|
3861 | 4165 | |
---|
3862 | | - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
---|
| 4166 | + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); |
---|
3863 | 4167 | |
---|
3864 | 4168 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
---|
3865 | 4169 | rx_status->device_timestamp, |
---|
.. | .. |
---|
3877 | 4181 | */ |
---|
3878 | 4182 | if (!ifmgd->have_beacon) { |
---|
3879 | 4183 | /* a few bogus AP send dtim_period = 0 or no TIM IE */ |
---|
3880 | | - if (elems.tim) |
---|
3881 | | - bss_conf->dtim_period = elems.tim->dtim_period ?: 1; |
---|
3882 | | - else |
---|
3883 | | - bss_conf->dtim_period = 1; |
---|
| 4184 | + bss_conf->dtim_period = elems.dtim_period ?: 1; |
---|
3884 | 4185 | |
---|
3885 | 4186 | changed |= BSS_CHANGED_BEACON_INFO; |
---|
3886 | 4187 | ifmgd->have_beacon = true; |
---|
.. | .. |
---|
3898 | 4199 | } else { |
---|
3899 | 4200 | erp_valid = false; |
---|
3900 | 4201 | } |
---|
3901 | | - changed |= ieee80211_handle_bss_capability(sdata, |
---|
3902 | | - le16_to_cpu(mgmt->u.beacon.capab_info), |
---|
3903 | | - erp_valid, erp_value); |
---|
| 4202 | + |
---|
| 4203 | + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) |
---|
| 4204 | + changed |= ieee80211_handle_bss_capability(sdata, |
---|
| 4205 | + le16_to_cpu(mgmt->u.beacon.capab_info), |
---|
| 4206 | + erp_valid, erp_value); |
---|
3904 | 4207 | |
---|
3905 | 4208 | mutex_lock(&local->sta_mtx); |
---|
3906 | 4209 | sta = sta_info_get(sdata, bssid); |
---|
3907 | 4210 | |
---|
3908 | | - if (ieee80211_config_bw(sdata, sta, |
---|
3909 | | - elems.ht_cap_elem, elems.ht_operation, |
---|
| 4211 | + changed |= ieee80211_recalc_twt_req(sdata, sta, &elems); |
---|
| 4212 | + |
---|
| 4213 | + if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem, |
---|
| 4214 | + elems.vht_cap_elem, elems.ht_operation, |
---|
3910 | 4215 | elems.vht_operation, elems.he_operation, |
---|
3911 | | - bssid, &changed)) { |
---|
| 4216 | + elems.s1g_oper, bssid, &changed)) { |
---|
3912 | 4217 | mutex_unlock(&local->sta_mtx); |
---|
3913 | 4218 | sdata_info(sdata, |
---|
3914 | 4219 | "failed to follow AP %pM bandwidth change, disconnect\n", |
---|
.. | .. |
---|
3919 | 4224 | ieee80211_report_disconnect(sdata, deauth_buf, |
---|
3920 | 4225 | sizeof(deauth_buf), true, |
---|
3921 | 4226 | WLAN_REASON_DEAUTH_LEAVING); |
---|
3922 | | - return; |
---|
| 4227 | + goto free; |
---|
3923 | 4228 | } |
---|
3924 | 4229 | |
---|
3925 | 4230 | if (sta && elems.opmode_notif) |
---|
.. | .. |
---|
3934 | 4239 | elems.cisco_dtpc_elem); |
---|
3935 | 4240 | |
---|
3936 | 4241 | ieee80211_bss_info_change_notify(sdata, changed); |
---|
| 4242 | +free: |
---|
| 4243 | + kfree(elems.nontx_profile); |
---|
| 4244 | +} |
---|
| 4245 | + |
---|
| 4246 | +void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, |
---|
| 4247 | + struct sk_buff *skb) |
---|
| 4248 | +{ |
---|
| 4249 | + struct ieee80211_rx_status *rx_status; |
---|
| 4250 | + struct ieee80211_hdr *hdr; |
---|
| 4251 | + u16 fc; |
---|
| 4252 | + |
---|
| 4253 | + rx_status = (struct ieee80211_rx_status *) skb->cb; |
---|
| 4254 | + hdr = (struct ieee80211_hdr *) skb->data; |
---|
| 4255 | + fc = le16_to_cpu(hdr->frame_control); |
---|
| 4256 | + |
---|
| 4257 | + sdata_lock(sdata); |
---|
| 4258 | + switch (fc & IEEE80211_FCTL_STYPE) { |
---|
| 4259 | + case IEEE80211_STYPE_S1G_BEACON: |
---|
| 4260 | + ieee80211_rx_mgmt_beacon(sdata, hdr, skb->len, rx_status); |
---|
| 4261 | + break; |
---|
| 4262 | + } |
---|
| 4263 | + sdata_unlock(sdata); |
---|
3937 | 4264 | } |
---|
3938 | 4265 | |
---|
3939 | 4266 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
---|
.. | .. |
---|
3953 | 4280 | |
---|
3954 | 4281 | switch (fc & IEEE80211_FCTL_STYPE) { |
---|
3955 | 4282 | case IEEE80211_STYPE_BEACON: |
---|
3956 | | - ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); |
---|
| 4283 | + ieee80211_rx_mgmt_beacon(sdata, (void *)mgmt, |
---|
| 4284 | + skb->len, rx_status); |
---|
3957 | 4285 | break; |
---|
3958 | 4286 | case IEEE80211_STYPE_PROBE_RESP: |
---|
3959 | 4287 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
---|
.. | .. |
---|
3980 | 4308 | if (ies_len < 0) |
---|
3981 | 4309 | break; |
---|
3982 | 4310 | |
---|
| 4311 | + /* CSA IE cannot be overridden, no need for BSSID */ |
---|
3983 | 4312 | ieee802_11_parse_elems( |
---|
3984 | 4313 | mgmt->u.action.u.chan_switch.variable, |
---|
3985 | | - ies_len, true, &elems); |
---|
| 4314 | + ies_len, true, &elems, mgmt->bssid, NULL); |
---|
3986 | 4315 | |
---|
3987 | 4316 | if (elems.parse_error) |
---|
3988 | 4317 | break; |
---|
.. | .. |
---|
3999 | 4328 | if (ies_len < 0) |
---|
4000 | 4329 | break; |
---|
4001 | 4330 | |
---|
| 4331 | + /* |
---|
| 4332 | + * extended CSA IE can't be overridden, no need for |
---|
| 4333 | + * BSSID |
---|
| 4334 | + */ |
---|
4002 | 4335 | ieee802_11_parse_elems( |
---|
4003 | 4336 | mgmt->u.action.u.ext_chan_switch.variable, |
---|
4004 | | - ies_len, true, &elems); |
---|
| 4337 | + ies_len, true, &elems, mgmt->bssid, NULL); |
---|
4005 | 4338 | |
---|
4006 | 4339 | if (elems.parse_error) |
---|
4007 | 4340 | break; |
---|
.. | .. |
---|
4212 | 4545 | |
---|
4213 | 4546 | if (ifmgd->auth_data && ifmgd->auth_data->timeout_started && |
---|
4214 | 4547 | time_after(jiffies, ifmgd->auth_data->timeout)) { |
---|
4215 | | - if (ifmgd->auth_data->done) { |
---|
| 4548 | + if (ifmgd->auth_data->done || ifmgd->auth_data->waiting) { |
---|
4216 | 4549 | /* |
---|
4217 | | - * ok ... we waited for assoc but userspace didn't, |
---|
4218 | | - * so let's just kill the auth data |
---|
| 4550 | + * ok ... we waited for assoc or continuation but |
---|
| 4551 | + * userspace didn't do it, so kill the auth data |
---|
4219 | 4552 | */ |
---|
4220 | 4553 | ieee80211_destroy_auth_data(sdata, false); |
---|
4221 | 4554 | } else if (ieee80211_auth(sdata)) { |
---|
.. | .. |
---|
4324 | 4657 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
---|
4325 | 4658 | return; |
---|
4326 | 4659 | |
---|
| 4660 | + if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) |
---|
| 4661 | + return; |
---|
| 4662 | + |
---|
4327 | 4663 | sdata->u.mgd.connection_loss = false; |
---|
4328 | 4664 | ieee80211_queue_work(&sdata->local->hw, |
---|
4329 | 4665 | &sdata->u.mgd.beacon_connection_loss_work); |
---|
.. | .. |
---|
4335 | 4671 | from_timer(sdata, t, u.mgd.conn_mon_timer); |
---|
4336 | 4672 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
4337 | 4673 | struct ieee80211_local *local = sdata->local; |
---|
| 4674 | + struct sta_info *sta; |
---|
| 4675 | + unsigned long timeout; |
---|
4338 | 4676 | |
---|
4339 | 4677 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
---|
4340 | 4678 | return; |
---|
| 4679 | + |
---|
| 4680 | + sta = sta_info_get(sdata, ifmgd->bssid); |
---|
| 4681 | + if (!sta) |
---|
| 4682 | + return; |
---|
| 4683 | + |
---|
| 4684 | + timeout = sta->status_stats.last_ack; |
---|
| 4685 | + if (time_before(sta->status_stats.last_ack, sta->rx_stats.last_rx)) |
---|
| 4686 | + timeout = sta->rx_stats.last_rx; |
---|
| 4687 | + timeout += IEEE80211_CONNECTION_IDLE_TIME; |
---|
| 4688 | + |
---|
| 4689 | + /* If timeout is after now, then update timer to fire at |
---|
| 4690 | + * the later date, but do not actually probe at this time. |
---|
| 4691 | + */ |
---|
| 4692 | + if (time_is_after_jiffies(timeout)) { |
---|
| 4693 | + mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout)); |
---|
| 4694 | + return; |
---|
| 4695 | + } |
---|
4341 | 4696 | |
---|
4342 | 4697 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); |
---|
4343 | 4698 | } |
---|
.. | .. |
---|
4381 | 4736 | * cfg80211 won't know and won't actually abort those attempts, |
---|
4382 | 4737 | * thus we need to do that ourselves. |
---|
4383 | 4738 | */ |
---|
4384 | | - ieee80211_send_deauth_disassoc(sdata, bssid, |
---|
| 4739 | + ieee80211_send_deauth_disassoc(sdata, bssid, bssid, |
---|
4385 | 4740 | IEEE80211_STYPE_DEAUTH, |
---|
4386 | 4741 | WLAN_REASON_DEAUTH_LEAVING, |
---|
4387 | 4742 | false, frame_buf); |
---|
.. | .. |
---|
4616 | 4971 | const struct ieee80211_ht_operation *ht_oper = NULL; |
---|
4617 | 4972 | const struct ieee80211_vht_operation *vht_oper = NULL; |
---|
4618 | 4973 | const struct ieee80211_he_operation *he_oper = NULL; |
---|
| 4974 | + const struct ieee80211_s1g_oper_ie *s1g_oper = NULL; |
---|
4619 | 4975 | struct ieee80211_supported_band *sband; |
---|
4620 | 4976 | struct cfg80211_chan_def chandef; |
---|
| 4977 | + bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; |
---|
| 4978 | + bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; |
---|
| 4979 | + struct ieee80211_bss *bss = (void *)cbss->priv; |
---|
4621 | 4980 | int ret; |
---|
4622 | 4981 | u32 i; |
---|
4623 | 4982 | bool have_80mhz; |
---|
.. | .. |
---|
4628 | 4987 | IEEE80211_STA_DISABLE_80P80MHZ | |
---|
4629 | 4988 | IEEE80211_STA_DISABLE_160MHZ); |
---|
4630 | 4989 | |
---|
| 4990 | + /* disable HT/VHT/HE if we don't support them */ |
---|
| 4991 | + if (!sband->ht_cap.ht_supported && !is_6ghz) { |
---|
| 4992 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
---|
| 4993 | + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
| 4994 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
| 4995 | + } |
---|
| 4996 | + |
---|
| 4997 | + if (!sband->vht_cap.vht_supported && is_5ghz) { |
---|
| 4998 | + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
| 4999 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
| 5000 | + } |
---|
| 5001 | + |
---|
| 5002 | + if (!ieee80211_get_he_sta_cap(sband)) |
---|
| 5003 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
| 5004 | + |
---|
4631 | 5005 | rcu_read_lock(); |
---|
4632 | 5006 | |
---|
4633 | | - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
---|
4634 | | - sband->ht_cap.ht_supported) { |
---|
| 5007 | + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && !is_6ghz) { |
---|
4635 | 5008 | const u8 *ht_oper_ie, *ht_cap_ie; |
---|
4636 | 5009 | |
---|
4637 | 5010 | ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); |
---|
.. | .. |
---|
4648 | 5021 | } |
---|
4649 | 5022 | } |
---|
4650 | 5023 | |
---|
4651 | | - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
---|
4652 | | - sband->vht_cap.vht_supported) { |
---|
| 5024 | + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && !is_6ghz) { |
---|
4653 | 5025 | const u8 *vht_oper_ie, *vht_cap; |
---|
4654 | 5026 | |
---|
4655 | 5027 | vht_oper_ie = ieee80211_bss_get_ie(cbss, |
---|
.. | .. |
---|
4659 | 5031 | if (vht_oper && !ht_oper) { |
---|
4660 | 5032 | vht_oper = NULL; |
---|
4661 | 5033 | sdata_info(sdata, |
---|
4662 | | - "AP advertised VHT without HT, disabling both\n"); |
---|
| 5034 | + "AP advertised VHT without HT, disabling HT/VHT/HE\n"); |
---|
4663 | 5035 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
---|
4664 | 5036 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
| 5037 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
4665 | 5038 | } |
---|
4666 | 5039 | |
---|
4667 | 5040 | vht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY); |
---|
.. | .. |
---|
4671 | 5044 | } |
---|
4672 | 5045 | } |
---|
4673 | 5046 | |
---|
4674 | | - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && |
---|
4675 | | - ieee80211_get_he_sta_cap(sband)) { |
---|
| 5047 | + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) { |
---|
4676 | 5048 | const struct cfg80211_bss_ies *ies; |
---|
4677 | 5049 | const u8 *he_oper_ie; |
---|
4678 | 5050 | |
---|
.. | .. |
---|
4680 | 5052 | he_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, |
---|
4681 | 5053 | ies->data, ies->len); |
---|
4682 | 5054 | if (he_oper_ie && |
---|
4683 | | - he_oper_ie[1] == ieee80211_he_oper_size(&he_oper_ie[3])) |
---|
| 5055 | + he_oper_ie[1] >= ieee80211_he_oper_size(&he_oper_ie[3])) |
---|
4684 | 5056 | he_oper = (void *)(he_oper_ie + 3); |
---|
4685 | 5057 | else |
---|
4686 | 5058 | he_oper = NULL; |
---|
.. | .. |
---|
4703 | 5075 | if (!have_80mhz) |
---|
4704 | 5076 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
4705 | 5077 | |
---|
| 5078 | + if (sband->band == NL80211_BAND_S1GHZ) { |
---|
| 5079 | + const u8 *s1g_oper_ie; |
---|
| 5080 | + |
---|
| 5081 | + s1g_oper_ie = ieee80211_bss_get_ie(cbss, |
---|
| 5082 | + WLAN_EID_S1G_OPERATION); |
---|
| 5083 | + if (s1g_oper_ie && s1g_oper_ie[1] >= sizeof(*s1g_oper)) |
---|
| 5084 | + s1g_oper = (void *)(s1g_oper_ie + 2); |
---|
| 5085 | + else |
---|
| 5086 | + sdata_info(sdata, |
---|
| 5087 | + "AP missing S1G operation element?\n"); |
---|
| 5088 | + } |
---|
| 5089 | + |
---|
4706 | 5090 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, |
---|
4707 | 5091 | cbss->channel, |
---|
| 5092 | + bss->vht_cap_info, |
---|
4708 | 5093 | ht_oper, vht_oper, he_oper, |
---|
| 5094 | + s1g_oper, |
---|
4709 | 5095 | &chandef, false); |
---|
4710 | 5096 | |
---|
4711 | 5097 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), |
---|
4712 | 5098 | local->rx_chains); |
---|
4713 | 5099 | |
---|
4714 | 5100 | rcu_read_unlock(); |
---|
| 5101 | + |
---|
| 5102 | + if (ifmgd->flags & IEEE80211_STA_DISABLE_HE && is_6ghz) { |
---|
| 5103 | + sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection"); |
---|
| 5104 | + return -EINVAL; |
---|
| 5105 | + } |
---|
4715 | 5106 | |
---|
4716 | 5107 | /* will change later if needed */ |
---|
4717 | 5108 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
---|
.. | .. |
---|
4738 | 5129 | out: |
---|
4739 | 5130 | mutex_unlock(&local->mtx); |
---|
4740 | 5131 | return ret; |
---|
| 5132 | +} |
---|
| 5133 | + |
---|
| 5134 | +static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies, |
---|
| 5135 | + u8 *dtim_count, u8 *dtim_period) |
---|
| 5136 | +{ |
---|
| 5137 | + const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); |
---|
| 5138 | + const u8 *idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, ies->data, |
---|
| 5139 | + ies->len); |
---|
| 5140 | + const struct ieee80211_tim_ie *tim = NULL; |
---|
| 5141 | + const struct ieee80211_bssid_index *idx; |
---|
| 5142 | + bool valid = tim_ie && tim_ie[1] >= 2; |
---|
| 5143 | + |
---|
| 5144 | + if (valid) |
---|
| 5145 | + tim = (void *)(tim_ie + 2); |
---|
| 5146 | + |
---|
| 5147 | + if (dtim_count) |
---|
| 5148 | + *dtim_count = valid ? tim->dtim_count : 0; |
---|
| 5149 | + |
---|
| 5150 | + if (dtim_period) |
---|
| 5151 | + *dtim_period = valid ? tim->dtim_period : 0; |
---|
| 5152 | + |
---|
| 5153 | + /* Check if value is overridden by non-transmitted profile */ |
---|
| 5154 | + if (!idx_ie || idx_ie[1] < 3) |
---|
| 5155 | + return valid; |
---|
| 5156 | + |
---|
| 5157 | + idx = (void *)(idx_ie + 2); |
---|
| 5158 | + |
---|
| 5159 | + if (dtim_count) |
---|
| 5160 | + *dtim_count = idx->dtim_count; |
---|
| 5161 | + |
---|
| 5162 | + if (dtim_period) |
---|
| 5163 | + *dtim_period = idx->dtim_period; |
---|
| 5164 | + |
---|
| 5165 | + return true; |
---|
4741 | 5166 | } |
---|
4742 | 5167 | |
---|
4743 | 5168 | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, |
---|
.. | .. |
---|
4793 | 5218 | const struct cfg80211_bss_ies *ies; |
---|
4794 | 5219 | int shift = ieee80211_vif_get_shift(&sdata->vif); |
---|
4795 | 5220 | |
---|
| 5221 | + /* TODO: S1G Basic Rate Set is expressed elsewhere */ |
---|
| 5222 | + if (cbss->channel->band == NL80211_BAND_S1GHZ) { |
---|
| 5223 | + ieee80211_s1g_sta_rate_init(new_sta); |
---|
| 5224 | + goto skip_rates; |
---|
| 5225 | + } |
---|
| 5226 | + |
---|
4796 | 5227 | ieee80211_get_rates(sband, bss->supp_rates, |
---|
4797 | 5228 | bss->supp_rates_len, |
---|
4798 | 5229 | &rates, &basic_rates, |
---|
.. | .. |
---|
4807 | 5238 | * doesn't happen any more, but keep the workaround so |
---|
4808 | 5239 | * in case some *other* APs are buggy in different ways |
---|
4809 | 5240 | * we can connect -- with a warning. |
---|
| 5241 | + * Allow this workaround only in case the AP provided at least |
---|
| 5242 | + * one rate. |
---|
4810 | 5243 | */ |
---|
4811 | | - if (!basic_rates && min_rate_index >= 0) { |
---|
| 5244 | + if (min_rate_index < 0) { |
---|
| 5245 | + sdata_info(sdata, |
---|
| 5246 | + "No legacy rates in association response\n"); |
---|
| 5247 | + |
---|
| 5248 | + sta_info_free(local, new_sta); |
---|
| 5249 | + return -EINVAL; |
---|
| 5250 | + } else if (!basic_rates) { |
---|
4812 | 5251 | sdata_info(sdata, |
---|
4813 | 5252 | "No basic rates, using min rate instead\n"); |
---|
4814 | 5253 | basic_rates = BIT(min_rate_index); |
---|
4815 | 5254 | } |
---|
4816 | 5255 | |
---|
4817 | | - new_sta->sta.supp_rates[cbss->channel->band] = rates; |
---|
| 5256 | + if (rates) |
---|
| 5257 | + new_sta->sta.supp_rates[cbss->channel->band] = rates; |
---|
| 5258 | + else |
---|
| 5259 | + sdata_info(sdata, |
---|
| 5260 | + "No rates found, keeping mandatory only\n"); |
---|
| 5261 | + |
---|
4818 | 5262 | sdata->vif.bss_conf.basic_rates = basic_rates; |
---|
4819 | 5263 | |
---|
4820 | 5264 | /* cf. IEEE 802.11 9.2.12 */ |
---|
.. | .. |
---|
4824 | 5268 | else |
---|
4825 | 5269 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
---|
4826 | 5270 | |
---|
| 5271 | +skip_rates: |
---|
4827 | 5272 | memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN); |
---|
4828 | 5273 | |
---|
4829 | 5274 | /* set timing information */ |
---|
.. | .. |
---|
4831 | 5276 | rcu_read_lock(); |
---|
4832 | 5277 | ies = rcu_dereference(cbss->beacon_ies); |
---|
4833 | 5278 | if (ies) { |
---|
4834 | | - const u8 *tim_ie; |
---|
4835 | | - |
---|
4836 | 5279 | sdata->vif.bss_conf.sync_tsf = ies->tsf; |
---|
4837 | 5280 | sdata->vif.bss_conf.sync_device_ts = |
---|
4838 | 5281 | bss->device_ts_beacon; |
---|
4839 | | - tim_ie = cfg80211_find_ie(WLAN_EID_TIM, |
---|
4840 | | - ies->data, ies->len); |
---|
4841 | | - if (tim_ie && tim_ie[1] >= 2) |
---|
4842 | | - sdata->vif.bss_conf.sync_dtim_count = tim_ie[2]; |
---|
4843 | | - else |
---|
4844 | | - sdata->vif.bss_conf.sync_dtim_count = 0; |
---|
| 5282 | + |
---|
| 5283 | + ieee80211_get_dtim(ies, |
---|
| 5284 | + &sdata->vif.bss_conf.sync_dtim_count, |
---|
| 5285 | + NULL); |
---|
4845 | 5286 | } else if (!ieee80211_hw_check(&sdata->local->hw, |
---|
4846 | 5287 | TIMING_BEACON_ONLY)) { |
---|
4847 | 5288 | ies = rcu_dereference(cbss->proberesp_ies); |
---|
.. | .. |
---|
4906 | 5347 | struct ieee80211_mgd_auth_data *auth_data; |
---|
4907 | 5348 | u16 auth_alg; |
---|
4908 | 5349 | int err; |
---|
| 5350 | + bool cont_auth; |
---|
4909 | 5351 | |
---|
4910 | 5352 | /* prepare auth data structure */ |
---|
4911 | 5353 | |
---|
.. | .. |
---|
4914 | 5356 | auth_alg = WLAN_AUTH_OPEN; |
---|
4915 | 5357 | break; |
---|
4916 | 5358 | case NL80211_AUTHTYPE_SHARED_KEY: |
---|
4917 | | - if (IS_ERR(local->wep_tx_tfm)) |
---|
| 5359 | + if (fips_enabled) |
---|
4918 | 5360 | return -EOPNOTSUPP; |
---|
4919 | 5361 | auth_alg = WLAN_AUTH_SHARED_KEY; |
---|
4920 | 5362 | break; |
---|
.. | .. |
---|
4940 | 5382 | return -EOPNOTSUPP; |
---|
4941 | 5383 | } |
---|
4942 | 5384 | |
---|
| 5385 | + if (ifmgd->assoc_data) |
---|
| 5386 | + return -EBUSY; |
---|
| 5387 | + |
---|
4943 | 5388 | auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len + |
---|
4944 | 5389 | req->ie_len, GFP_KERNEL); |
---|
4945 | 5390 | if (!auth_data) |
---|
.. | .. |
---|
4959 | 5404 | auth_data->data_len += req->auth_data_len - 4; |
---|
4960 | 5405 | } |
---|
4961 | 5406 | |
---|
| 5407 | + /* Check if continuing authentication or trying to authenticate with the |
---|
| 5408 | + * same BSS that we were in the process of authenticating with and avoid |
---|
| 5409 | + * removal and re-addition of the STA entry in |
---|
| 5410 | + * ieee80211_prep_connection(). |
---|
| 5411 | + */ |
---|
| 5412 | + cont_auth = ifmgd->auth_data && req->bss == ifmgd->auth_data->bss; |
---|
| 5413 | + |
---|
4962 | 5414 | if (req->ie && req->ie_len) { |
---|
4963 | 5415 | memcpy(&auth_data->data[auth_data->data_len], |
---|
4964 | 5416 | req->ie, req->ie_len); |
---|
.. | .. |
---|
4975 | 5427 | |
---|
4976 | 5428 | /* try to authenticate/probe */ |
---|
4977 | 5429 | |
---|
4978 | | - if ((ifmgd->auth_data && !ifmgd->auth_data->done) || |
---|
4979 | | - ifmgd->assoc_data) { |
---|
4980 | | - err = -EBUSY; |
---|
4981 | | - goto err_free; |
---|
| 5430 | + if (ifmgd->auth_data) { |
---|
| 5431 | + if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE) { |
---|
| 5432 | + auth_data->peer_confirmed = |
---|
| 5433 | + ifmgd->auth_data->peer_confirmed; |
---|
| 5434 | + } |
---|
| 5435 | + ieee80211_destroy_auth_data(sdata, cont_auth); |
---|
4982 | 5436 | } |
---|
4983 | | - |
---|
4984 | | - if (ifmgd->auth_data) |
---|
4985 | | - ieee80211_destroy_auth_data(sdata, false); |
---|
4986 | 5437 | |
---|
4987 | 5438 | /* prep auth_data so we don't go into idle on disassoc */ |
---|
4988 | 5439 | ifmgd->auth_data = auth_data; |
---|
| 5440 | + |
---|
| 5441 | + /* If this is continuation of an ongoing SAE authentication exchange |
---|
| 5442 | + * (i.e., request to send SAE Confirm) and the peer has already |
---|
| 5443 | + * confirmed, mark authentication completed since we are about to send |
---|
| 5444 | + * out SAE Confirm. |
---|
| 5445 | + */ |
---|
| 5446 | + if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE && |
---|
| 5447 | + auth_data->peer_confirmed && auth_data->sae_trans == 2) |
---|
| 5448 | + ieee80211_mark_sta_auth(sdata, req->bss->bssid); |
---|
4989 | 5449 | |
---|
4990 | 5450 | if (ifmgd->associated) { |
---|
4991 | 5451 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
---|
.. | .. |
---|
5004 | 5464 | |
---|
5005 | 5465 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); |
---|
5006 | 5466 | |
---|
5007 | | - err = ieee80211_prep_connection(sdata, req->bss, false, false); |
---|
| 5467 | + err = ieee80211_prep_connection(sdata, req->bss, cont_auth, false); |
---|
5008 | 5468 | if (err) |
---|
5009 | 5469 | goto err_clear; |
---|
5010 | 5470 | |
---|
.. | .. |
---|
5025 | 5485 | mutex_lock(&sdata->local->mtx); |
---|
5026 | 5486 | ieee80211_vif_release_channel(sdata); |
---|
5027 | 5487 | mutex_unlock(&sdata->local->mtx); |
---|
5028 | | - err_free: |
---|
5029 | 5488 | kfree(auth_data); |
---|
5030 | 5489 | return err; |
---|
5031 | 5490 | } |
---|
.. | .. |
---|
5033 | 5492 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
---|
5034 | 5493 | struct cfg80211_assoc_request *req) |
---|
5035 | 5494 | { |
---|
| 5495 | + bool is_6ghz = req->bss->channel->band == NL80211_BAND_6GHZ; |
---|
| 5496 | + bool is_5ghz = req->bss->channel->band == NL80211_BAND_5GHZ; |
---|
5036 | 5497 | struct ieee80211_local *local = sdata->local; |
---|
5037 | 5498 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
---|
5038 | 5499 | struct ieee80211_bss *bss = (void *)req->bss->priv; |
---|
.. | .. |
---|
5113 | 5574 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
5114 | 5575 | ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
5115 | 5576 | netdev_info(sdata->dev, |
---|
5116 | | - "disabling HE/HT/VHT due to WEP/TKIP use\n"); |
---|
| 5577 | + "disabling HT/VHT/HE due to WEP/TKIP use\n"); |
---|
5117 | 5578 | } |
---|
5118 | 5579 | } |
---|
5119 | 5580 | |
---|
5120 | | - /* Also disable HT if we don't support it or the AP doesn't use WMM */ |
---|
5121 | 5581 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
---|
5122 | | - if (!sband->ht_cap.ht_supported || |
---|
5123 | | - local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used || |
---|
5124 | | - ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { |
---|
5125 | | - ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
---|
5126 | | - if (!bss->wmm_used && |
---|
5127 | | - !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM)) |
---|
5128 | | - netdev_info(sdata->dev, |
---|
5129 | | - "disabling HT as WMM/QoS is not supported by the AP\n"); |
---|
5130 | | - } |
---|
5131 | 5582 | |
---|
5132 | | - /* disable VHT if we don't support it or the AP doesn't use WMM */ |
---|
5133 | | - if (!sband->vht_cap.vht_supported || |
---|
5134 | | - local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used || |
---|
5135 | | - ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { |
---|
| 5583 | + /* also disable HT/VHT/HE if the AP doesn't use WMM */ |
---|
| 5584 | + if (!bss->wmm_used) { |
---|
| 5585 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
---|
5136 | 5586 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
5137 | | - if (!bss->wmm_used && |
---|
5138 | | - !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM)) |
---|
5139 | | - netdev_info(sdata->dev, |
---|
5140 | | - "disabling VHT as WMM/QoS is not supported by the AP\n"); |
---|
| 5587 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
| 5588 | + netdev_info(sdata->dev, |
---|
| 5589 | + "disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n"); |
---|
5141 | 5590 | } |
---|
5142 | 5591 | |
---|
5143 | 5592 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); |
---|
.. | .. |
---|
5147 | 5596 | memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa)); |
---|
5148 | 5597 | memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask, |
---|
5149 | 5598 | sizeof(ifmgd->vht_capa_mask)); |
---|
| 5599 | + |
---|
| 5600 | + memcpy(&ifmgd->s1g_capa, &req->s1g_capa, sizeof(ifmgd->s1g_capa)); |
---|
| 5601 | + memcpy(&ifmgd->s1g_capa_mask, &req->s1g_capa_mask, |
---|
| 5602 | + sizeof(ifmgd->s1g_capa_mask)); |
---|
5150 | 5603 | |
---|
5151 | 5604 | if (req->ie && req->ie_len) { |
---|
5152 | 5605 | memcpy(assoc_data->ie, req->ie, req->ie_len); |
---|
.. | .. |
---|
5187 | 5640 | if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation)) |
---|
5188 | 5641 | assoc_data->ap_ht_param = |
---|
5189 | 5642 | ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; |
---|
5190 | | - else |
---|
| 5643 | + else if (!is_6ghz) |
---|
5191 | 5644 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
---|
5192 | 5645 | vht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_VHT_CAPABILITY); |
---|
5193 | 5646 | if (vht_ie && vht_ie[1] >= sizeof(struct ieee80211_vht_cap)) |
---|
5194 | 5647 | memcpy(&assoc_data->ap_vht_cap, vht_ie + 2, |
---|
5195 | 5648 | sizeof(struct ieee80211_vht_cap)); |
---|
5196 | | - else |
---|
5197 | | - ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
| 5649 | + else if (is_5ghz) |
---|
| 5650 | + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT | |
---|
| 5651 | + IEEE80211_STA_DISABLE_HE; |
---|
5198 | 5652 | rcu_read_unlock(); |
---|
5199 | 5653 | |
---|
5200 | 5654 | if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) && |
---|
.. | .. |
---|
5236 | 5690 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; |
---|
5237 | 5691 | sdata->control_port_over_nl80211 = |
---|
5238 | 5692 | req->crypto.control_port_over_nl80211; |
---|
| 5693 | + sdata->control_port_no_preauth = req->crypto.control_port_no_preauth; |
---|
5239 | 5694 | sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, |
---|
5240 | 5695 | sdata->vif.type); |
---|
5241 | 5696 | |
---|
.. | .. |
---|
5269 | 5724 | if (req->flags & ASSOC_REQ_DISABLE_HT) { |
---|
5270 | 5725 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
---|
5271 | 5726 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
---|
| 5727 | + ifmgd->flags |= IEEE80211_STA_DISABLE_HE; |
---|
5272 | 5728 | } |
---|
5273 | 5729 | |
---|
5274 | 5730 | if (req->flags & ASSOC_REQ_DISABLE_VHT) |
---|
.. | .. |
---|
5293 | 5749 | assoc_data->timeout_started = true; |
---|
5294 | 5750 | assoc_data->need_beacon = true; |
---|
5295 | 5751 | } else if (beacon_ies) { |
---|
5296 | | - const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, |
---|
5297 | | - beacon_ies->data, |
---|
5298 | | - beacon_ies->len); |
---|
| 5752 | + const struct element *elem; |
---|
5299 | 5753 | u8 dtim_count = 0; |
---|
5300 | 5754 | |
---|
5301 | | - if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) { |
---|
5302 | | - const struct ieee80211_tim_ie *tim; |
---|
5303 | | - tim = (void *)(tim_ie + 2); |
---|
5304 | | - ifmgd->dtim_period = tim->dtim_period; |
---|
5305 | | - dtim_count = tim->dtim_count; |
---|
5306 | | - } |
---|
| 5755 | + ieee80211_get_dtim(beacon_ies, &dtim_count, |
---|
| 5756 | + &ifmgd->dtim_period); |
---|
| 5757 | + |
---|
5307 | 5758 | ifmgd->have_beacon = true; |
---|
5308 | 5759 | assoc_data->timeout = jiffies; |
---|
5309 | 5760 | assoc_data->timeout_started = true; |
---|
.. | .. |
---|
5314 | 5765 | bss->device_ts_beacon; |
---|
5315 | 5766 | sdata->vif.bss_conf.sync_dtim_count = dtim_count; |
---|
5316 | 5767 | } |
---|
| 5768 | + |
---|
| 5769 | + elem = cfg80211_find_ext_elem(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION, |
---|
| 5770 | + beacon_ies->data, beacon_ies->len); |
---|
| 5771 | + if (elem && elem->datalen >= 3) |
---|
| 5772 | + sdata->vif.bss_conf.profile_periodicity = elem->data[2]; |
---|
| 5773 | + else |
---|
| 5774 | + sdata->vif.bss_conf.profile_periodicity = 0; |
---|
| 5775 | + |
---|
| 5776 | + elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, |
---|
| 5777 | + beacon_ies->data, beacon_ies->len); |
---|
| 5778 | + if (elem && elem->datalen >= 11 && |
---|
| 5779 | + (elem->data[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) |
---|
| 5780 | + sdata->vif.bss_conf.ema_ap = true; |
---|
| 5781 | + else |
---|
| 5782 | + sdata->vif.bss_conf.ema_ap = false; |
---|
5317 | 5783 | } else { |
---|
5318 | 5784 | assoc_data->timeout = jiffies; |
---|
5319 | 5785 | assoc_data->timeout_started = true; |
---|
.. | .. |
---|
5361 | 5827 | ieee80211_get_reason_code_string(req->reason_code)); |
---|
5362 | 5828 | |
---|
5363 | 5829 | drv_mgd_prepare_tx(sdata->local, sdata, 0); |
---|
5364 | | - ieee80211_send_deauth_disassoc(sdata, req->bssid, |
---|
| 5830 | + ieee80211_send_deauth_disassoc(sdata, req->bssid, req->bssid, |
---|
5365 | 5831 | IEEE80211_STYPE_DEAUTH, |
---|
5366 | 5832 | req->reason_code, tx, |
---|
5367 | 5833 | frame_buf); |
---|
.. | .. |
---|
5381 | 5847 | ieee80211_get_reason_code_string(req->reason_code)); |
---|
5382 | 5848 | |
---|
5383 | 5849 | drv_mgd_prepare_tx(sdata->local, sdata, 0); |
---|
5384 | | - ieee80211_send_deauth_disassoc(sdata, req->bssid, |
---|
| 5850 | + ieee80211_send_deauth_disassoc(sdata, req->bssid, req->bssid, |
---|
5385 | 5851 | IEEE80211_STYPE_DEAUTH, |
---|
5386 | 5852 | req->reason_code, tx, |
---|
5387 | 5853 | frame_buf); |
---|
.. | .. |
---|
5471 | 5937 | ifmgd->teardown_skb = NULL; |
---|
5472 | 5938 | ifmgd->orig_teardown_skb = NULL; |
---|
5473 | 5939 | } |
---|
| 5940 | + kfree(ifmgd->assoc_req_ies); |
---|
| 5941 | + ifmgd->assoc_req_ies = NULL; |
---|
| 5942 | + ifmgd->assoc_req_ies_len = 0; |
---|
5474 | 5943 | spin_unlock_bh(&ifmgd->teardown_lock); |
---|
5475 | 5944 | del_timer_sync(&ifmgd->timer); |
---|
5476 | 5945 | sdata_unlock(sdata); |
---|