summaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorLuca Coelho <luciano.coelho@intel.com>2018-06-09 02:14:44 -0400
committerJohannes Berg <johannes.berg@intel.com>2018-06-18 16:40:32 -0400
commit41cbb0f5a29592874355e4159489eb08337cd50e (patch)
treeee56f9b9754452ae89a6f9b89efc63d2c360a50a /net/mac80211
parentb8042b3da925f390c1482bf9dc0898dc0b3ea7b5 (diff)
mac80211: add support for HE
Add support for HE in mac80211 conforming with P802.11ax_D1.4. Johannes: Fix another bug with the buf_size comparison in agg-rx.c. Signed-off-by: Liad Kaufman <liad.kaufman@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Ido Yariv <idox.yariv@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Makefile1
-rw-r--r--net/mac80211/agg-rx.c10
-rw-r--r--net/mac80211/agg-tx.c19
-rw-r--r--net/mac80211/cfg.c5
-rw-r--r--net/mac80211/he.c55
-rw-r--r--net/mac80211/ieee80211_i.h16
-rw-r--r--net/mac80211/main.c19
-rw-r--r--net/mac80211/mlme.c288
-rw-r--r--net/mac80211/rx.c127
-rw-r--r--net/mac80211/sta_info.c15
-rw-r--r--net/mac80211/sta_info.h20
-rw-r--r--net/mac80211/trace.h2
-rw-r--r--net/mac80211/util.c120
13 files changed, 661 insertions, 36 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index e3589ade62e0..bb707789ef2b 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -12,6 +12,7 @@ mac80211-y := \
12 scan.o offchannel.o \ 12 scan.o offchannel.o \
13 ht.o agg-tx.o agg-rx.o \ 13 ht.o agg-tx.o agg-rx.o \
14 vht.o \ 14 vht.o \
15 he.o \
15 ibss.o \ 16 ibss.o \
16 iface.o \ 17 iface.o \
17 rate.o \ 18 rate.o \
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 3ffd853b483f..6a4f154c99f6 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -245,6 +245,7 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
245 }; 245 };
246 int i, ret = -EOPNOTSUPP; 246 int i, ret = -EOPNOTSUPP;
247 u16 status = WLAN_STATUS_REQUEST_DECLINED; 247 u16 status = WLAN_STATUS_REQUEST_DECLINED;
248 u16 max_buf_size;
248 249
249 if (tid >= IEEE80211_FIRST_TSPEC_TSID) { 250 if (tid >= IEEE80211_FIRST_TSPEC_TSID) {
250 ht_dbg(sta->sdata, 251 ht_dbg(sta->sdata,
@@ -268,13 +269,18 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
268 goto end; 269 goto end;
269 } 270 }
270 271
272 if (sta->sta.he_cap.has_he)
273 max_buf_size = IEEE80211_MAX_AMPDU_BUF;
274 else
275 max_buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
276
271 /* sanity check for incoming parameters: 277 /* sanity check for incoming parameters:
272 * check if configuration can support the BA policy 278 * check if configuration can support the BA policy
273 * and if buffer size does not exceeds max value */ 279 * and if buffer size does not exceeds max value */
274 /* XXX: check own ht delayed BA capability?? */ 280 /* XXX: check own ht delayed BA capability?? */
275 if (((ba_policy != 1) && 281 if (((ba_policy != 1) &&
276 (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) || 282 (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||
277 (buf_size > IEEE80211_MAX_AMPDU_BUF_HT)) { 283 (buf_size > max_buf_size)) {
278 status = WLAN_STATUS_INVALID_QOS_PARAM; 284 status = WLAN_STATUS_INVALID_QOS_PARAM;
279 ht_dbg_ratelimited(sta->sdata, 285 ht_dbg_ratelimited(sta->sdata,
280 "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", 286 "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
@@ -283,7 +289,7 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
283 } 289 }
284 /* determine default buffer size */ 290 /* determine default buffer size */
285 if (buf_size == 0) 291 if (buf_size == 0)
286 buf_size = IEEE80211_MAX_AMPDU_BUF_HT; 292 buf_size = max_buf_size;
287 293
288 /* make sure the size doesn't exceed the maximum supported by the hw */ 294 /* make sure the size doesn't exceed the maximum supported by the hw */
289 if (buf_size > sta->sta.max_rx_aggregation_subframes) 295 if (buf_size > sta->sta.max_rx_aggregation_subframes)
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 86c6bc0432ba..69e831bc317b 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -463,6 +463,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
463 .timeout = 0, 463 .timeout = 0,
464 }; 464 };
465 int ret; 465 int ret;
466 u16 buf_size;
466 467
467 tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 468 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
468 469
@@ -511,11 +512,22 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
511 sta->ampdu_mlme.addba_req_num[tid]++; 512 sta->ampdu_mlme.addba_req_num[tid]++;
512 spin_unlock_bh(&sta->lock); 513 spin_unlock_bh(&sta->lock);
513 514
515 if (sta->sta.he_cap.has_he) {
516 buf_size = local->hw.max_tx_aggregation_subframes;
517 } else {
518 /*
519 * We really should use what the driver told us it will
520 * transmit as the maximum, but certain APs (e.g. the
521 * LinkSys WRT120N with FW v1.0.07 build 002 Jun 18 2012)
522 * will crash when we use a lower number.
523 */
524 buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
525 }
526
514 /* send AddBA request */ 527 /* send AddBA request */
515 ieee80211_send_addba_request(sdata, sta->sta.addr, tid, 528 ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
516 tid_tx->dialog_token, params.ssn, 529 tid_tx->dialog_token, params.ssn,
517 IEEE80211_MAX_AMPDU_BUF_HT, 530 buf_size, tid_tx->timeout);
518 tid_tx->timeout);
519} 531}
520 532
521/* 533/*
@@ -905,8 +917,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
905{ 917{
906 struct tid_ampdu_tx *tid_tx; 918 struct tid_ampdu_tx *tid_tx;
907 struct ieee80211_txq *txq; 919 struct ieee80211_txq *txq;
908 u16 capab, tid; 920 u16 capab, tid, buf_size;
909 u8 buf_size;
910 bool amsdu; 921 bool amsdu;
911 922
912 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); 923 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c4e2f7d2bcb8..02f3672e7b5e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1412,6 +1412,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
1412 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, 1412 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
1413 params->vht_capa, sta); 1413 params->vht_capa, sta);
1414 1414
1415 if (params->he_capa)
1416 ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
1417 (void *)params->he_capa,
1418 params->he_capa_len, sta);
1419
1415 if (params->opmode_notif_used) { 1420 if (params->opmode_notif_used) {
1416 /* returned value is only needed for rc update, but the 1421 /* returned value is only needed for rc update, but the
1417 * rc isn't initialized here yet, so ignore it 1422 * rc isn't initialized here yet, so ignore it
diff --git a/net/mac80211/he.c b/net/mac80211/he.c
new file mode 100644
index 000000000000..769078ed5a12
--- /dev/null
+++ b/net/mac80211/he.c
@@ -0,0 +1,55 @@
1/*
2 * HE handling
3 *
4 * Copyright(c) 2017 Intel Deutschland GmbH
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include "ieee80211_i.h"
12
13void
14ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
15 struct ieee80211_supported_band *sband,
16 const u8 *he_cap_ie, u8 he_cap_len,
17 struct sta_info *sta)
18{
19 struct ieee80211_sta_he_cap *he_cap = &sta->sta.he_cap;
20 struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
21 u8 he_ppe_size;
22 u8 mcs_nss_size;
23 u8 he_total_size;
24
25 memset(he_cap, 0, sizeof(*he_cap));
26
27 if (!he_cap_ie || !ieee80211_get_he_sta_cap(sband))
28 return;
29
30 /* Make sure size is OK */
31 mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem);
32 he_ppe_size =
33 ieee80211_he_ppe_size(he_cap_ie[sizeof(he_cap->he_cap_elem) +
34 mcs_nss_size],
35 he_cap_ie_elem->phy_cap_info);
36 he_total_size = sizeof(he_cap->he_cap_elem) + mcs_nss_size +
37 he_ppe_size;
38 if (he_cap_len < he_total_size)
39 return;
40
41 memcpy(&he_cap->he_cap_elem, he_cap_ie, sizeof(he_cap->he_cap_elem));
42
43 /* HE Tx/Rx HE MCS NSS Support Field */
44 memcpy(&he_cap->he_mcs_nss_supp,
45 &he_cap_ie[sizeof(he_cap->he_cap_elem)], mcs_nss_size);
46
47 /* Check if there are (optional) PPE Thresholds */
48 if (he_cap->he_cap_elem.phy_cap_info[6] &
49 IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
50 memcpy(he_cap->ppe_thres,
51 &he_cap_ie[sizeof(he_cap->he_cap_elem) + mcs_nss_size],
52 he_ppe_size);
53
54 he_cap->has_he = true;
55}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a6c12c104c38..172aeae21ae9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -365,6 +365,7 @@ enum ieee80211_sta_flags {
365 IEEE80211_STA_DISABLE_160MHZ = BIT(13), 365 IEEE80211_STA_DISABLE_160MHZ = BIT(13),
366 IEEE80211_STA_DISABLE_WMM = BIT(14), 366 IEEE80211_STA_DISABLE_WMM = BIT(14),
367 IEEE80211_STA_ENABLE_RRM = BIT(15), 367 IEEE80211_STA_ENABLE_RRM = BIT(15),
368 IEEE80211_STA_DISABLE_HE = BIT(16),
368}; 369};
369 370
370struct ieee80211_mgd_auth_data { 371struct ieee80211_mgd_auth_data {
@@ -1454,6 +1455,10 @@ struct ieee802_11_elems {
1454 const struct ieee80211_vht_cap *vht_cap_elem; 1455 const struct ieee80211_vht_cap *vht_cap_elem;
1455 const struct ieee80211_vht_operation *vht_operation; 1456 const struct ieee80211_vht_operation *vht_operation;
1456 const struct ieee80211_meshconf_ie *mesh_config; 1457 const struct ieee80211_meshconf_ie *mesh_config;
1458 const u8 *he_cap;
1459 const struct ieee80211_he_operation *he_operation;
1460 const struct ieee80211_mu_edca_param_set *mu_edca_param_set;
1461 const u8 *uora_element;
1457 const u8 *mesh_id; 1462 const u8 *mesh_id;
1458 const u8 *peering; 1463 const u8 *peering;
1459 const __le16 *awake_window; 1464 const __le16 *awake_window;
@@ -1483,6 +1488,7 @@ struct ieee802_11_elems {
1483 u8 ext_supp_rates_len; 1488 u8 ext_supp_rates_len;
1484 u8 wmm_info_len; 1489 u8 wmm_info_len;
1485 u8 wmm_param_len; 1490 u8 wmm_param_len;
1491 u8 he_cap_len;
1486 u8 mesh_id_len; 1492 u8 mesh_id_len;
1487 u8 peering_len; 1493 u8 peering_len;
1488 u8 preq_len; 1494 u8 preq_len;
@@ -1825,6 +1831,13 @@ void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
1825enum nl80211_chan_width 1831enum nl80211_chan_width
1826ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta); 1832ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta);
1827 1833
1834/* HE */
1835void
1836ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
1837 struct ieee80211_supported_band *sband,
1838 const u8 *he_cap_ie, u8 he_cap_len,
1839 struct sta_info *sta);
1840
1828/* Spectrum management */ 1841/* Spectrum management */
1829void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, 1842void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
1830 struct ieee80211_mgmt *mgmt, 1843 struct ieee80211_mgmt *mgmt,
@@ -2076,6 +2089,9 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
2076 u32 cap); 2089 u32 cap);
2077u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, 2090u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
2078 const struct cfg80211_chan_def *chandef); 2091 const struct cfg80211_chan_def *chandef);
2092u8 *ieee80211_ie_build_he_cap(u8 *pos,
2093 const struct ieee80211_sta_he_cap *he_cap,
2094 u8 *end);
2079int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, 2095int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
2080 const struct ieee80211_supported_band *sband, 2096 const struct ieee80211_supported_band *sband,
2081 const u8 *srates, int srates_len, u32 *rates); 2097 const u8 *srates, int srates_len, u32 *rates);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 070f77862014..b33faba8cbbe 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -3,6 +3,7 @@
3 * Copyright 2005-2006, Devicescape Software, Inc. 3 * Copyright 2005-2006, Devicescape Software, Inc.
4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
5 * Copyright 2013-2014 Intel Mobile Communications GmbH 5 * Copyright 2013-2014 Intel Mobile Communications GmbH
6 * Copyright (C) 2017 Intel Deutschland GmbH
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -825,7 +826,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
825 int result, i; 826 int result, i;
826 enum nl80211_band band; 827 enum nl80211_band band;
827 int channels, max_bitrates; 828 int channels, max_bitrates;
828 bool supp_ht, supp_vht; 829 bool supp_ht, supp_vht, supp_he;
829 netdev_features_t feature_whitelist; 830 netdev_features_t feature_whitelist;
830 struct cfg80211_chan_def dflt_chandef = {}; 831 struct cfg80211_chan_def dflt_chandef = {};
831 832
@@ -905,6 +906,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
905 max_bitrates = 0; 906 max_bitrates = 0;
906 supp_ht = false; 907 supp_ht = false;
907 supp_vht = false; 908 supp_vht = false;
909 supp_he = false;
908 for (band = 0; band < NUM_NL80211_BANDS; band++) { 910 for (band = 0; band < NUM_NL80211_BANDS; band++) {
909 struct ieee80211_supported_band *sband; 911 struct ieee80211_supported_band *sband;
910 912
@@ -931,6 +933,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
931 supp_ht = supp_ht || sband->ht_cap.ht_supported; 933 supp_ht = supp_ht || sband->ht_cap.ht_supported;
932 supp_vht = supp_vht || sband->vht_cap.vht_supported; 934 supp_vht = supp_vht || sband->vht_cap.vht_supported;
933 935
936 if (!supp_he)
937 supp_he = !!ieee80211_get_he_sta_cap(sband);
938
934 if (!sband->ht_cap.ht_supported) 939 if (!sband->ht_cap.ht_supported)
935 continue; 940 continue;
936 941
@@ -1020,6 +1025,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
1020 local->scan_ies_len += 1025 local->scan_ies_len +=
1021 2 + sizeof(struct ieee80211_vht_cap); 1026 2 + sizeof(struct ieee80211_vht_cap);
1022 1027
1028 /* HE cap element is variable in size - set len to allow max size */
1029 /*
1030 * TODO: 1 is added at the end of the calculation to accommodate for
1031 * the temporary placing of the HE capabilities IE under EXT.
1032 * Remove it once it is placed in the final place.
1033 */
1034 if (supp_he)
1035 local->scan_ies_len +=
1036 2 + sizeof(struct ieee80211_he_cap_elem) +
1037 sizeof(struct ieee80211_he_mcs_nss_supp) +
1038 IEEE80211_HE_PPE_THRES_MAX_LEN + 1;
1039
1023 if (!local->ops->hw_scan) { 1040 if (!local->ops->hw_scan) {
1024 /* For hw_scan, driver needs to set these up. */ 1041 /* For hw_scan, driver needs to set these up. */
1025 local->hw.wiphy->max_scan_ssids = 4; 1042 local->hw.wiphy->max_scan_ssids = 4;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a44e5b4aaeda..0322d78007ad 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -149,6 +149,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
149 struct ieee80211_channel *channel, 149 struct ieee80211_channel *channel,
150 const struct ieee80211_ht_operation *ht_oper, 150 const struct ieee80211_ht_operation *ht_oper,
151 const struct ieee80211_vht_operation *vht_oper, 151 const struct ieee80211_vht_operation *vht_oper,
152 const struct ieee80211_he_operation *he_oper,
152 struct cfg80211_chan_def *chandef, bool tracking) 153 struct cfg80211_chan_def *chandef, bool tracking)
153{ 154{
154 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 155 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -207,7 +208,27 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
207 } 208 }
208 209
209 vht_chandef = *chandef; 210 vht_chandef = *chandef;
210 if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) { 211 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && he_oper &&
212 (le32_to_cpu(he_oper->he_oper_params) &
213 IEEE80211_HE_OPERATION_VHT_OPER_INFO)) {
214 struct ieee80211_vht_operation he_oper_vht_cap;
215
216 /*
217 * Set only first 3 bytes (other 2 aren't used in
218 * ieee80211_chandef_vht_oper() anyway)
219 */
220 memcpy(&he_oper_vht_cap, he_oper->optional, 3);
221 he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0);
222
223 if (!ieee80211_chandef_vht_oper(&he_oper_vht_cap,
224 &vht_chandef)) {
225 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
226 sdata_info(sdata,
227 "HE AP VHT information is invalid, disable HE\n");
228 ret = IEEE80211_STA_DISABLE_HE;
229 goto out;
230 }
231 } else if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
211 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) 232 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
212 sdata_info(sdata, 233 sdata_info(sdata,
213 "AP VHT information is invalid, disable VHT\n"); 234 "AP VHT information is invalid, disable VHT\n");
@@ -300,12 +321,14 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
300 const struct ieee80211_ht_cap *ht_cap, 321 const struct ieee80211_ht_cap *ht_cap,
301 const struct ieee80211_ht_operation *ht_oper, 322 const struct ieee80211_ht_operation *ht_oper,
302 const struct ieee80211_vht_operation *vht_oper, 323 const struct ieee80211_vht_operation *vht_oper,
324 const struct ieee80211_he_operation *he_oper,
303 const u8 *bssid, u32 *changed) 325 const u8 *bssid, u32 *changed)
304{ 326{
305 struct ieee80211_local *local = sdata->local; 327 struct ieee80211_local *local = sdata->local;
306 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 328 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
307 struct ieee80211_supported_band *sband; 329 struct ieee80211_channel *chan = sdata->vif.bss_conf.chandef.chan;
308 struct ieee80211_channel *chan; 330 struct ieee80211_supported_band *sband =
331 local->hw.wiphy->bands[chan->band];
309 struct cfg80211_chan_def chandef; 332 struct cfg80211_chan_def chandef;
310 u16 ht_opmode; 333 u16 ht_opmode;
311 u32 flags; 334 u32 flags;
@@ -320,6 +343,11 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
320 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) 343 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
321 vht_oper = NULL; 344 vht_oper = NULL;
322 345
346 /* don't check HE if we associated as non-HE station */
347 if (ifmgd->flags & IEEE80211_STA_DISABLE_HE ||
348 !ieee80211_get_he_sta_cap(sband))
349 he_oper = NULL;
350
323 if (WARN_ON_ONCE(!sta)) 351 if (WARN_ON_ONCE(!sta))
324 return -EINVAL; 352 return -EINVAL;
325 353
@@ -333,12 +361,9 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
333 sdata->vif.bss_conf.ht_operation_mode = ht_opmode; 361 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
334 } 362 }
335 363
336 chan = sdata->vif.bss_conf.chandef.chan; 364 /* calculate new channel (type) based on HT/VHT/HE operation IEs */
337 sband = local->hw.wiphy->bands[chan->band];
338
339 /* calculate new channel (type) based on HT/VHT operation IEs */
340 flags = ieee80211_determine_chantype(sdata, sband, chan, 365 flags = ieee80211_determine_chantype(sdata, sband, chan,
341 ht_oper, vht_oper, 366 ht_oper, vht_oper, he_oper,
342 &chandef, true); 367 &chandef, true);
343 368
344 /* 369 /*
@@ -582,6 +607,34 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
582 ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); 607 ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
583} 608}
584 609
610/* This function determines HE capability flags for the association
611 * and builds the IE.
612 */
613static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
614 struct sk_buff *skb,
615 struct ieee80211_supported_band *sband)
616{
617 u8 *pos;
618 const struct ieee80211_sta_he_cap *he_cap = NULL;
619 u8 he_cap_size;
620
621 he_cap = ieee80211_get_he_sta_cap(sband);
622 if (!he_cap)
623 return;
624
625 /*
626 * TODO: the 1 added is because this temporarily is under the EXTENSION
627 * IE. Get rid of it when it moves.
628 */
629 he_cap_size =
630 2 + 1 + sizeof(he_cap->he_cap_elem) +
631 ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) +
632 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
633 he_cap->he_cap_elem.phy_cap_info);
634 pos = skb_put(skb, he_cap_size);
635 ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size);
636}
637
585static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) 638static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
586{ 639{
587 struct ieee80211_local *local = sdata->local; 640 struct ieee80211_local *local = sdata->local;
@@ -643,6 +696,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
643 2 + 2 * sband->n_channels + /* supported channels */ 696 2 + 2 * sband->n_channels + /* supported channels */
644 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ 697 2 + sizeof(struct ieee80211_ht_cap) + /* HT */
645 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */ 698 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */
699 2 + 1 + sizeof(struct ieee80211_he_cap_elem) + /* HE */
700 sizeof(struct ieee80211_he_mcs_nss_supp) +
701 IEEE80211_HE_PPE_THRES_MAX_LEN +
646 assoc_data->ie_len + /* extra IEs */ 702 assoc_data->ie_len + /* extra IEs */
647 (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) + 703 (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
648 9, /* WMM */ 704 9, /* WMM */
@@ -827,11 +883,41 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
827 offset = noffset; 883 offset = noffset;
828 } 884 }
829 885
886 /* if present, add any custom IEs that go before HE */
887 if (assoc_data->ie_len) {
888 static const u8 before_he[] = {
889 /*
890 * no need to list the ones split off before VHT
891 * or generated here
892 */
893 WLAN_EID_OPMODE_NOTIF,
894 WLAN_EID_EXTENSION, WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE,
895 /* 11ai elements */
896 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_SESSION,
897 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_PUBLIC_KEY,
898 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_KEY_CONFIRM,
899 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_HLP_CONTAINER,
900 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN,
901 /* TODO: add 11ah/11aj/11ak elements */
902 };
903
904 /* RIC already taken above, so no need to handle here anymore */
905 noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
906 before_he, ARRAY_SIZE(before_he),
907 offset);
908 pos = skb_put(skb, noffset - offset);
909 memcpy(pos, assoc_data->ie + offset, noffset - offset);
910 offset = noffset;
911 }
912
830 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) 913 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
831 ieee80211_add_vht_ie(sdata, skb, sband, 914 ieee80211_add_vht_ie(sdata, skb, sband,
832 &assoc_data->ap_vht_cap); 915 &assoc_data->ap_vht_cap);
833 916
834 /* if present, add any custom non-vendor IEs that go after HT */ 917 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
918 ieee80211_add_he_ie(sdata, skb, sband);
919
920 /* if present, add any custom non-vendor IEs that go after HE */
835 if (assoc_data->ie_len) { 921 if (assoc_data->ie_len) {
836 noffset = ieee80211_ie_split_vendor(assoc_data->ie, 922 noffset = ieee80211_ie_split_vendor(assoc_data->ie,
837 assoc_data->ie_len, 923 assoc_data->ie_len,
@@ -898,6 +984,11 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
898 struct ieee80211_hdr_3addr *nullfunc; 984 struct ieee80211_hdr_3addr *nullfunc;
899 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 985 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
900 986
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
901 skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, 992 skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif,
902 !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP)); 993 !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP));
903 if (!skb) 994 if (!skb)
@@ -929,6 +1020,10 @@ static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
929 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) 1020 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
930 return; 1021 return;
931 1022
1023 /* Don't send NDPs when connected HE */
1024 if (!(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE))
1025 return;
1026
932 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); 1027 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
933 if (!skb) 1028 if (!skb)
934 return; 1029 return;
@@ -1700,9 +1795,11 @@ static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
1700} 1795}
1701 1796
1702/* MLME */ 1797/* MLME */
1703static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, 1798static bool
1704 struct ieee80211_sub_if_data *sdata, 1799ieee80211_sta_wmm_params(struct ieee80211_local *local,
1705 const u8 *wmm_param, size_t wmm_param_len) 1800 struct ieee80211_sub_if_data *sdata,
1801 const u8 *wmm_param, size_t wmm_param_len,
1802 const struct ieee80211_mu_edca_param_set *mu_edca)
1706{ 1803{
1707 struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS]; 1804 struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS];
1708 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1805 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1749,6 +1846,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1749 sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ 1846 sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
1750 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) 1847 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
1751 uapsd = true; 1848 uapsd = true;
1849 params[ac].mu_edca = !!mu_edca;
1850 if (mu_edca)
1851 params[ac].mu_edca_param_rec = mu_edca->ac_bk;
1752 break; 1852 break;
1753 case 2: /* AC_VI */ 1853 case 2: /* AC_VI */
1754 ac = IEEE80211_AC_VI; 1854 ac = IEEE80211_AC_VI;
@@ -1756,6 +1856,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1756 sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ 1856 sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
1757 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) 1857 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
1758 uapsd = true; 1858 uapsd = true;
1859 params[ac].mu_edca = !!mu_edca;
1860 if (mu_edca)
1861 params[ac].mu_edca_param_rec = mu_edca->ac_vi;
1759 break; 1862 break;
1760 case 3: /* AC_VO */ 1863 case 3: /* AC_VO */
1761 ac = IEEE80211_AC_VO; 1864 ac = IEEE80211_AC_VO;
@@ -1763,6 +1866,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1763 sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ 1866 sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
1764 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) 1867 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
1765 uapsd = true; 1868 uapsd = true;
1869 params[ac].mu_edca = !!mu_edca;
1870 if (mu_edca)
1871 params[ac].mu_edca_param_rec = mu_edca->ac_vo;
1766 break; 1872 break;
1767 case 0: /* AC_BE */ 1873 case 0: /* AC_BE */
1768 default: 1874 default:
@@ -1771,6 +1877,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1771 sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ 1877 sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
1772 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) 1878 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
1773 uapsd = true; 1879 uapsd = true;
1880 params[ac].mu_edca = !!mu_edca;
1881 if (mu_edca)
1882 params[ac].mu_edca_param_rec = mu_edca->ac_be;
1774 break; 1883 break;
1775 } 1884 }
1776 1885
@@ -3021,6 +3130,25 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
3021 goto out; 3130 goto out;
3022 } 3131 }
3023 3132
3133 /*
3134 * If AP doesn't support HT, or it doesn't have HE mandatory IEs, mark
3135 * HE as disabled. If on the 5GHz band, make sure it supports VHT.
3136 */
3137 if (ifmgd->flags & IEEE80211_STA_DISABLE_HT ||
3138 (sband->band == NL80211_BAND_5GHZ &&
3139 ifmgd->flags & IEEE80211_STA_DISABLE_VHT) ||
3140 (!elems.he_cap && !elems.he_operation))
3141 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
3142
3143 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
3144 (!elems.he_cap || !elems.he_operation)) {
3145 mutex_unlock(&sdata->local->sta_mtx);
3146 sdata_info(sdata,
3147 "HE AP is missing HE capability/operation\n");
3148 ret = false;
3149 goto out;
3150 }
3151
3024 /* Set up internal HT/VHT capabilities */ 3152 /* Set up internal HT/VHT capabilities */
3025 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) 3153 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
3026 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, 3154 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
@@ -3030,6 +3158,48 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
3030 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, 3158 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
3031 elems.vht_cap_elem, sta); 3159 elems.vht_cap_elem, sta);
3032 3160
3161 if (elems.he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
3162 elems.he_cap) {
3163 ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
3164 elems.he_cap,
3165 elems.he_cap_len,
3166 sta);
3167
3168 bss_conf->he_support = sta->sta.he_cap.has_he;
3169 } else {
3170 bss_conf->he_support = false;
3171 }
3172
3173 if (bss_conf->he_support) {
3174 u32 he_oper_params =
3175 le32_to_cpu(elems.he_operation->he_oper_params);
3176
3177 bss_conf->bss_color = he_oper_params &
3178 IEEE80211_HE_OPERATION_BSS_COLOR_MASK;
3179 bss_conf->htc_trig_based_pkt_ext =
3180 (he_oper_params &
3181 IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK) <<
3182 IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET;
3183 bss_conf->frame_time_rts_th =
3184 (he_oper_params &
3185 IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK) <<
3186 IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET;
3187
3188 bss_conf->multi_sta_back_32bit =
3189 sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
3190 IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP;
3191
3192 bss_conf->ack_enabled =
3193 sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
3194 IEEE80211_HE_MAC_CAP2_ACK_EN;
3195
3196 bss_conf->uora_exists = !!elems.uora_element;
3197 if (elems.uora_element)
3198 bss_conf->uora_ocw_range = elems.uora_element[0];
3199
3200 /* TODO: OPEN: what happens if BSS color disable is set? */
3201 }
3202
3033 /* 3203 /*
3034 * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data 3204 * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
3035 * in their association response, so ignore that data for our own 3205 * in their association response, so ignore that data for our own
@@ -3089,7 +3259,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
3089 if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { 3259 if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
3090 ieee80211_set_wmm_default(sdata, false, false); 3260 ieee80211_set_wmm_default(sdata, false, false);
3091 } else if (!ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, 3261 } else if (!ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
3092 elems.wmm_param_len)) { 3262 elems.wmm_param_len,
3263 elems.mu_edca_param_set)) {
3093 /* still enable QoS since we might have HT/VHT */ 3264 /* still enable QoS since we might have HT/VHT */
3094 ieee80211_set_wmm_default(sdata, false, true); 3265 ieee80211_set_wmm_default(sdata, false, true);
3095 /* set the disable-WMM flag in this case to disable 3266 /* set the disable-WMM flag in this case to disable
@@ -3603,7 +3774,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
3603 3774
3604 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && 3775 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
3605 ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, 3776 ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
3606 elems.wmm_param_len)) 3777 elems.wmm_param_len,
3778 elems.mu_edca_param_set))
3607 changed |= BSS_CHANGED_QOS; 3779 changed |= BSS_CHANGED_QOS;
3608 3780
3609 /* 3781 /*
@@ -3642,7 +3814,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
3642 3814
3643 if (ieee80211_config_bw(sdata, sta, 3815 if (ieee80211_config_bw(sdata, sta,
3644 elems.ht_cap_elem, elems.ht_operation, 3816 elems.ht_cap_elem, elems.ht_operation,
3645 elems.vht_operation, bssid, &changed)) { 3817 elems.vht_operation, elems.he_operation,
3818 bssid, &changed)) {
3646 mutex_unlock(&local->sta_mtx); 3819 mutex_unlock(&local->sta_mtx);
3647 sdata_info(sdata, 3820 sdata_info(sdata,
3648 "failed to follow AP %pM bandwidth change, disconnect\n", 3821 "failed to follow AP %pM bandwidth change, disconnect\n",
@@ -4279,6 +4452,66 @@ static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
4279 return chains; 4452 return chains;
4280} 4453}
4281 4454
4455static bool
4456ieee80211_verify_sta_he_mcs_support(struct ieee80211_supported_band *sband,
4457 const struct ieee80211_he_operation *he_op)
4458{
4459 const struct ieee80211_sta_he_cap *sta_he_cap =
4460 ieee80211_get_he_sta_cap(sband);
4461 u16 ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set);
4462 int i;
4463
4464 if (!sta_he_cap || !he_op)
4465 return false;
4466
4467 /* Need to go over for 80MHz, 160MHz and for 80+80 */
4468 for (i = 0; i < 3; i++) {
4469 const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp =
4470 &sta_he_cap->he_mcs_nss_supp;
4471 u16 sta_mcs_map_rx =
4472 le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]);
4473 u16 sta_mcs_map_tx =
4474 le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]);
4475 u8 nss;
4476 bool verified = true;
4477
4478 /*
4479 * For each band there is a maximum of 8 spatial streams
4480 * possible. Each of the sta_mcs_map_* is a 16-bit struct built
4481 * of 2 bits per NSS (1-8), with the values defined in enum
4482 * ieee80211_he_mcs_support. Need to make sure STA TX and RX
4483 * capabilities aren't less than the AP's minimum requirements
4484 * for this HE BSS per SS.
4485 * It is enough to find one such band that meets the reqs.
4486 */
4487 for (nss = 8; nss > 0; nss--) {
4488 u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3;
4489 u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3;
4490 u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
4491
4492 if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED)
4493 continue;
4494
4495 /*
4496 * Make sure the HE AP doesn't require MCSs that aren't
4497 * supported by the client
4498 */
4499 if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
4500 sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
4501 (ap_val > sta_rx_val) || (ap_val > sta_tx_val)) {
4502 verified = false;
4503 break;
4504 }
4505 }
4506
4507 if (verified)
4508 return true;
4509 }
4510
4511 /* If here, STA doesn't meet AP's HE min requirements */
4512 return false;
4513}
4514
4282static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, 4515static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4283 struct cfg80211_bss *cbss) 4516 struct cfg80211_bss *cbss)
4284{ 4517{
@@ -4287,6 +4520,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4287 const struct ieee80211_ht_cap *ht_cap = NULL; 4520 const struct ieee80211_ht_cap *ht_cap = NULL;
4288 const struct ieee80211_ht_operation *ht_oper = NULL; 4521 const struct ieee80211_ht_operation *ht_oper = NULL;
4289 const struct ieee80211_vht_operation *vht_oper = NULL; 4522 const struct ieee80211_vht_operation *vht_oper = NULL;
4523 const struct ieee80211_he_operation *he_oper = NULL;
4290 struct ieee80211_supported_band *sband; 4524 struct ieee80211_supported_band *sband;
4291 struct cfg80211_chan_def chandef; 4525 struct cfg80211_chan_def chandef;
4292 int ret; 4526 int ret;
@@ -4342,6 +4576,25 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4342 } 4576 }
4343 } 4577 }
4344 4578
4579 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
4580 ieee80211_get_he_sta_cap(sband)) {
4581 const struct cfg80211_bss_ies *ies;
4582 const u8 *he_oper_ie;
4583
4584 ies = rcu_dereference(cbss->ies);
4585 he_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION,
4586 ies->data, ies->len);
4587 if (he_oper_ie &&
4588 he_oper_ie[1] == ieee80211_he_oper_size(&he_oper_ie[3]))
4589 he_oper = (void *)(he_oper_ie + 3);
4590 else
4591 he_oper = NULL;
4592
4593 if (!he_oper ||
4594 !ieee80211_verify_sta_he_mcs_support(sband, he_oper))
4595 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
4596 }
4597
4345 /* Allow VHT if at least one channel on the sband supports 80 MHz */ 4598 /* Allow VHT if at least one channel on the sband supports 80 MHz */
4346 have_80mhz = false; 4599 have_80mhz = false;
4347 for (i = 0; i < sband->n_channels; i++) { 4600 for (i = 0; i < sband->n_channels; i++) {
@@ -4358,7 +4611,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
4358 4611
4359 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, 4612 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
4360 cbss->channel, 4613 cbss->channel,
4361 ht_oper, vht_oper, 4614 ht_oper, vht_oper, he_oper,
4362 &chandef, false); 4615 &chandef, false);
4363 4616
4364 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), 4617 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
@@ -4764,8 +5017,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
4764 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { 5017 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
4765 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 5018 ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
4766 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 5019 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
5020 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
4767 netdev_info(sdata->dev, 5021 netdev_info(sdata->dev,
4768 "disabling HT/VHT due to WEP/TKIP use\n"); 5022 "disabling HE/HT/VHT due to WEP/TKIP use\n");
4769 } 5023 }
4770 } 5024 }
4771 5025
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 756ba176db1e..a16ba568e2a3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -175,6 +175,20 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
175 len += 12; 175 len += 12;
176 } 176 }
177 177
178 if (status->encoding == RX_ENC_HE &&
179 status->flag & RX_FLAG_RADIOTAP_HE) {
180 len = ALIGN(len, 2);
181 len += 12;
182 BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) != 12);
183 }
184
185 if (status->encoding == RX_ENC_HE &&
186 status->flag & RX_FLAG_RADIOTAP_HE_MU) {
187 len = ALIGN(len, 2);
188 len += 12;
189 BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12);
190 }
191
178 if (status->chains) { 192 if (status->chains) {
179 /* antenna and antenna signal fields */ 193 /* antenna and antenna signal fields */
180 len += 2 * hweight8(status->chains); 194 len += 2 * hweight8(status->chains);
@@ -263,6 +277,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
263 int mpdulen, chain; 277 int mpdulen, chain;
264 unsigned long chains = status->chains; 278 unsigned long chains = status->chains;
265 struct ieee80211_vendor_radiotap rtap = {}; 279 struct ieee80211_vendor_radiotap rtap = {};
280 struct ieee80211_radiotap_he he = {};
281 struct ieee80211_radiotap_he_mu he_mu = {};
282
283 if (status->flag & RX_FLAG_RADIOTAP_HE) {
284 he = *(struct ieee80211_radiotap_he *)skb->data;
285 skb_pull(skb, sizeof(he));
286 WARN_ON_ONCE(status->encoding != RX_ENC_HE);
287 }
288
289 if (status->flag & RX_FLAG_RADIOTAP_HE_MU) {
290 he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data;
291 skb_pull(skb, sizeof(he_mu));
292 }
266 293
267 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { 294 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
268 rtap = *(struct ieee80211_vendor_radiotap *)skb->data; 295 rtap = *(struct ieee80211_vendor_radiotap *)skb->data;
@@ -520,6 +547,89 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
520 *pos++ = flags; 547 *pos++ = flags;
521 } 548 }
522 549
550 if (status->encoding == RX_ENC_HE &&
551 status->flag & RX_FLAG_RADIOTAP_HE) {
552#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val))
553
554 if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) {
555 he.data6 |= HE_PREP(DATA6_NSTS,
556 FIELD_GET(RX_ENC_FLAG_STBC_MASK,
557 status->enc_flags));
558 he.data3 |= HE_PREP(DATA3_STBC, 1);
559 } else {
560 he.data6 |= HE_PREP(DATA6_NSTS, status->nss);
561 }
562
563#define CHECK_GI(s) \
564 BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \
565 (int)NL80211_RATE_INFO_HE_GI_##s)
566
567 CHECK_GI(0_8);
568 CHECK_GI(1_6);
569 CHECK_GI(3_2);
570
571 he.data3 |= HE_PREP(DATA3_DATA_MCS, status->rate_idx);
572 he.data3 |= HE_PREP(DATA3_DATA_DCM, status->he_dcm);
573 he.data3 |= HE_PREP(DATA3_CODING,
574 !!(status->enc_flags & RX_ENC_FLAG_LDPC));
575
576 he.data5 |= HE_PREP(DATA5_GI, status->he_gi);
577
578 switch (status->bw) {
579 case RATE_INFO_BW_20:
580 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
581 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ);
582 break;
583 case RATE_INFO_BW_40:
584 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
585 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ);
586 break;
587 case RATE_INFO_BW_80:
588 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
589 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ);
590 break;
591 case RATE_INFO_BW_160:
592 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
593 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ);
594 break;
595 case RATE_INFO_BW_HE_RU:
596#define CHECK_RU_ALLOC(s) \
597 BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \
598 NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4)
599
600 CHECK_RU_ALLOC(26);
601 CHECK_RU_ALLOC(52);
602 CHECK_RU_ALLOC(106);
603 CHECK_RU_ALLOC(242);
604 CHECK_RU_ALLOC(484);
605 CHECK_RU_ALLOC(996);
606 CHECK_RU_ALLOC(2x996);
607
608 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
609 status->he_ru + 4);
610 break;
611 default:
612 WARN_ONCE(1, "Invalid SU BW %d\n", status->bw);
613 }
614
615 /* ensure 2 byte alignment */
616 while ((pos - (u8 *)rthdr) & 1)
617 pos++;
618 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE);
619 memcpy(pos, &he, sizeof(he));
620 pos += sizeof(he);
621 }
622
623 if (status->encoding == RX_ENC_HE &&
624 status->flag & RX_FLAG_RADIOTAP_HE_MU) {
625 /* ensure 2 byte alignment */
626 while ((pos - (u8 *)rthdr) & 1)
627 pos++;
628 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE_MU);
629 memcpy(pos, &he_mu, sizeof(he_mu));
630 pos += sizeof(he_mu);
631 }
632
523 for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { 633 for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
524 *pos++ = status->chain_signal[chain]; 634 *pos++ = status->chain_signal[chain];
525 *pos++ = chain; 635 *pos++ = chain;
@@ -613,6 +723,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
613 rcu_dereference(local->monitor_sdata); 723 rcu_dereference(local->monitor_sdata);
614 bool only_monitor = false; 724 bool only_monitor = false;
615 725
726 if (status->flag & RX_FLAG_RADIOTAP_HE)
727 rtap_space += sizeof(struct ieee80211_radiotap_he);
728
729 if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
730 rtap_space += sizeof(struct ieee80211_radiotap_he_mu);
731
616 if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { 732 if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) {
617 struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; 733 struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data;
618 734
@@ -3386,8 +3502,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
3386 status = IEEE80211_SKB_RXCB((rx->skb)); 3502 status = IEEE80211_SKB_RXCB((rx->skb));
3387 3503
3388 sband = rx->local->hw.wiphy->bands[status->band]; 3504 sband = rx->local->hw.wiphy->bands[status->band];
3389 if (!(status->encoding == RX_ENC_HT) && 3505 if (status->encoding == RX_ENC_LEGACY)
3390 !(status->encoding == RX_ENC_VHT))
3391 rate = &sband->bitrates[status->rate_idx]; 3506 rate = &sband->bitrates[status->rate_idx];
3392 3507
3393 ieee80211_rx_cooked_monitor(rx, rate); 3508 ieee80211_rx_cooked_monitor(rx, rate);
@@ -4386,6 +4501,14 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
4386 status->rate_idx, status->nss)) 4501 status->rate_idx, status->nss))
4387 goto drop; 4502 goto drop;
4388 break; 4503 break;
4504 case RX_ENC_HE:
4505 if (WARN_ONCE(status->rate_idx > 11 ||
4506 !status->nss ||
4507 status->nss > 8,
4508 "Rate marked as an HE rate but data is invalid: MCS: %d, NSS: %d\n",
4509 status->rate_idx, status->nss))
4510 goto drop;
4511 break;
4389 default: 4512 default:
4390 WARN_ON_ONCE(1); 4513 WARN_ON_ONCE(1);
4391 /* fall through */ 4514 /* fall through */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index aa96fddfbfc2..aa8fe771a8db 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1323,6 +1323,11 @@ static void ieee80211_send_null_response(struct sta_info *sta, int tid,
1323 struct ieee80211_tx_info *info; 1323 struct ieee80211_tx_info *info;
1324 struct ieee80211_chanctx_conf *chanctx_conf; 1324 struct ieee80211_chanctx_conf *chanctx_conf;
1325 1325
1326 /* Don't send NDPs when STA is connected HE */
1327 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
1328 !(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE))
1329 return;
1330
1326 if (qos) { 1331 if (qos) {
1327 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | 1332 fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
1328 IEEE80211_STYPE_QOS_NULLFUNC | 1333 IEEE80211_STYPE_QOS_NULLFUNC |
@@ -1968,7 +1973,7 @@ sta_get_last_rx_stats(struct sta_info *sta)
1968 return stats; 1973 return stats;
1969} 1974}
1970 1975
1971static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate, 1976static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,
1972 struct rate_info *rinfo) 1977 struct rate_info *rinfo)
1973{ 1978{
1974 rinfo->bw = STA_STATS_GET(BW, rate); 1979 rinfo->bw = STA_STATS_GET(BW, rate);
@@ -2005,6 +2010,14 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
2005 rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); 2010 rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
2006 break; 2011 break;
2007 } 2012 }
2013 case STA_STATS_RATE_TYPE_HE:
2014 rinfo->flags = RATE_INFO_FLAGS_HE_MCS;
2015 rinfo->mcs = STA_STATS_GET(HE_MCS, rate);
2016 rinfo->nss = STA_STATS_GET(HE_NSS, rate);
2017 rinfo->he_gi = STA_STATS_GET(HE_GI, rate);
2018 rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate);
2019 rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate);
2020 break;
2008 } 2021 }
2009} 2022}
2010 2023
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 81b35f623792..9a04327d71d1 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -170,7 +170,7 @@ struct tid_ampdu_tx {
170 u8 dialog_token; 170 u8 dialog_token;
171 u8 stop_initiator; 171 u8 stop_initiator;
172 bool tx_stop; 172 bool tx_stop;
173 u8 buf_size; 173 u16 buf_size;
174 174
175 u16 failed_bar_ssn; 175 u16 failed_bar_ssn;
176 bool bar_pending; 176 bool bar_pending;
@@ -405,7 +405,7 @@ struct ieee80211_sta_rx_stats {
405 int last_signal; 405 int last_signal;
406 u8 chains; 406 u8 chains;
407 s8 chain_signal_last[IEEE80211_MAX_CHAINS]; 407 s8 chain_signal_last[IEEE80211_MAX_CHAINS];
408 u16 last_rate; 408 u32 last_rate;
409 struct u64_stats_sync syncp; 409 struct u64_stats_sync syncp;
410 u64 bytes; 410 u64 bytes;
411 u64 msdu[IEEE80211_NUM_TIDS + 1]; 411 u64 msdu[IEEE80211_NUM_TIDS + 1];
@@ -764,6 +764,7 @@ enum sta_stats_type {
764 STA_STATS_RATE_TYPE_LEGACY, 764 STA_STATS_RATE_TYPE_LEGACY,
765 STA_STATS_RATE_TYPE_HT, 765 STA_STATS_RATE_TYPE_HT,
766 STA_STATS_RATE_TYPE_VHT, 766 STA_STATS_RATE_TYPE_VHT,
767 STA_STATS_RATE_TYPE_HE,
767}; 768};
768 769
769#define STA_STATS_FIELD_HT_MCS GENMASK( 7, 0) 770#define STA_STATS_FIELD_HT_MCS GENMASK( 7, 0)
@@ -771,9 +772,14 @@ enum sta_stats_type {
771#define STA_STATS_FIELD_LEGACY_BAND GENMASK( 7, 4) 772#define STA_STATS_FIELD_LEGACY_BAND GENMASK( 7, 4)
772#define STA_STATS_FIELD_VHT_MCS GENMASK( 3, 0) 773#define STA_STATS_FIELD_VHT_MCS GENMASK( 3, 0)
773#define STA_STATS_FIELD_VHT_NSS GENMASK( 7, 4) 774#define STA_STATS_FIELD_VHT_NSS GENMASK( 7, 4)
775#define STA_STATS_FIELD_HE_MCS GENMASK( 3, 0)
776#define STA_STATS_FIELD_HE_NSS GENMASK( 7, 4)
774#define STA_STATS_FIELD_BW GENMASK(11, 8) 777#define STA_STATS_FIELD_BW GENMASK(11, 8)
775#define STA_STATS_FIELD_SGI GENMASK(12, 12) 778#define STA_STATS_FIELD_SGI GENMASK(12, 12)
776#define STA_STATS_FIELD_TYPE GENMASK(15, 13) 779#define STA_STATS_FIELD_TYPE GENMASK(15, 13)
780#define STA_STATS_FIELD_HE_RU GENMASK(18, 16)
781#define STA_STATS_FIELD_HE_GI GENMASK(20, 19)
782#define STA_STATS_FIELD_HE_DCM GENMASK(21, 21)
777 783
778#define STA_STATS_FIELD(_n, _v) FIELD_PREP(STA_STATS_FIELD_ ## _n, _v) 784#define STA_STATS_FIELD(_n, _v) FIELD_PREP(STA_STATS_FIELD_ ## _n, _v)
779#define STA_STATS_GET(_n, _v) FIELD_GET(STA_STATS_FIELD_ ## _n, _v) 785#define STA_STATS_GET(_n, _v) FIELD_GET(STA_STATS_FIELD_ ## _n, _v)
@@ -782,7 +788,7 @@ enum sta_stats_type {
782 788
783static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s) 789static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
784{ 790{
785 u16 r; 791 u32 r;
786 792
787 r = STA_STATS_FIELD(BW, s->bw); 793 r = STA_STATS_FIELD(BW, s->bw);
788 794
@@ -804,6 +810,14 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
804 r |= STA_STATS_FIELD(LEGACY_BAND, s->band); 810 r |= STA_STATS_FIELD(LEGACY_BAND, s->band);
805 r |= STA_STATS_FIELD(LEGACY_IDX, s->rate_idx); 811 r |= STA_STATS_FIELD(LEGACY_IDX, s->rate_idx);
806 break; 812 break;
813 case RX_ENC_HE:
814 r |= STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_HE);
815 r |= STA_STATS_FIELD(HE_NSS, s->nss);
816 r |= STA_STATS_FIELD(HE_MCS, s->rate_idx);
817 r |= STA_STATS_FIELD(HE_GI, s->he_gi);
818 r |= STA_STATS_FIELD(HE_RU, s->he_ru);
819 r |= STA_STATS_FIELD(HE_DCM, s->he_dcm);
820 break;
807 default: 821 default:
808 WARN_ON(1); 822 WARN_ON(1);
809 return STA_STATS_RATE_INVALID; 823 return STA_STATS_RATE_INVALID;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 80a7edf8d314..0ab69a1964f8 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -92,7 +92,7 @@
92 STA_ENTRY \ 92 STA_ENTRY \
93 __field(u16, tid) \ 93 __field(u16, tid) \
94 __field(u16, ssn) \ 94 __field(u16, ssn) \
95 __field(u8, buf_size) \ 95 __field(u16, buf_size) \
96 __field(bool, amsdu) \ 96 __field(bool, amsdu) \
97 __field(u16, timeout) \ 97 __field(u16, timeout) \
98 __field(u16, action) 98 __field(u16, action)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index b744b10465c3..c77c84325348 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1095,6 +1095,21 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
1095 if (elen >= sizeof(*elems->max_idle_period_ie)) 1095 if (elen >= sizeof(*elems->max_idle_period_ie))
1096 elems->max_idle_period_ie = (void *)pos; 1096 elems->max_idle_period_ie = (void *)pos;
1097 break; 1097 break;
1098 case WLAN_EID_EXTENSION:
1099 if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
1100 elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
1101 elems->mu_edca_param_set = (void *)&pos[1];
1102 } else if (pos[0] == WLAN_EID_EXT_HE_CAPABILITY) {
1103 elems->he_cap = (void *)&pos[1];
1104 elems->he_cap_len = elen - 1;
1105 } else if (pos[0] == WLAN_EID_EXT_HE_OPERATION &&
1106 elen >= sizeof(*elems->he_operation) &&
1107 elen >= ieee80211_he_oper_size(&pos[1])) {
1108 elems->he_operation = (void *)&pos[1];
1109 } else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) {
1110 elems->uora_element = (void *)&pos[1];
1111 }
1112 break;
1098 default: 1113 default:
1099 break; 1114 break;
1100 } 1115 }
@@ -1356,6 +1371,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
1356 size_t *offset, u32 flags) 1371 size_t *offset, u32 flags)
1357{ 1372{
1358 struct ieee80211_supported_band *sband; 1373 struct ieee80211_supported_band *sband;
1374 const struct ieee80211_sta_he_cap *he_cap;
1359 u8 *pos = buffer, *end = buffer + buffer_len; 1375 u8 *pos = buffer, *end = buffer + buffer_len;
1360 size_t noffset; 1376 size_t noffset;
1361 int supp_rates_len, i; 1377 int supp_rates_len, i;
@@ -1463,11 +1479,6 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
1463 sband->ht_cap.cap); 1479 sband->ht_cap.cap);
1464 } 1480 }
1465 1481
1466 /*
1467 * If adding more here, adjust code in main.c
1468 * that calculates local->scan_ies_len.
1469 */
1470
1471 /* insert custom IEs that go before VHT */ 1482 /* insert custom IEs that go before VHT */
1472 if (ie && ie_len) { 1483 if (ie && ie_len) {
1473 static const u8 before_vht[] = { 1484 static const u8 before_vht[] = {
@@ -1510,6 +1521,39 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
1510 sband->vht_cap.cap); 1521 sband->vht_cap.cap);
1511 } 1522 }
1512 1523
1524 /* insert custom IEs that go before HE */
1525 if (ie && ie_len) {
1526 static const u8 before_he[] = {
1527 /*
1528 * no need to list the ones split off before VHT
1529 * or generated here
1530 */
1531 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_REQ_PARAMS,
1532 WLAN_EID_AP_CSN,
1533 /* TODO: add 11ah/11aj/11ak elements */
1534 };
1535 noffset = ieee80211_ie_split(ie, ie_len,
1536 before_he, ARRAY_SIZE(before_he),
1537 *offset);
1538 if (end - pos < noffset - *offset)
1539 goto out_err;
1540 memcpy(pos, ie + *offset, noffset - *offset);
1541 pos += noffset - *offset;
1542 *offset = noffset;
1543 }
1544
1545 he_cap = ieee80211_get_he_sta_cap(sband);
1546 if (he_cap) {
1547 pos = ieee80211_ie_build_he_cap(pos, he_cap, end);
1548 if (!pos)
1549 goto out_err;
1550 }
1551
1552 /*
1553 * If adding more here, adjust code in main.c
1554 * that calculates local->scan_ies_len.
1555 */
1556
1513 return pos - buffer; 1557 return pos - buffer;
1514 out_err: 1558 out_err:
1515 WARN_ONCE(1, "not enough space for preq IEs\n"); 1559 WARN_ONCE(1, "not enough space for preq IEs\n");
@@ -2396,6 +2440,72 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
2396 return pos; 2440 return pos;
2397} 2441}
2398 2442
2443u8 *ieee80211_ie_build_he_cap(u8 *pos,
2444 const struct ieee80211_sta_he_cap *he_cap,
2445 u8 *end)
2446{
2447 u8 n;
2448 u8 ie_len;
2449 u8 *orig_pos = pos;
2450
2451 /* Make sure we have place for the IE */
2452 /*
2453 * TODO: the 1 added is because this temporarily is under the EXTENSION
2454 * IE. Get rid of it when it moves.
2455 */
2456 if (!he_cap)
2457 return orig_pos;
2458
2459 n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem);
2460 ie_len = 2 + 1 +
2461 sizeof(he_cap->he_cap_elem) + n +
2462 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
2463 he_cap->he_cap_elem.phy_cap_info);
2464
2465 if ((end - pos) < ie_len)
2466 return orig_pos;
2467
2468 *pos++ = WLAN_EID_EXTENSION;
2469 pos++; /* We'll set the size later below */
2470 *pos++ = WLAN_EID_EXT_HE_CAPABILITY;
2471
2472 /* Fixed data */
2473 memcpy(pos, &he_cap->he_cap_elem, sizeof(he_cap->he_cap_elem));
2474 pos += sizeof(he_cap->he_cap_elem);
2475
2476 memcpy(pos, &he_cap->he_mcs_nss_supp, n);
2477 pos += n;
2478
2479 /* Check if PPE Threshold should be present */
2480 if ((he_cap->he_cap_elem.phy_cap_info[6] &
2481 IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0)
2482 goto end;
2483
2484 /*
2485 * Calculate how many PPET16/PPET8 pairs are to come. Algorithm:
2486 * (NSS_M1 + 1) x (num of 1 bits in RU_INDEX_BITMASK)
2487 */
2488 n = hweight8(he_cap->ppe_thres[0] &
2489 IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
2490 n *= (1 + ((he_cap->ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) >>
2491 IEEE80211_PPE_THRES_NSS_POS));
2492
2493 /*
2494 * Each pair is 6 bits, and we need to add the 7 "header" bits to the
2495 * total size.
2496 */
2497 n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7;
2498 n = DIV_ROUND_UP(n, 8);
2499
2500 /* Copy PPE Thresholds */
2501 memcpy(pos, &he_cap->ppe_thres, n);
2502 pos += n;
2503
2504end:
2505 orig_pos[1] = (pos - orig_pos) - 2;
2506 return pos;
2507}
2508
2399u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, 2509u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
2400 const struct cfg80211_chan_def *chandef, 2510 const struct cfg80211_chan_def *chandef,
2401 u16 prot_mode, bool rifs_mode) 2511 u16 prot_mode, bool rifs_mode)