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 - 2024 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 const struct ieee80211_vht_cap
*vht_cap_ie2
,
120 struct link_sta_info
*link_sta
)
122 struct ieee80211_sta_vht_cap
*vht_cap
= &link_sta
->pub
->vht_cap
;
123 struct ieee80211_sta_vht_cap own_cap
;
128 memset(vht_cap
, 0, sizeof(*vht_cap
));
130 if (!link_sta
->pub
->ht_cap
.ht_supported
)
133 if (!vht_cap_ie
|| !sband
->vht_cap
.vht_supported
)
136 /* Allow VHT if at least one channel on the sband supports 80 MHz */
138 for (i
= 0; i
< sband
->n_channels
; i
++) {
139 if (sband
->channels
[i
].flags
& (IEEE80211_CHAN_DISABLED
|
140 IEEE80211_CHAN_NO_80MHZ
))
151 * A VHT STA must support 40 MHz, but if we verify that here
152 * then we break a few things - some APs (e.g. Netgear R6300v2
153 * and others based on the BCM4360 chipset) will unset this
154 * capability bit when operating in 20 MHz.
157 vht_cap
->vht_supported
= true;
159 own_cap
= sband
->vht_cap
;
161 * If user has specified capability overrides, take care
162 * of that if the station we're setting up is the AP that
163 * we advertised a restricted capability set to. Override
164 * our own capabilities and then use those below.
166 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
&&
167 !test_sta_flag(link_sta
->sta
, WLAN_STA_TDLS_PEER
))
168 ieee80211_apply_vhtcap_overrides(sdata
, &own_cap
);
170 /* take some capabilities as-is */
171 cap_info
= le32_to_cpu(vht_cap_ie
->vht_cap_info
);
172 vht_cap
->cap
= cap_info
;
173 vht_cap
->cap
&= IEEE80211_VHT_CAP_RXLDPC
|
174 IEEE80211_VHT_CAP_VHT_TXOP_PS
|
175 IEEE80211_VHT_CAP_HTC_VHT
|
176 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK
|
177 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB
|
178 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB
|
179 IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN
|
180 IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN
;
182 vht_cap
->cap
|= min_t(u32
, cap_info
& IEEE80211_VHT_CAP_MAX_MPDU_MASK
,
183 own_cap
.cap
& IEEE80211_VHT_CAP_MAX_MPDU_MASK
);
185 /* and some based on our own capabilities */
186 switch (own_cap
.cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
) {
187 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
:
188 vht_cap
->cap
|= cap_info
&
189 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
;
191 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
:
192 vht_cap
->cap
|= cap_info
&
193 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
200 /* symmetric capabilities */
201 vht_cap
->cap
|= cap_info
& own_cap
.cap
&
202 (IEEE80211_VHT_CAP_SHORT_GI_80
|
203 IEEE80211_VHT_CAP_SHORT_GI_160
);
206 if (own_cap
.cap
& IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
)
207 vht_cap
->cap
|= cap_info
&
208 (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE
|
209 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK
);
211 if (own_cap
.cap
& IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE
)
212 vht_cap
->cap
|= cap_info
&
213 (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
|
214 IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK
);
216 if (own_cap
.cap
& IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE
)
217 vht_cap
->cap
|= cap_info
&
218 IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE
;
220 if (own_cap
.cap
& IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE
)
221 vht_cap
->cap
|= cap_info
&
222 IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE
;
224 if (own_cap
.cap
& IEEE80211_VHT_CAP_TXSTBC
)
225 vht_cap
->cap
|= cap_info
& IEEE80211_VHT_CAP_RXSTBC_MASK
;
227 if (own_cap
.cap
& IEEE80211_VHT_CAP_RXSTBC_MASK
)
228 vht_cap
->cap
|= cap_info
& IEEE80211_VHT_CAP_TXSTBC
;
230 /* Copy peer MCS info, the driver might need them. */
231 memcpy(&vht_cap
->vht_mcs
, &vht_cap_ie
->supp_mcs
,
232 sizeof(struct ieee80211_vht_mcs_info
));
234 /* copy EXT_NSS_BW Support value or remove the capability */
235 if (ieee80211_hw_check(&sdata
->local
->hw
, SUPPORTS_VHT_EXT_NSS_BW
))
236 vht_cap
->cap
|= (cap_info
& IEEE80211_VHT_CAP_EXT_NSS_BW_MASK
);
238 vht_cap
->vht_mcs
.tx_highest
&=
239 ~cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE
);
241 /* but also restrict MCSes */
242 for (i
= 0; i
< 8; i
++) {
243 u16 own_rx
, own_tx
, peer_rx
, peer_tx
;
245 own_rx
= le16_to_cpu(own_cap
.vht_mcs
.rx_mcs_map
);
246 own_rx
= (own_rx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
248 own_tx
= le16_to_cpu(own_cap
.vht_mcs
.tx_mcs_map
);
249 own_tx
= (own_tx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
251 peer_rx
= le16_to_cpu(vht_cap
->vht_mcs
.rx_mcs_map
);
252 peer_rx
= (peer_rx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
254 peer_tx
= le16_to_cpu(vht_cap
->vht_mcs
.tx_mcs_map
);
255 peer_tx
= (peer_tx
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
257 if (peer_tx
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
258 if (own_rx
== IEEE80211_VHT_MCS_NOT_SUPPORTED
)
259 peer_tx
= IEEE80211_VHT_MCS_NOT_SUPPORTED
;
260 else if (own_rx
< peer_tx
)
264 if (peer_rx
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
265 if (own_tx
== IEEE80211_VHT_MCS_NOT_SUPPORTED
)
266 peer_rx
= IEEE80211_VHT_MCS_NOT_SUPPORTED
;
267 else if (own_tx
< peer_rx
)
271 vht_cap
->vht_mcs
.rx_mcs_map
&=
272 ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED
<< i
* 2);
273 vht_cap
->vht_mcs
.rx_mcs_map
|= cpu_to_le16(peer_rx
<< i
* 2);
275 vht_cap
->vht_mcs
.tx_mcs_map
&=
276 ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED
<< i
* 2);
277 vht_cap
->vht_mcs
.tx_mcs_map
|= cpu_to_le16(peer_tx
<< i
* 2);
281 * This is a workaround for VHT-enabled STAs which break the spec
282 * and have the VHT-MCS Rx map filled in with value 3 for all eight
283 * spacial streams, an example is AR9462.
285 * As per spec, in section 22.1.1 Introduction to the VHT PHY
286 * A VHT STA shall support at least single spactial stream VHT-MCSs
287 * 0 to 7 (transmit and receive) in all supported channel widths.
289 if (vht_cap
->vht_mcs
.rx_mcs_map
== cpu_to_le16(0xFFFF)) {
290 vht_cap
->vht_supported
= false;
292 "Ignoring VHT IE from %pM (link:%pM) due to invalid rx_mcs_map\n",
293 link_sta
->sta
->addr
, link_sta
->addr
);
297 /* finally set up the bandwidth */
298 switch (vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
) {
299 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
:
300 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
:
301 link_sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
304 link_sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_80
;
306 if (!(vht_cap
->vht_mcs
.tx_highest
&
307 cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE
)))
311 * If this is non-zero, then it does support 160 MHz after all,
312 * in one form or the other. We don't distinguish here (or even
313 * above) between 160 and 80+80 yet.
315 if (cap_info
& IEEE80211_VHT_CAP_EXT_NSS_BW_MASK
)
316 link_sta
->cur_max_bandwidth
=
317 IEEE80211_STA_RX_BW_160
;
320 link_sta
->pub
->bandwidth
= ieee80211_sta_cur_vht_bw(link_sta
);
323 * Work around the Cisco 9115 FW 17.3 bug by taking the min of
324 * both reported MPDU lengths.
326 mpdu_len
= vht_cap
->cap
& IEEE80211_VHT_CAP_MAX_MPDU_MASK
;
328 mpdu_len
= min_t(u32
, mpdu_len
,
329 le32_get_bits(vht_cap_ie2
->vht_cap_info
,
330 IEEE80211_VHT_CAP_MAX_MPDU_MASK
));
333 * FIXME - should the amsdu len be per link? store per link
334 * and maintain a minimum?
337 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454
:
338 link_sta
->pub
->agg
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_11454
;
340 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991
:
341 link_sta
->pub
->agg
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_7991
;
343 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895
:
345 link_sta
->pub
->agg
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_3895
;
349 ieee80211_sta_recalc_aggregates(&link_sta
->sta
->sta
);
352 /* FIXME: move this to some better location - parses HE/EHT now */
353 enum ieee80211_sta_rx_bandwidth
354 _ieee80211_sta_cap_rx_bw(struct link_sta_info
*link_sta
,
355 struct cfg80211_chan_def
*chandef
)
357 unsigned int link_id
= link_sta
->link_id
;
358 struct ieee80211_sub_if_data
*sdata
= link_sta
->sta
->sdata
;
359 struct ieee80211_sta_vht_cap
*vht_cap
= &link_sta
->pub
->vht_cap
;
360 struct ieee80211_sta_he_cap
*he_cap
= &link_sta
->pub
->he_cap
;
361 struct ieee80211_sta_eht_cap
*eht_cap
= &link_sta
->pub
->eht_cap
;
364 if (he_cap
->has_he
) {
365 enum nl80211_band band
;
369 band
= chandef
->chan
->band
;
371 struct ieee80211_bss_conf
*link_conf
;
374 link_conf
= rcu_dereference(sdata
->vif
.link_conf
[link_id
]);
375 band
= link_conf
->chanreq
.oper
.chan
->band
;
379 if (eht_cap
->has_eht
&& band
== NL80211_BAND_6GHZ
) {
380 info
= eht_cap
->eht_cap_elem
.phy_cap_info
[0];
382 if (info
& IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ
)
383 return IEEE80211_STA_RX_BW_320
;
386 info
= he_cap
->he_cap_elem
.phy_cap_info
[0];
388 if (band
== NL80211_BAND_2GHZ
) {
389 if (info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G
)
390 return IEEE80211_STA_RX_BW_40
;
391 return IEEE80211_STA_RX_BW_20
;
394 if (info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
||
395 info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
)
396 return IEEE80211_STA_RX_BW_160
;
398 if (info
& IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G
)
399 return IEEE80211_STA_RX_BW_80
;
401 return IEEE80211_STA_RX_BW_20
;
404 if (!vht_cap
->vht_supported
)
405 return link_sta
->pub
->ht_cap
.cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
?
406 IEEE80211_STA_RX_BW_40
:
407 IEEE80211_STA_RX_BW_20
;
409 cap_width
= vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
411 if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
||
412 cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
)
413 return IEEE80211_STA_RX_BW_160
;
416 * If this is non-zero, then it does support 160 MHz after all,
417 * in one form or the other. We don't distinguish here (or even
418 * above) between 160 and 80+80 yet.
420 if (vht_cap
->cap
& IEEE80211_VHT_CAP_EXT_NSS_BW_MASK
)
421 return IEEE80211_STA_RX_BW_160
;
423 return IEEE80211_STA_RX_BW_80
;
426 enum nl80211_chan_width
427 ieee80211_sta_cap_chan_bw(struct link_sta_info
*link_sta
)
429 struct ieee80211_sta_vht_cap
*vht_cap
= &link_sta
->pub
->vht_cap
;
432 if (!vht_cap
->vht_supported
) {
433 if (!link_sta
->pub
->ht_cap
.ht_supported
)
434 return NL80211_CHAN_WIDTH_20_NOHT
;
436 return link_sta
->pub
->ht_cap
.cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
?
437 NL80211_CHAN_WIDTH_40
: NL80211_CHAN_WIDTH_20
;
440 cap_width
= vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
442 if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
)
443 return NL80211_CHAN_WIDTH_160
;
444 else if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
)
445 return NL80211_CHAN_WIDTH_80P80
;
447 return NL80211_CHAN_WIDTH_80
;
450 enum nl80211_chan_width
451 ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info
*link_sta
)
453 enum ieee80211_sta_rx_bandwidth cur_bw
=
454 link_sta
->pub
->bandwidth
;
455 struct ieee80211_sta_vht_cap
*vht_cap
=
456 &link_sta
->pub
->vht_cap
;
460 case IEEE80211_STA_RX_BW_20
:
461 if (!link_sta
->pub
->ht_cap
.ht_supported
)
462 return NL80211_CHAN_WIDTH_20_NOHT
;
464 return NL80211_CHAN_WIDTH_20
;
465 case IEEE80211_STA_RX_BW_40
:
466 return NL80211_CHAN_WIDTH_40
;
467 case IEEE80211_STA_RX_BW_80
:
468 return NL80211_CHAN_WIDTH_80
;
469 case IEEE80211_STA_RX_BW_160
:
471 vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
473 if (cap_width
== IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
)
474 return NL80211_CHAN_WIDTH_160
;
476 return NL80211_CHAN_WIDTH_80P80
;
478 return NL80211_CHAN_WIDTH_20
;
482 enum ieee80211_sta_rx_bandwidth
483 ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width
)
486 case NL80211_CHAN_WIDTH_20_NOHT
:
487 case NL80211_CHAN_WIDTH_20
:
488 return IEEE80211_STA_RX_BW_20
;
489 case NL80211_CHAN_WIDTH_40
:
490 return IEEE80211_STA_RX_BW_40
;
491 case NL80211_CHAN_WIDTH_80
:
492 return IEEE80211_STA_RX_BW_80
;
493 case NL80211_CHAN_WIDTH_160
:
494 case NL80211_CHAN_WIDTH_80P80
:
495 return IEEE80211_STA_RX_BW_160
;
496 case NL80211_CHAN_WIDTH_320
:
497 return IEEE80211_STA_RX_BW_320
;
500 return IEEE80211_STA_RX_BW_20
;
504 /* FIXME: rename/move - this deals with everything not just VHT */
505 enum ieee80211_sta_rx_bandwidth
506 _ieee80211_sta_cur_vht_bw(struct link_sta_info
*link_sta
,
507 struct cfg80211_chan_def
*chandef
)
509 struct sta_info
*sta
= link_sta
->sta
;
510 enum nl80211_chan_width bss_width
;
511 enum ieee80211_sta_rx_bandwidth bw
;
514 bss_width
= chandef
->width
;
516 struct ieee80211_bss_conf
*link_conf
;
519 link_conf
= rcu_dereference(sta
->sdata
->vif
.link_conf
[link_sta
->link_id
]);
520 if (WARN_ON_ONCE(!link_conf
)) {
522 return IEEE80211_STA_RX_BW_20
;
524 bss_width
= link_conf
->chanreq
.oper
.width
;
528 bw
= _ieee80211_sta_cap_rx_bw(link_sta
, chandef
);
529 bw
= min(bw
, link_sta
->cur_max_bandwidth
);
531 /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of
532 * IEEE80211-2016 specification makes higher bandwidth operation
533 * possible on the TDLS link if the peers have wider bandwidth
536 * However, in this case, and only if the TDLS peer is authorized,
537 * limit to the tdls_chandef so that the configuration here isn't
538 * wider than what's actually requested on the channel context.
540 if (test_sta_flag(sta
, WLAN_STA_TDLS_PEER
) &&
541 test_sta_flag(sta
, WLAN_STA_TDLS_WIDER_BW
) &&
542 test_sta_flag(sta
, WLAN_STA_AUTHORIZED
) &&
543 sta
->tdls_chandef
.chan
)
544 bw
= min(bw
, ieee80211_chan_width_to_rx_bw(sta
->tdls_chandef
.width
));
546 bw
= min(bw
, ieee80211_chan_width_to_rx_bw(bss_width
));
551 void ieee80211_sta_init_nss(struct link_sta_info
*link_sta
)
553 u8 ht_rx_nss
= 0, vht_rx_nss
= 0, he_rx_nss
= 0, eht_rx_nss
= 0, rx_nss
;
556 if (link_sta
->pub
->eht_cap
.has_eht
) {
558 const u8
*rx_nss_mcs
= (void *)&link_sta
->pub
->eht_cap
.eht_mcs_nss_supp
;
560 /* get the max nss for EHT over all possible bandwidths and mcs */
561 for (i
= 0; i
< sizeof(struct ieee80211_eht_mcs_nss_supp
); i
++)
562 eht_rx_nss
= max_t(u8
, eht_rx_nss
,
563 u8_get_bits(rx_nss_mcs
[i
],
564 IEEE80211_EHT_MCS_NSS_RX
));
567 if (link_sta
->pub
->he_cap
.has_he
) {
569 u8 rx_mcs_80
= 0, rx_mcs_160
= 0;
570 const struct ieee80211_sta_he_cap
*he_cap
= &link_sta
->pub
->he_cap
;
572 le16_to_cpu(he_cap
->he_mcs_nss_supp
.rx_mcs_160
);
573 u16 mcs_80_map
= le16_to_cpu(he_cap
->he_mcs_nss_supp
.rx_mcs_80
);
575 for (i
= 7; i
>= 0; i
--) {
576 u8 mcs_160
= (mcs_160_map
>> (2 * i
)) & 3;
578 if (mcs_160
!= IEEE80211_HE_MCS_NOT_SUPPORTED
) {
583 for (i
= 7; i
>= 0; i
--) {
584 u8 mcs_80
= (mcs_80_map
>> (2 * i
)) & 3;
586 if (mcs_80
!= IEEE80211_HE_MCS_NOT_SUPPORTED
) {
592 support_160
= he_cap
->he_cap_elem
.phy_cap_info
[0] &
593 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
;
596 he_rx_nss
= min(rx_mcs_80
, rx_mcs_160
);
598 he_rx_nss
= rx_mcs_80
;
601 if (link_sta
->pub
->ht_cap
.ht_supported
) {
602 if (link_sta
->pub
->ht_cap
.mcs
.rx_mask
[0])
604 if (link_sta
->pub
->ht_cap
.mcs
.rx_mask
[1])
606 if (link_sta
->pub
->ht_cap
.mcs
.rx_mask
[2])
608 if (link_sta
->pub
->ht_cap
.mcs
.rx_mask
[3])
610 /* FIXME: consider rx_highest? */
613 if (link_sta
->pub
->vht_cap
.vht_supported
) {
617 rx_mcs_map
= le16_to_cpu(link_sta
->pub
->vht_cap
.vht_mcs
.rx_mcs_map
);
619 for (i
= 7; i
>= 0; i
--) {
620 u8 mcs
= (rx_mcs_map
>> (2 * i
)) & 3;
622 if (mcs
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
627 /* FIXME: consider rx_highest? */
630 rx_nss
= max(vht_rx_nss
, ht_rx_nss
);
631 rx_nss
= max(he_rx_nss
, rx_nss
);
632 rx_nss
= max(eht_rx_nss
, rx_nss
);
633 rx_nss
= max_t(u8
, 1, rx_nss
);
634 link_sta
->capa_nss
= rx_nss
;
636 /* that shouldn't be set yet, but we can handle it anyway */
637 if (link_sta
->op_mode_nss
)
638 link_sta
->pub
->rx_nss
=
639 min_t(u8
, rx_nss
, link_sta
->op_mode_nss
);
641 link_sta
->pub
->rx_nss
= rx_nss
;
644 u32
__ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data
*sdata
,
645 struct link_sta_info
*link_sta
,
646 u8 opmode
, enum nl80211_band band
)
648 enum ieee80211_sta_rx_bandwidth new_bw
;
649 struct sta_opmode_info sta_opmode
= {};
653 /* ignore - no support for BF yet */
654 if (opmode
& IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF
)
657 nss
= opmode
& IEEE80211_OPMODE_NOTIF_RX_NSS_MASK
;
658 nss
>>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT
;
661 if (link_sta
->op_mode_nss
!= nss
) {
662 if (nss
<= link_sta
->capa_nss
) {
663 link_sta
->op_mode_nss
= nss
;
665 if (nss
!= link_sta
->pub
->rx_nss
) {
666 link_sta
->pub
->rx_nss
= nss
;
667 changed
|= IEEE80211_RC_NSS_CHANGED
;
668 sta_opmode
.rx_nss
= link_sta
->pub
->rx_nss
;
669 sta_opmode
.changed
|= STA_OPMODE_N_SS_CHANGED
;
672 pr_warn_ratelimited("Ignoring NSS change in VHT Operating Mode Notification from %pM with invalid nss %d",
673 link_sta
->pub
->addr
, nss
);
677 switch (opmode
& IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK
) {
678 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ
:
679 /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
680 link_sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_20
;
682 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ
:
683 /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
684 link_sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_40
;
686 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ
:
687 if (opmode
& IEEE80211_OPMODE_NOTIF_BW_160_80P80
)
688 link_sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
690 link_sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_80
;
692 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ
:
693 /* legacy only, no longer used by newer spec */
694 link_sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
698 new_bw
= ieee80211_sta_cur_vht_bw(link_sta
);
699 if (new_bw
!= link_sta
->pub
->bandwidth
) {
700 link_sta
->pub
->bandwidth
= new_bw
;
701 sta_opmode
.bw
= ieee80211_sta_rx_bw_to_chan_width(link_sta
);
702 changed
|= IEEE80211_RC_BW_CHANGED
;
703 sta_opmode
.changed
|= STA_OPMODE_MAX_BW_CHANGED
;
706 if (sta_opmode
.changed
)
707 cfg80211_sta_opmode_change_notify(sdata
->dev
, link_sta
->addr
,
708 &sta_opmode
, GFP_KERNEL
);
713 void ieee80211_process_mu_groups(struct ieee80211_sub_if_data
*sdata
,
714 struct ieee80211_link_data
*link
,
715 struct ieee80211_mgmt
*mgmt
)
717 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
719 if (!link_conf
->mu_mimo_owner
)
722 if (!memcmp(mgmt
->u
.action
.u
.vht_group_notif
.position
,
723 link_conf
->mu_group
.position
, WLAN_USER_POSITION_LEN
) &&
724 !memcmp(mgmt
->u
.action
.u
.vht_group_notif
.membership
,
725 link_conf
->mu_group
.membership
, WLAN_MEMBERSHIP_LEN
))
728 memcpy(link_conf
->mu_group
.membership
,
729 mgmt
->u
.action
.u
.vht_group_notif
.membership
,
730 WLAN_MEMBERSHIP_LEN
);
731 memcpy(link_conf
->mu_group
.position
,
732 mgmt
->u
.action
.u
.vht_group_notif
.position
,
733 WLAN_USER_POSITION_LEN
);
735 ieee80211_link_info_change_notify(sdata
, link
,
736 BSS_CHANGED_MU_GROUPS
);
739 void ieee80211_update_mu_groups(struct ieee80211_vif
*vif
, unsigned int link_id
,
740 const u8
*membership
, const u8
*position
)
742 struct ieee80211_bss_conf
*link_conf
;
745 link_conf
= rcu_dereference(vif
->link_conf
[link_id
]);
747 if (!WARN_ON_ONCE(!link_conf
|| !link_conf
->mu_mimo_owner
)) {
748 memcpy(link_conf
->mu_group
.membership
, membership
,
749 WLAN_MEMBERSHIP_LEN
);
750 memcpy(link_conf
->mu_group
.position
, position
,
751 WLAN_USER_POSITION_LEN
);
755 EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups
);
757 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data
*sdata
,
758 struct link_sta_info
*link_sta
,
759 u8 opmode
, enum nl80211_band band
)
761 struct ieee80211_local
*local
= sdata
->local
;
762 struct ieee80211_supported_band
*sband
= local
->hw
.wiphy
->bands
[band
];
764 u32 changed
= __ieee80211_vht_handle_opmode(sdata
, link_sta
,
768 ieee80211_recalc_min_chandef(sdata
, link_sta
->link_id
);
769 rate_control_rate_update(local
, sband
, link_sta
->sta
,
770 link_sta
->link_id
, changed
);
774 void ieee80211_get_vht_mask_from_cap(__le16 vht_cap
,
775 u16 vht_mask
[NL80211_VHT_NSS_MAX
])
778 u16 mask
, cap
= le16_to_cpu(vht_cap
);
780 for (i
= 0; i
< NL80211_VHT_NSS_MAX
; i
++) {
781 mask
= (cap
>> i
* 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED
;
783 case IEEE80211_VHT_MCS_SUPPORT_0_7
:
784 vht_mask
[i
] = 0x00FF;
786 case IEEE80211_VHT_MCS_SUPPORT_0_8
:
787 vht_mask
[i
] = 0x01FF;
789 case IEEE80211_VHT_MCS_SUPPORT_0_9
:
790 vht_mask
[i
] = 0x03FF;
792 case IEEE80211_VHT_MCS_NOT_SUPPORTED
: