1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright(c) 2017 Intel Deutschland GmbH
6 * Copyright(c) 2019 - 2023 Intel Corporation
9 #include "ieee80211_i.h"
12 ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa
*he_6ghz_capa
,
13 struct link_sta_info
*link_sta
)
15 struct sta_info
*sta
= link_sta
->sta
;
16 enum ieee80211_smps_mode smps_mode
;
18 if (sta
->sdata
->vif
.type
== NL80211_IFTYPE_AP
||
19 sta
->sdata
->vif
.type
== NL80211_IFTYPE_AP_VLAN
) {
20 switch (le16_get_bits(he_6ghz_capa
->capa
,
21 IEEE80211_HE_6GHZ_CAP_SM_PS
)) {
22 case WLAN_HT_CAP_SM_PS_INVALID
:
23 case WLAN_HT_CAP_SM_PS_STATIC
:
24 smps_mode
= IEEE80211_SMPS_STATIC
;
26 case WLAN_HT_CAP_SM_PS_DYNAMIC
:
27 smps_mode
= IEEE80211_SMPS_DYNAMIC
;
29 case WLAN_HT_CAP_SM_PS_DISABLED
:
30 smps_mode
= IEEE80211_SMPS_OFF
;
34 link_sta
->pub
->smps_mode
= smps_mode
;
36 link_sta
->pub
->smps_mode
= IEEE80211_SMPS_OFF
;
39 switch (le16_get_bits(he_6ghz_capa
->capa
,
40 IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN
)) {
41 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454
:
42 link_sta
->pub
->agg
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_11454
;
44 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991
:
45 link_sta
->pub
->agg
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_7991
;
47 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895
:
49 link_sta
->pub
->agg
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_3895
;
53 ieee80211_sta_recalc_aggregates(&sta
->sta
);
55 link_sta
->pub
->he_6ghz_capa
= *he_6ghz_capa
;
58 static void ieee80211_he_mcs_disable(__le16
*he_mcs
)
62 for (i
= 0; i
< 8; i
++)
63 *he_mcs
|= cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED
<< i
* 2);
66 static void ieee80211_he_mcs_intersection(__le16
*he_own_rx
, __le16
*he_peer_rx
,
67 __le16
*he_own_tx
, __le16
*he_peer_tx
)
70 u16 own_rx
, own_tx
, peer_rx
, peer_tx
;
72 for (i
= 0; i
< 8; i
++) {
73 own_rx
= le16_to_cpu(*he_own_rx
);
74 own_rx
= (own_rx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
76 own_tx
= le16_to_cpu(*he_own_tx
);
77 own_tx
= (own_tx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
79 peer_rx
= le16_to_cpu(*he_peer_rx
);
80 peer_rx
= (peer_rx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
82 peer_tx
= le16_to_cpu(*he_peer_tx
);
83 peer_tx
= (peer_tx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
85 if (peer_tx
!= IEEE80211_HE_MCS_NOT_SUPPORTED
) {
86 if (own_rx
== IEEE80211_HE_MCS_NOT_SUPPORTED
)
87 peer_tx
= IEEE80211_HE_MCS_NOT_SUPPORTED
;
88 else if (own_rx
< peer_tx
)
92 if (peer_rx
!= IEEE80211_HE_MCS_NOT_SUPPORTED
) {
93 if (own_tx
== IEEE80211_HE_MCS_NOT_SUPPORTED
)
94 peer_rx
= IEEE80211_HE_MCS_NOT_SUPPORTED
;
95 else if (own_tx
< peer_rx
)
100 ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED
<< i
* 2);
101 *he_peer_rx
|= cpu_to_le16(peer_rx
<< i
* 2);
104 ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED
<< i
* 2);
105 *he_peer_tx
|= cpu_to_le16(peer_tx
<< i
* 2);
110 ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data
*sdata
,
111 struct ieee80211_supported_band
*sband
,
112 const u8
*he_cap_ie
, u8 he_cap_len
,
113 const struct ieee80211_he_6ghz_capa
*he_6ghz_capa
,
114 struct link_sta_info
*link_sta
)
116 struct ieee80211_sta_he_cap
*he_cap
= &link_sta
->pub
->he_cap
;
117 const struct ieee80211_sta_he_cap
*own_he_cap_ptr
;
118 struct ieee80211_sta_he_cap own_he_cap
;
119 struct ieee80211_he_cap_elem
*he_cap_ie_elem
= (void *)he_cap_ie
;
123 bool own_160
, peer_160
, own_80p80
, peer_80p80
;
125 memset(he_cap
, 0, sizeof(*he_cap
));
131 ieee80211_get_he_iftype_cap_vif(sband
, &sdata
->vif
);
135 own_he_cap
= *own_he_cap_ptr
;
137 /* Make sure size is OK */
138 mcs_nss_size
= ieee80211_he_mcs_nss_size(he_cap_ie_elem
);
140 ieee80211_he_ppe_size(he_cap_ie
[sizeof(he_cap
->he_cap_elem
) +
142 he_cap_ie_elem
->phy_cap_info
);
143 he_total_size
= sizeof(he_cap
->he_cap_elem
) + mcs_nss_size
+
145 if (he_cap_len
< he_total_size
)
148 memcpy(&he_cap
->he_cap_elem
, he_cap_ie
, sizeof(he_cap
->he_cap_elem
));
150 /* HE Tx/Rx HE MCS NSS Support Field */
151 memcpy(&he_cap
->he_mcs_nss_supp
,
152 &he_cap_ie
[sizeof(he_cap
->he_cap_elem
)], mcs_nss_size
);
154 /* Check if there are (optional) PPE Thresholds */
155 if (he_cap
->he_cap_elem
.phy_cap_info
[6] &
156 IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT
)
157 memcpy(he_cap
->ppe_thres
,
158 &he_cap_ie
[sizeof(he_cap
->he_cap_elem
) + mcs_nss_size
],
161 he_cap
->has_he
= true;
163 link_sta
->cur_max_bandwidth
= ieee80211_sta_cap_rx_bw(link_sta
);
164 link_sta
->pub
->bandwidth
= ieee80211_sta_cur_vht_bw(link_sta
);
166 if (sband
->band
== NL80211_BAND_6GHZ
&& he_6ghz_capa
)
167 ieee80211_update_from_he_6ghz_capa(he_6ghz_capa
, link_sta
);
169 ieee80211_he_mcs_intersection(&own_he_cap
.he_mcs_nss_supp
.rx_mcs_80
,
170 &he_cap
->he_mcs_nss_supp
.rx_mcs_80
,
171 &own_he_cap
.he_mcs_nss_supp
.tx_mcs_80
,
172 &he_cap
->he_mcs_nss_supp
.tx_mcs_80
);
174 own_160
= own_he_cap
.he_cap_elem
.phy_cap_info
[0] &
175 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
;
176 peer_160
= he_cap
->he_cap_elem
.phy_cap_info
[0] &
177 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
;
179 if (peer_160
&& own_160
) {
180 ieee80211_he_mcs_intersection(&own_he_cap
.he_mcs_nss_supp
.rx_mcs_160
,
181 &he_cap
->he_mcs_nss_supp
.rx_mcs_160
,
182 &own_he_cap
.he_mcs_nss_supp
.tx_mcs_160
,
183 &he_cap
->he_mcs_nss_supp
.tx_mcs_160
);
184 } else if (peer_160
&& !own_160
) {
185 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.rx_mcs_160
);
186 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.tx_mcs_160
);
187 he_cap
->he_cap_elem
.phy_cap_info
[0] &=
188 ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
;
191 own_80p80
= own_he_cap
.he_cap_elem
.phy_cap_info
[0] &
192 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
;
193 peer_80p80
= he_cap
->he_cap_elem
.phy_cap_info
[0] &
194 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
;
196 if (peer_80p80
&& own_80p80
) {
197 ieee80211_he_mcs_intersection(&own_he_cap
.he_mcs_nss_supp
.rx_mcs_80p80
,
198 &he_cap
->he_mcs_nss_supp
.rx_mcs_80p80
,
199 &own_he_cap
.he_mcs_nss_supp
.tx_mcs_80p80
,
200 &he_cap
->he_mcs_nss_supp
.tx_mcs_80p80
);
201 } else if (peer_80p80
&& !own_80p80
) {
202 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.rx_mcs_80p80
);
203 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.tx_mcs_80p80
);
204 he_cap
->he_cap_elem
.phy_cap_info
[0] &=
205 ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
;
210 ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif
*vif
,
211 const struct ieee80211_he_operation
*he_op_ie
)
213 memset(&vif
->bss_conf
.he_oper
, 0, sizeof(vif
->bss_conf
.he_oper
));
217 vif
->bss_conf
.he_oper
.params
= __le32_to_cpu(he_op_ie
->he_oper_params
);
218 vif
->bss_conf
.he_oper
.nss_set
= __le16_to_cpu(he_op_ie
->he_mcs_nss_set
);
222 ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif
*vif
,
223 const struct ieee80211_he_spr
*he_spr_ie_elem
)
225 struct ieee80211_he_obss_pd
*he_obss_pd
=
226 &vif
->bss_conf
.he_obss_pd
;
229 memset(he_obss_pd
, 0, sizeof(*he_obss_pd
));
234 he_obss_pd
->sr_ctrl
= he_spr_ie_elem
->he_sr_control
;
235 data
= he_spr_ie_elem
->optional
;
237 if (he_spr_ie_elem
->he_sr_control
&
238 IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT
)
239 he_obss_pd
->non_srg_max_offset
= *data
++;
241 if (he_spr_ie_elem
->he_sr_control
&
242 IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT
) {
243 he_obss_pd
->min_offset
= *data
++;
244 he_obss_pd
->max_offset
= *data
++;
245 memcpy(he_obss_pd
->bss_color_bitmap
, data
, 8);
247 memcpy(he_obss_pd
->partial_bssid_bitmap
, data
, 8);
248 he_obss_pd
->enable
= true;