1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright(c) 2017 Intel Deutschland GmbH
6 * Copyright(c) 2019 - 2020 Intel Corporation
9 #include "ieee80211_i.h"
12 ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa
*he_6ghz_capa
,
15 enum ieee80211_smps_mode smps_mode
;
17 if (sta
->sdata
->vif
.type
== NL80211_IFTYPE_AP
||
18 sta
->sdata
->vif
.type
== NL80211_IFTYPE_AP_VLAN
) {
19 switch (le16_get_bits(he_6ghz_capa
->capa
,
20 IEEE80211_HE_6GHZ_CAP_SM_PS
)) {
21 case WLAN_HT_CAP_SM_PS_INVALID
:
22 case WLAN_HT_CAP_SM_PS_STATIC
:
23 smps_mode
= IEEE80211_SMPS_STATIC
;
25 case WLAN_HT_CAP_SM_PS_DYNAMIC
:
26 smps_mode
= IEEE80211_SMPS_DYNAMIC
;
28 case WLAN_HT_CAP_SM_PS_DISABLED
:
29 smps_mode
= IEEE80211_SMPS_OFF
;
33 sta
->sta
.smps_mode
= smps_mode
;
35 sta
->sta
.smps_mode
= IEEE80211_SMPS_OFF
;
38 switch (le16_get_bits(he_6ghz_capa
->capa
,
39 IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN
)) {
40 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454
:
41 sta
->sta
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_11454
;
43 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991
:
44 sta
->sta
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_7991
;
46 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895
:
48 sta
->sta
.max_amsdu_len
= IEEE80211_MAX_MPDU_LEN_VHT_3895
;
52 sta
->sta
.he_6ghz_capa
= *he_6ghz_capa
;
55 static void ieee80211_he_mcs_disable(__le16
*he_mcs
)
59 for (i
= 0; i
< 8; i
++)
60 *he_mcs
|= cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED
<< i
* 2);
63 static void ieee80211_he_mcs_intersection(__le16
*he_own_rx
, __le16
*he_peer_rx
,
64 __le16
*he_own_tx
, __le16
*he_peer_tx
)
67 u16 own_rx
, own_tx
, peer_rx
, peer_tx
;
69 for (i
= 0; i
< 8; i
++) {
70 own_rx
= le16_to_cpu(*he_own_rx
);
71 own_rx
= (own_rx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
73 own_tx
= le16_to_cpu(*he_own_tx
);
74 own_tx
= (own_tx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
76 peer_rx
= le16_to_cpu(*he_peer_rx
);
77 peer_rx
= (peer_rx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
79 peer_tx
= le16_to_cpu(*he_peer_tx
);
80 peer_tx
= (peer_tx
>> i
* 2) & IEEE80211_HE_MCS_NOT_SUPPORTED
;
82 if (peer_tx
!= IEEE80211_HE_MCS_NOT_SUPPORTED
) {
83 if (own_rx
== IEEE80211_HE_MCS_NOT_SUPPORTED
)
84 peer_tx
= IEEE80211_HE_MCS_NOT_SUPPORTED
;
85 else if (own_rx
< peer_tx
)
89 if (peer_rx
!= IEEE80211_HE_MCS_NOT_SUPPORTED
) {
90 if (own_tx
== IEEE80211_HE_MCS_NOT_SUPPORTED
)
91 peer_rx
= IEEE80211_HE_MCS_NOT_SUPPORTED
;
92 else if (own_tx
< peer_rx
)
97 ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED
<< i
* 2);
98 *he_peer_rx
|= cpu_to_le16(peer_rx
<< i
* 2);
101 ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED
<< i
* 2);
102 *he_peer_tx
|= cpu_to_le16(peer_tx
<< i
* 2);
107 ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data
*sdata
,
108 struct ieee80211_supported_band
*sband
,
109 const u8
*he_cap_ie
, u8 he_cap_len
,
110 const struct ieee80211_he_6ghz_capa
*he_6ghz_capa
,
111 struct sta_info
*sta
)
113 struct ieee80211_sta_he_cap
*he_cap
= &sta
->sta
.he_cap
;
114 struct ieee80211_sta_he_cap own_he_cap
;
115 struct ieee80211_he_cap_elem
*he_cap_ie_elem
= (void *)he_cap_ie
;
119 bool own_160
, peer_160
, own_80p80
, peer_80p80
;
121 memset(he_cap
, 0, sizeof(*he_cap
));
124 !ieee80211_get_he_iftype_cap(sband
,
125 ieee80211_vif_type_p2p(&sdata
->vif
)))
128 own_he_cap
= sband
->iftype_data
->he_cap
;
130 /* Make sure size is OK */
131 mcs_nss_size
= ieee80211_he_mcs_nss_size(he_cap_ie_elem
);
133 ieee80211_he_ppe_size(he_cap_ie
[sizeof(he_cap
->he_cap_elem
) +
135 he_cap_ie_elem
->phy_cap_info
);
136 he_total_size
= sizeof(he_cap
->he_cap_elem
) + mcs_nss_size
+
138 if (he_cap_len
< he_total_size
)
141 memcpy(&he_cap
->he_cap_elem
, he_cap_ie
, sizeof(he_cap
->he_cap_elem
));
143 /* HE Tx/Rx HE MCS NSS Support Field */
144 memcpy(&he_cap
->he_mcs_nss_supp
,
145 &he_cap_ie
[sizeof(he_cap
->he_cap_elem
)], mcs_nss_size
);
147 /* Check if there are (optional) PPE Thresholds */
148 if (he_cap
->he_cap_elem
.phy_cap_info
[6] &
149 IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT
)
150 memcpy(he_cap
->ppe_thres
,
151 &he_cap_ie
[sizeof(he_cap
->he_cap_elem
) + mcs_nss_size
],
154 he_cap
->has_he
= true;
156 sta
->cur_max_bandwidth
= ieee80211_sta_cap_rx_bw(sta
);
157 sta
->sta
.bandwidth
= ieee80211_sta_cur_vht_bw(sta
);
159 if (sband
->band
== NL80211_BAND_6GHZ
&& he_6ghz_capa
)
160 ieee80211_update_from_he_6ghz_capa(he_6ghz_capa
, sta
);
162 ieee80211_he_mcs_intersection(&own_he_cap
.he_mcs_nss_supp
.rx_mcs_80
,
163 &he_cap
->he_mcs_nss_supp
.rx_mcs_80
,
164 &own_he_cap
.he_mcs_nss_supp
.tx_mcs_80
,
165 &he_cap
->he_mcs_nss_supp
.tx_mcs_80
);
167 own_160
= own_he_cap
.he_cap_elem
.phy_cap_info
[0] &
168 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
;
169 peer_160
= he_cap
->he_cap_elem
.phy_cap_info
[0] &
170 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
;
172 if (peer_160
&& own_160
) {
173 ieee80211_he_mcs_intersection(&own_he_cap
.he_mcs_nss_supp
.rx_mcs_160
,
174 &he_cap
->he_mcs_nss_supp
.rx_mcs_160
,
175 &own_he_cap
.he_mcs_nss_supp
.tx_mcs_160
,
176 &he_cap
->he_mcs_nss_supp
.tx_mcs_160
);
177 } else if (peer_160
&& !own_160
) {
178 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.rx_mcs_160
);
179 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.tx_mcs_160
);
180 he_cap
->he_cap_elem
.phy_cap_info
[0] &=
181 ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G
;
184 own_80p80
= own_he_cap
.he_cap_elem
.phy_cap_info
[0] &
185 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
;
186 peer_80p80
= he_cap
->he_cap_elem
.phy_cap_info
[0] &
187 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
;
189 if (peer_80p80
&& own_80p80
) {
190 ieee80211_he_mcs_intersection(&own_he_cap
.he_mcs_nss_supp
.rx_mcs_80p80
,
191 &he_cap
->he_mcs_nss_supp
.rx_mcs_80p80
,
192 &own_he_cap
.he_mcs_nss_supp
.tx_mcs_80p80
,
193 &he_cap
->he_mcs_nss_supp
.tx_mcs_80p80
);
194 } else if (peer_80p80
&& !own_80p80
) {
195 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.rx_mcs_80p80
);
196 ieee80211_he_mcs_disable(&he_cap
->he_mcs_nss_supp
.tx_mcs_80p80
);
197 he_cap
->he_cap_elem
.phy_cap_info
[0] &=
198 ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G
;
203 ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif
*vif
,
204 const struct ieee80211_he_operation
*he_op_ie
)
206 memset(&vif
->bss_conf
.he_oper
, 0, sizeof(vif
->bss_conf
.he_oper
));
210 vif
->bss_conf
.he_oper
.params
= __le32_to_cpu(he_op_ie
->he_oper_params
);
211 vif
->bss_conf
.he_oper
.nss_set
= __le16_to_cpu(he_op_ie
->he_mcs_nss_set
);
215 ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif
*vif
,
216 const struct ieee80211_he_spr
*he_spr_ie_elem
)
218 struct ieee80211_he_obss_pd
*he_obss_pd
=
219 &vif
->bss_conf
.he_obss_pd
;
222 memset(he_obss_pd
, 0, sizeof(*he_obss_pd
));
226 data
= he_spr_ie_elem
->optional
;
228 if (he_spr_ie_elem
->he_sr_control
&
229 IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT
)
231 if (he_spr_ie_elem
->he_sr_control
&
232 IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT
) {
233 he_obss_pd
->max_offset
= *data
++;
234 he_obss_pd
->min_offset
= *data
++;
235 he_obss_pd
->enable
= true;