4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
9 #include <linux/ieee80211.h>
10 #include <linux/export.h>
11 #include <net/mac80211.h>
12 #include "ieee80211_i.h"
17 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data
*sdata
,
18 struct ieee80211_supported_band
*sband
,
19 const struct ieee80211_vht_cap
*vht_cap_ie
,
22 struct ieee80211_sta_vht_cap
*vht_cap
= &sta
->sta
.vht_cap
;
24 memset(vht_cap
, 0, sizeof(*vht_cap
));
26 if (!sta
->sta
.ht_cap
.ht_supported
)
29 if (!vht_cap_ie
|| !sband
->vht_cap
.vht_supported
)
32 /* A VHT STA must support 40 MHz */
33 if (!(sta
->sta
.ht_cap
.cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
))
36 vht_cap
->vht_supported
= true;
38 vht_cap
->cap
= le32_to_cpu(vht_cap_ie
->vht_cap_info
);
40 /* Copy peer MCS info, the driver might need them. */
41 memcpy(&vht_cap
->vht_mcs
, &vht_cap_ie
->supp_mcs
,
42 sizeof(struct ieee80211_vht_mcs_info
));
44 switch (vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
) {
45 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
:
46 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
:
47 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
50 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_80
;
53 sta
->sta
.bandwidth
= ieee80211_sta_cur_vht_bw(sta
);
56 enum ieee80211_sta_rx_bandwidth
ieee80211_sta_cur_vht_bw(struct sta_info
*sta
)
58 struct ieee80211_sub_if_data
*sdata
= sta
->sdata
;
59 u32 cap
= sta
->sta
.vht_cap
.cap
;
60 enum ieee80211_sta_rx_bandwidth bw
;
62 if (!sta
->sta
.vht_cap
.vht_supported
) {
63 bw
= sta
->sta
.ht_cap
.cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
?
64 IEEE80211_STA_RX_BW_40
: IEEE80211_STA_RX_BW_20
;
68 switch (sdata
->vif
.bss_conf
.chandef
.width
) {
72 case NL80211_CHAN_WIDTH_20_NOHT
:
73 case NL80211_CHAN_WIDTH_20
:
74 case NL80211_CHAN_WIDTH_40
:
75 bw
= sta
->sta
.ht_cap
.cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
?
76 IEEE80211_STA_RX_BW_40
: IEEE80211_STA_RX_BW_20
;
78 case NL80211_CHAN_WIDTH_160
:
79 if ((cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
) ==
80 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
) {
81 bw
= IEEE80211_STA_RX_BW_160
;
85 case NL80211_CHAN_WIDTH_80P80
:
86 if ((cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
) ==
87 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
) {
88 bw
= IEEE80211_STA_RX_BW_160
;
92 case NL80211_CHAN_WIDTH_80
:
93 bw
= IEEE80211_STA_RX_BW_80
;
97 if (bw
> sta
->cur_max_bandwidth
)
98 bw
= sta
->cur_max_bandwidth
;
102 void ieee80211_sta_set_rx_nss(struct sta_info
*sta
)
104 u8 ht_rx_nss
= 0, vht_rx_nss
= 0;
106 /* if we received a notification already don't overwrite it */
110 if (sta
->sta
.ht_cap
.ht_supported
) {
111 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[0])
113 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[1])
115 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[2])
117 if (sta
->sta
.ht_cap
.mcs
.rx_mask
[3])
119 /* FIXME: consider rx_highest? */
122 if (sta
->sta
.vht_cap
.vht_supported
) {
126 rx_mcs_map
= le16_to_cpu(sta
->sta
.vht_cap
.vht_mcs
.rx_mcs_map
);
128 for (i
= 7; i
>= 0; i
--) {
129 u8 mcs
= (rx_mcs_map
>> (2 * i
)) & 3;
131 if (mcs
!= IEEE80211_VHT_MCS_NOT_SUPPORTED
) {
136 /* FIXME: consider rx_highest? */
139 ht_rx_nss
= max(ht_rx_nss
, vht_rx_nss
);
140 sta
->sta
.rx_nss
= max_t(u8
, 1, ht_rx_nss
);
143 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data
*sdata
,
144 struct sta_info
*sta
, u8 opmode
,
145 enum ieee80211_band band
, bool nss_only
)
147 struct ieee80211_local
*local
= sdata
->local
;
148 struct ieee80211_supported_band
*sband
;
149 enum ieee80211_sta_rx_bandwidth new_bw
;
153 sband
= local
->hw
.wiphy
->bands
[band
];
155 /* ignore - no support for BF yet */
156 if (opmode
& IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF
)
159 nss
= opmode
& IEEE80211_OPMODE_NOTIF_RX_NSS_MASK
;
160 nss
>>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT
;
163 if (sta
->sta
.rx_nss
!= nss
) {
164 sta
->sta
.rx_nss
= nss
;
165 changed
|= IEEE80211_RC_NSS_CHANGED
;
171 switch (opmode
& IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK
) {
172 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ
:
173 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_20
;
175 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ
:
176 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_40
;
178 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ
:
179 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_80
;
181 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ
:
182 sta
->cur_max_bandwidth
= IEEE80211_STA_RX_BW_160
;
186 new_bw
= ieee80211_sta_cur_vht_bw(sta
);
187 if (new_bw
!= sta
->sta
.bandwidth
) {
188 sta
->sta
.bandwidth
= new_bw
;
189 changed
|= IEEE80211_RC_NSS_CHANGED
;
194 rate_control_rate_update(local
, sband
, sta
, changed
);