1 // SPDX-License-Identifier: GPL-2.0-only
5 * Portions of this file
6 * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
7 * Copyright (C) 2018 - 2020 Intel Corporation
10 #include <linux/ieee80211.h>
11 #include <linux/export.h>
12 #include <net/mac80211.h>
13 #include "ieee80211_i.h"
17 static void __check_vhtcap_disable(struct ieee80211_sub_if_data
*sdata
,
18 struct ieee80211_sta_vht_cap
*vht_cap
,
21 __le32 le_flag
= cpu_to_le32(flag
);
23 if (sdata
->u
.mgd
.vht_capa_mask
.vht_cap_info
& le_flag
&&
24 !(sdata
->u
.mgd
.vht_capa
.vht_cap_info
& le_flag
))
25 vht_cap
->cap
&= ~flag
;
28 void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data
*sdata
,
29 struct ieee80211_sta_vht_cap
*vht_cap
)
32 u16 rxmcs_mask
, rxmcs_cap
, rxmcs_n
, txmcs_mask
, txmcs_cap
, txmcs_n
;
34 if (!vht_cap
->vht_supported
)
37 if (sdata
->vif
.type
!= NL80211_IFTYPE_STATION
)
40 __check_vhtcap_disable(sdata
, vht_cap
,
41 IEEE80211_VHT_CAP_RXLDPC
);
42 __check_vhtcap_disable(sdata
, vht_cap
,
43 IEEE80211_VHT_CAP_SHORT_GI_80
);
44 __check_vhtcap_disable(sdata
, vht_cap
,
45 IEEE80211_VHT_CAP_SHORT_GI_160
);
46 __check_vhtcap_disable(sdata
, vht_cap
,
47 IEEE80211_VHT_CAP_TXSTBC
);
48 __check_vhtcap_disable(sdata
, vht_cap
,
49 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE
);
50 __check_vhtcap_disable(sdata
, vht_cap
,
51 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
);
52 __check_vhtcap_disable(sdata
, vht_cap
,
53 IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN
);
54 __check_vhtcap_disable(sdata
, vht_cap
,
55 IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN
);
57 /* Allow user to decrease AMPDU length exponent */
58 if (sdata
->u
.mgd
.vht_capa_mask
.vht_cap_info
&
59 cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK
)) {
62 n
= le32_to_cpu(sdata
->u
.mgd
.vht_capa
.vht_cap_info
) &
63 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK
;
64 n
>>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT
;
65 cap
= vht_cap
->cap
& IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK
;
66 cap
>>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT
;
70 ~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK
;
72 n
<< IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT
;
76 /* Allow the user to decrease MCSes */
78 le16_to_cpu(sdata
->u
.mgd
.vht_capa_mask
.supp_mcs
.rx_mcs_map
);
79 rxmcs_n
= le16_to_cpu(sdata
->u
.mgd
.vht_capa
.supp_mcs
.rx_mcs_map
);
80 rxmcs_n
&= rxmcs_mask
;
81 rxmcs_cap
= le16_to_cpu(vht_cap
->vht_mcs
.rx_mcs_map
);
84 le16_to_cpu(sdata
->u
.mgd
.vht_capa_mask
.supp_mcs
.tx_mcs_map
);
85 txmcs_n
= le16_to_cpu(sdata
->u
.mgd
.vht_capa
.supp_mcs
.tx_mcs_map
);
86 txmcs_n
&= txmcs_mask
;
87 txmcs_cap
= le16_to_cpu(vht_cap
->vht_mcs
.tx_mcs_map
);
88 for (i
= 0; i
< 8; i
++) {
91 m
= (rxmcs_mask
>> 2*i
) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
92 n
= (rxmcs_n
>> 2*i
) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
93 c
= (rxmcs_cap
>> 2*i
) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
95 if (m
&& ((c
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
&& n
< c
) ||
96 n
== IEEE80211_VHT_MCS_NOT_SUPPORTED
)) {
97 rxmcs_cap
&= ~(3 << 2*i
);
98 rxmcs_cap
|= (rxmcs_n
& (3 << 2*i
));
101 m
= (txmcs_mask
>> 2*i
) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
102 n
= (txmcs_n
>> 2*i
) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
103 c
= (txmcs_cap
>> 2*i
) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
105 if (m
&& ((c
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
&& n
< c
) ||
106 n
== IEEE80211_VHT_MCS_NOT_SUPPORTED
)) {
107 txmcs_cap
&= ~(3 << 2*i
);
108 txmcs_cap
|= (txmcs_n
& (3 << 2*i
));
111 vht_cap
->vht_mcs
.rx_mcs_map
= cpu_to_le16(rxmcs_cap
);
112 vht_cap
->vht_mcs
.tx_mcs_map
= cpu_to_le16(txmcs_cap
);
116 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data
*sdata
,
117 struct ieee80211_supported_band
*sband
,
118 const struct ieee80211_vht_cap
*vht_cap_ie
,
119 struct sta_info
*sta
)
121 struct ieee80211_sta_vht_cap
*vht_cap
= &sta
->sta
.vht_cap
;
122 struct ieee80211_sta_vht_cap own_cap
;
126 memset(vht_cap
, 0, sizeof(*vht_cap
));
128 if (!sta
->sta
.ht_cap
.ht_supported
)
131 if (!vht_cap_ie
|| !sband
->vht_cap
.vht_supported
)
134 /* Allow VHT if at least one channel on the sband supports 80 MHz */
136 for (i
= 0; i
< sband
->n_channels
; i
++) {
137 if (sband
->channels
[i
].flags
& (IEEE80211_CHAN_DISABLED
|
138 IEEE80211_CHAN_NO_80MHZ
))
149 * A VHT STA must support 40 MHz, but if we verify that here
150 * then we break a few things - some APs (e.g. Netgear R6300v2
151 * and others based on the BCM4360 chipset) will unset this
152 * capability bit when operating in 20 MHz.
155 vht_cap
->vht_supported
= true;
157 own_cap
= sband
->vht_cap
;
159 * If user has specified capability overrides, take care
160 * of that if the station we're setting up is the AP that
161 * we advertised a restricted capability set to. Override
162 * our own capabilities and then use those below.
164 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
&&
165 !test_sta_flag(sta
, WLAN_STA_TDLS_PEER
))
166 ieee80211_apply_vhtcap_overrides(sdata
, &own_cap
);
168 /* take some capabilities as-is */
169 cap_info
= le32_to_cpu(vht_cap_ie
->vht_cap_info
);
170 vht_cap
->cap
= cap_info
;
171 vht_cap
->cap
&= IEEE80211_VHT_CAP_RXLDPC
|
172 IEEE80211_VHT_CAP_VHT_TXOP_PS
|
173 IEEE80211_VHT_CAP_HTC_VHT
|
174 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK
|
175 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB
|
176 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB
|
177 IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN
|
178 IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN
;
180 vht_cap
->cap
|= min_t(u32
, cap_info
& IEEE80211_VHT_CAP_MAX_MPDU_MASK
,
181 own_cap
.cap
& IEEE80211_VHT_CAP_MAX_MPDU_MASK
);
183 /* and some based on our own capabilities */
184 switch (own_cap
.cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
) {
185 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
:
186 vht_cap
->cap
|= cap_info
&
187 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
;
189 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
:
190 vht_cap
->cap
|= cap_info
&
191 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
198 /* symmetric capabilities */
199 vht_cap
->cap
|= cap_info
& own_cap
.cap
&
200 (IEEE80211_VHT_CAP_SHORT_GI_80
|
201 IEEE80211_VHT_CAP_SHORT_GI_160
);
204 if (own_cap
.cap
& IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
)
205 vht_cap
->cap
|= cap_info
&
206 (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE
|
207 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK
);
209 if (own_cap
.cap
& IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE
)
210 vht_cap
->cap
|= cap_info
&
211 (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
|
212 IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK
);
214 if (own_cap
.cap
& IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE
)
215 vht_cap
->cap
|= cap_info
&
216 IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE
;
218 if (own_cap
.cap
& IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE
)
219 vht_cap
->cap
|= cap_info
&
220 IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE
;
222 if (own_cap
.cap
& IEEE80211_VHT_CAP_TXSTBC
)
223 vht_cap
->cap
|= cap_info
& IEEE80211_VHT_CAP_RXSTBC_MASK
;
225 if (own_cap
.cap
& IEEE80211_VHT_CAP_RXSTBC_MASK
)
226 vht_cap
->cap
|= cap_info
& IEEE80211_VHT_CAP_TXSTBC
;
228 /* Copy peer MCS info, the driver might need them. */
229 memcpy(&vht_cap
->vht_mcs
, &vht_cap_ie
->supp_mcs
,
230 sizeof(struct ieee80211_vht_mcs_info
));
232 /* copy EXT_NSS_BW Support value or remove the capability */
233 if (ieee80211_hw_check(&sdata
->local
->hw
, SUPPORTS_VHT_EXT_NSS_BW
))
234 vht_cap
->cap
|= (cap_info
& IEEE80211_VHT_CAP_EXT_NSS_BW_MASK
);
236 vht_cap
->vht_mcs
.tx_highest
&=
237 ~cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE
);
239 /* but also restrict MCSes */
240 for (i
= 0; i
< 8; i
++) {
241 u16 own_rx
, own_tx
, peer_rx
, peer_tx
;
243 own_rx
= le16_to_cpu(own_cap
.vht_mcs
.rx_mcs_map
);
244 own_rx
= (own_rx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
246 own_tx
= le16_to_cpu(own_cap
.vht_mcs
.tx_mcs_map
);
247 own_tx
= (own_tx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
249 peer_rx
= le16_to_cpu(vht_cap
->vht_mcs
.rx_mcs_map
);
250 peer_rx
= (peer_rx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
252 peer_tx
= le16_to_cpu(vht_cap
->vht_mcs
.tx_mcs_map
);
253 peer_tx
= (peer_tx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
255 if (peer_tx
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
256 if (own_rx
== IEEE80211_VHT_MCS_NOT_SUPPORTED
)
257 peer_tx
= IEEE80211_VHT_MCS_NOT_SUPPORTED
;
258 else if (own_rx
< peer_tx
)
262 if (peer_rx
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
263 if (own_tx
== IEEE80211_VHT_MCS_NOT_SUPPORTED
)
264 peer_rx
= IEEE80211_VHT_MCS_NOT_SUPPORTED
;
265 else if (own_tx
< peer_rx
)
269 vht_cap
->vht_mcs
.rx_mcs_map
&=
270 ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED
<< i
* 2);
271 vht_cap
->vht_mcs
.rx_mcs_map
|= cpu_to_le16(peer_rx
<< i
* 2);
273 vht_cap
->vht_mcs
.tx_mcs_map
&=
274 ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED
<< i
* 2);
275 vht_cap
->vht_mcs
.tx_mcs_map
|= cpu_to_le16(peer_tx
<< i
* 2);
279 * This is a workaround for VHT-enabled STAs which break the spec
280 * and have the VHT-MCS Rx map filled in with value 3 for all eight
281 * spacial streams, an example is AR9462.
283 * As per spec, in section 22.1.1 Introduction to the VHT PHY
284 * A VHT STA shall support at least single spactial stream VHT-MCSs
285 * 0 to 7 (transmit and receive) in all supported channel widths.
287 if (vht_cap
->vht_mcs
.rx_mcs_map
== cpu_to_le16(0xFFFF)) {
288 vht_cap
->vht_supported
= false;
289 sdata_info(sdata
, "Ignoring VHT IE from %pM due to invalid rx_mcs_map\n",
294 /* finally set up the bandwidth */
295 switch (vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
) {
296 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
:
297 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
:
298 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
301 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_80
;
303 if (!(vht_cap
->vht_mcs
.tx_highest
&
304 cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE
)))
308 * If this is non-zero, then it does support 160 MHz after all,
309 * in one form or the other. We don't distinguish here (or even
310 * above) between 160 and 80+80 yet.
312 if (cap_info
& IEEE80211_VHT_CAP_EXT_NSS_BW_MASK
)
313 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
316 sta
->sta
.bandwidth
= ieee80211_sta_cur_vht_bw(sta
);
318 switch (vht_cap
->cap
& IEEE80211_VHT_CAP_MAX_MPDU_MASK
) {
319 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454
:
320 sta
->sta
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_11454
;
322 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991
:
323 sta
->sta
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_7991
;
325 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895
:
327 sta
->sta
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_3895
;
332 /* FIXME: move this to some better location - parses HE now */
333 enum ieee80211_sta_rx_bandwidth
ieee80211_sta_cap_rx_bw(struct sta_info
*sta
)
335 struct ieee80211_sta_vht_cap
*vht_cap
= &sta
->sta
.vht_cap
;
336 struct ieee80211_sta_he_cap
*he_cap
= &sta
->sta
.he_cap
;
339 if (he_cap
->has_he
) {
340 u8 info
= he_cap
->he_cap_elem
.phy_cap_info
[0];
342 if (sta
->sdata
->vif
.bss_conf
.chandef
.chan
->band
==
344 if (info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G
)
345 return IEEE80211_STA_RX_BW_40
;
347 return IEEE80211_STA_RX_BW_20
;
350 if (info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
||
351 info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
)
352 return IEEE80211_STA_RX_BW_160
;
353 else if (info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G
)
354 return IEEE80211_STA_RX_BW_80
;
356 return IEEE80211_STA_RX_BW_20
;
359 if (!vht_cap
->vht_supported
)
360 return sta
->sta
.ht_cap
.cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
?
361 IEEE80211_STA_RX_BW_40
:
362 IEEE80211_STA_RX_BW_20
;
364 cap_width
= vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
366 if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
||
367 cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
)
368 return IEEE80211_STA_RX_BW_160
;
371 * If this is non-zero, then it does support 160 MHz after all,
372 * in one form or the other. We don't distinguish here (or even
373 * above) between 160 and 80+80 yet.
375 if (vht_cap
->cap
& IEEE80211_VHT_CAP_EXT_NSS_BW_MASK
)
376 return IEEE80211_STA_RX_BW_160
;
378 return IEEE80211_STA_RX_BW_80
;
381 enum nl80211_chan_width
ieee80211_sta_cap_chan_bw(struct sta_info
*sta
)
383 struct ieee80211_sta_vht_cap
*vht_cap
= &sta
->sta
.vht_cap
;
386 if (!vht_cap
->vht_supported
) {
387 if (!sta
->sta
.ht_cap
.ht_supported
)
388 return NL80211_CHAN_WIDTH_20_NOHT
;
390 return sta
->sta
.ht_cap
.cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
?
391 NL80211_CHAN_WIDTH_40
: NL80211_CHAN_WIDTH_20
;
394 cap_width
= vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
396 if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
)
397 return NL80211_CHAN_WIDTH_160
;
398 else if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
)
399 return NL80211_CHAN_WIDTH_80P80
;
401 return NL80211_CHAN_WIDTH_80
;
404 enum nl80211_chan_width
405 ieee80211_sta_rx_bw_to_chan_width(struct sta_info
*sta
)
407 enum ieee80211_sta_rx_bandwidth cur_bw
= sta
->sta
.bandwidth
;
408 struct ieee80211_sta_vht_cap
*vht_cap
= &sta
->sta
.vht_cap
;
412 case IEEE80211_STA_RX_BW_20
:
413 if (!sta
->sta
.ht_cap
.ht_supported
)
414 return NL80211_CHAN_WIDTH_20_NOHT
;
416 return NL80211_CHAN_WIDTH_20
;
417 case IEEE80211_STA_RX_BW_40
:
418 return NL80211_CHAN_WIDTH_40
;
419 case IEEE80211_STA_RX_BW_80
:
420 return NL80211_CHAN_WIDTH_80
;
421 case IEEE80211_STA_RX_BW_160
:
423 vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
425 if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
)
426 return NL80211_CHAN_WIDTH_160
;
428 return NL80211_CHAN_WIDTH_80P80
;
430 return NL80211_CHAN_WIDTH_20
;
434 enum ieee80211_sta_rx_bandwidth
435 ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width
)
438 case NL80211_CHAN_WIDTH_20_NOHT
:
439 case NL80211_CHAN_WIDTH_20
:
440 return IEEE80211_STA_RX_BW_20
;
441 case NL80211_CHAN_WIDTH_40
:
442 return IEEE80211_STA_RX_BW_40
;
443 case NL80211_CHAN_WIDTH_80
:
444 return IEEE80211_STA_RX_BW_80
;
445 case NL80211_CHAN_WIDTH_160
:
446 case NL80211_CHAN_WIDTH_80P80
:
447 return IEEE80211_STA_RX_BW_160
;
450 return IEEE80211_STA_RX_BW_20
;
454 /* FIXME: rename/move - this deals with everything not just VHT */
455 enum ieee80211_sta_rx_bandwidth
ieee80211_sta_cur_vht_bw(struct sta_info
*sta
)
457 struct ieee80211_sub_if_data
*sdata
= sta
->sdata
;
458 enum ieee80211_sta_rx_bandwidth bw
;
459 enum nl80211_chan_width bss_width
= sdata
->vif
.bss_conf
.chandef
.width
;
461 bw
= ieee80211_sta_cap_rx_bw(sta
);
462 bw
= min(bw
, sta
->cur_max_bandwidth
);
464 /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of
465 * IEEE80211-2016 specification makes higher bandwidth operation
466 * possible on the TDLS link if the peers have wider bandwidth
469 * However, in this case, and only if the TDLS peer is authorized,
470 * limit to the tdls_chandef so that the configuration here isn't
471 * wider than what's actually requested on the channel context.
473 if (test_sta_flag(sta
, WLAN_STA_TDLS_PEER
) &&
474 test_sta_flag(sta
, WLAN_STA_TDLS_WIDER_BW
) &&
475 test_sta_flag(sta
, WLAN_STA_AUTHORIZED
) &&
476 sta
->tdls_chandef
.chan
)
477 bw
= min(bw
, ieee80211_chan_width_to_rx_bw(sta
->tdls_chandef
.width
));
479 bw
= min(bw
, ieee80211_chan_width_to_rx_bw(bss_width
));
484 void ieee80211_sta_set_rx_nss(struct sta_info
*sta
)
486 u8 ht_rx_nss
= 0, vht_rx_nss
= 0, he_rx_nss
= 0, rx_nss
;
488 /* if we received a notification already don't overwrite it */
492 if (sta
->sta
.he_cap
.has_he
) {
494 u8 rx_mcs_80
= 0, rx_mcs_160
= 0;
495 const struct ieee80211_sta_he_cap
*he_cap
= &sta
->sta
.he_cap
;
497 le16_to_cpu(he_cap
->he_mcs_nss_supp
.rx_mcs_160
);
498 u16 mcs_80_map
= le16_to_cpu(he_cap
->he_mcs_nss_supp
.rx_mcs_80
);
500 for (i
= 7; i
>= 0; i
--) {
501 u8 mcs_160
= (mcs_160_map
>> (2 * i
)) & 3;
503 if (mcs_160
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
508 for (i
= 7; i
>= 0; i
--) {
509 u8 mcs_80
= (mcs_80_map
>> (2 * i
)) & 3;
511 if (mcs_80
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
517 he_rx_nss
= min(rx_mcs_80
, rx_mcs_160
);
520 if (sta
->sta
.ht_cap
.ht_supported
) {
521 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[0])
523 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[1])
525 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[2])
527 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[3])
529 /* FIXME: consider rx_highest? */
532 if (sta
->sta
.vht_cap
.vht_supported
) {
536 rx_mcs_map
= le16_to_cpu(sta
->sta
.vht_cap
.vht_mcs
.rx_mcs_map
);
538 for (i
= 7; i
>= 0; i
--) {
539 u8 mcs
= (rx_mcs_map
>> (2 * i
)) & 3;
541 if (mcs
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
546 /* FIXME: consider rx_highest? */
549 rx_nss
= max(vht_rx_nss
, ht_rx_nss
);
550 rx_nss
= max(he_rx_nss
, rx_nss
);
551 sta
->sta
.rx_nss
= max_t(u8
, 1, rx_nss
);
554 u32
__ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data
*sdata
,
555 struct sta_info
*sta
, u8 opmode
,
556 enum nl80211_band band
)
558 enum ieee80211_sta_rx_bandwidth new_bw
;
559 struct sta_opmode_info sta_opmode
= {};
563 /* ignore - no support for BF yet */
564 if (opmode
& IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF
)
567 nss
= opmode
& IEEE80211_OPMODE_NOTIF_RX_NSS_MASK
;
568 nss
>>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT
;
571 if (sta
->sta
.rx_nss
!= nss
) {
572 sta
->sta
.rx_nss
= nss
;
573 sta_opmode
.rx_nss
= nss
;
574 changed
|= IEEE80211_RC_NSS_CHANGED
;
575 sta_opmode
.changed
|= STA_OPMODE_N_SS_CHANGED
;
578 switch (opmode
& IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK
) {
579 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ
:
580 /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
581 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_20
;
583 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ
:
584 /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
585 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_40
;
587 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ
:
588 if (opmode
& IEEE80211_OPMODE_NOTIF_BW_160_80P80
)
589 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
591 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_80
;
593 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ
:
594 /* legacy only, no longer used by newer spec */
595 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
599 new_bw
= ieee80211_sta_cur_vht_bw(sta
);
600 if (new_bw
!= sta
->sta
.bandwidth
) {
601 sta
->sta
.bandwidth
= new_bw
;
602 sta_opmode
.bw
= ieee80211_sta_rx_bw_to_chan_width(sta
);
603 changed
|= IEEE80211_RC_BW_CHANGED
;
604 sta_opmode
.changed
|= STA_OPMODE_MAX_BW_CHANGED
;
607 if (sta_opmode
.changed
)
608 cfg80211_sta_opmode_change_notify(sdata
->dev
, sta
->addr
,
609 &sta_opmode
, GFP_KERNEL
);
614 void ieee80211_process_mu_groups(struct ieee80211_sub_if_data
*sdata
,
615 struct ieee80211_mgmt
*mgmt
)
617 struct ieee80211_bss_conf
*bss_conf
= &sdata
->vif
.bss_conf
;
619 if (!sdata
->vif
.mu_mimo_owner
)
622 if (!memcmp(mgmt
->u
.action
.u
.vht_group_notif
.position
,
623 bss_conf
->mu_group
.position
, WLAN_USER_POSITION_LEN
) &&
624 !memcmp(mgmt
->u
.action
.u
.vht_group_notif
.membership
,
625 bss_conf
->mu_group
.membership
, WLAN_MEMBERSHIP_LEN
))
628 memcpy(bss_conf
->mu_group
.membership
,
629 mgmt
->u
.action
.u
.vht_group_notif
.membership
,
630 WLAN_MEMBERSHIP_LEN
);
631 memcpy(bss_conf
->mu_group
.position
,
632 mgmt
->u
.action
.u
.vht_group_notif
.position
,
633 WLAN_USER_POSITION_LEN
);
635 ieee80211_bss_info_change_notify(sdata
, BSS_CHANGED_MU_GROUPS
);
638 void ieee80211_update_mu_groups(struct ieee80211_vif
*vif
,
639 const u8
*membership
, const u8
*position
)
641 struct ieee80211_bss_conf
*bss_conf
= &vif
->bss_conf
;
643 if (WARN_ON_ONCE(!vif
->mu_mimo_owner
))
646 memcpy(bss_conf
->mu_group
.membership
, membership
, WLAN_MEMBERSHIP_LEN
);
647 memcpy(bss_conf
->mu_group
.position
, position
, WLAN_USER_POSITION_LEN
);
649 EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups
);
651 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data
*sdata
,
652 struct sta_info
*sta
, u8 opmode
,
653 enum nl80211_band band
)
655 struct ieee80211_local
*local
= sdata
->local
;
656 struct ieee80211_supported_band
*sband
= local
->hw
.wiphy
->bands
[band
];
658 u32 changed
= __ieee80211_vht_handle_opmode(sdata
, sta
, opmode
, band
);
661 ieee80211_recalc_min_chandef(sdata
);
662 rate_control_rate_update(local
, sband
, sta
, changed
);
666 void ieee80211_get_vht_mask_from_cap(__le16 vht_cap
,
667 u16 vht_mask
[NL80211_VHT_NSS_MAX
])
670 u16 mask
, cap
= le16_to_cpu(vht_cap
);
672 for (i
= 0; i
< NL80211_VHT_NSS_MAX
; i
++) {
673 mask
= (cap
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
675 case IEEE80211_VHT_MCS_SUPPORT_0_7
:
676 vht_mask
[i
] = 0x00FF;
678 case IEEE80211_VHT_MCS_SUPPORT_0_8
:
679 vht_mask
[i
] = 0x01FF;
681 case IEEE80211_VHT_MCS_SUPPORT_0_9
:
682 vht_mask
[i
] = 0x03FF;
684 case IEEE80211_VHT_MCS_NOT_SUPPORTED
: