1 /** @file mlan_11ax.c
2 *
3 * @brief This file contains the functions for 11ax related features.
4 *
5 *
6 * Copyright 2018-2022 NXP
7 *
8 * This software file (the File) is distributed by NXP
9 * under the terms of the GNU General Public License Version 2, June 1991
10 * (the License). You may use, redistribute and/or modify the File in
11 * accordance with the terms and conditions of the License, a copy of which
12 * is available by writing to the Free Software Foundation, Inc.,
13 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15 *
16 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
19 * this warranty disclaimer.
20 *
21 */
22
23 #include "mlan.h"
24 #include "mlan_join.h"
25 #include "mlan_util.h"
26 #include "mlan_ioctl.h"
27 #include "mlan_fw.h"
28 #include "mlan_main.h"
29 #include "mlan_wmm.h"
30 #include "mlan_11n.h"
31 #include "mlan_11ax.h"
32 #include "mlan_11ac.h"
33
34 /********************************************************
35 Local Variables
36 ********************************************************/
37
38 /********************************************************
39 Global Variables
40 ********************************************************/
41
42 /********************************************************
43 Local Functions
44 ********************************************************/
45
46 /********************************************************
47 Global Functions
48 ********************************************************/
49
50 #if 0
51 /**
52 * @brief This function prints the 802.11ax HE mac capability
53 *
54 * @param pmadapter A pointer to mlan_adapter structure
55 * @param cap Capability value
56 *
57 * @return N/A
58 */
59 static void wlan_show_dot11axmaccap(pmlan_adapter pmadapter, t_u32 cap)
60 {
61 ENTER();
62
63 LEAVE();
64 return;
65 }
66 #endif
67
68 /**
69 * @brief This function check if AP support TWT Response.
70 *
71 * @param pbss_desc A pointer to BSSDescriptor_t structure
72 *
73 * @return MTRUE/MFALSE
74 */
wlan_check_ap_11ax_twt_supported(BSSDescriptor_t * pbss_desc)75 static t_u8 wlan_check_ap_11ax_twt_supported(BSSDescriptor_t *pbss_desc)
76 {
77 if (!pbss_desc->phe_cap)
78 return MFALSE;
79 if (!(pbss_desc->phe_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_RESP_SUPPORT))
80 return MFALSE;
81 if (!pbss_desc->pext_cap)
82 return MFALSE;
83 if (!ISSUPP_EXTCAP_EXT_TWT_RESP(pbss_desc->pext_cap->ext_cap))
84 return MFALSE;
85 return MTRUE;
86 }
87
88 /**
89 * @brief This function check if we should enable TWT support
90 *
91 * @param pbss_desc A pointer to BSSDescriptor_t structure
92 *
93 * @return MTRUE/MFALSE
94 */
wlan_check_11ax_twt_supported(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc)95 t_u8 wlan_check_11ax_twt_supported(mlan_private *pmpriv,
96 BSSDescriptor_t *pbss_desc)
97 {
98 MrvlIEtypes_He_cap_t *phecap =
99 (MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
100 MrvlIEtypes_He_cap_t *hw_he_cap =
101 (MrvlIEtypes_He_cap_t *)&pmpriv->adapter->hw_he_cap;
102 t_u16 band_selected = BAND_A;
103
104 if (pbss_desc && !wlan_check_ap_11ax_twt_supported(pbss_desc)) {
105 PRINTM(MINFO, "AP don't support twt feature\n");
106 return MFALSE;
107 }
108 if (pbss_desc) {
109 if (pbss_desc->bss_band & band_selected) {
110 hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmpriv->adapter
111 ->hw_he_cap;
112 phecap = (MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
113 } else {
114 hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmpriv->adapter
115 ->hw_2g_he_cap;
116 phecap =
117 (MrvlIEtypes_He_cap_t *)&pmpriv->user_2g_he_cap;
118 }
119 }
120 if (!(hw_he_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)) {
121 PRINTM(MINFO, "FW don't support TWT\n");
122 return MFALSE;
123 }
124 if (phecap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)
125 return MTRUE;
126 PRINTM(MINFO, "USER HE_MAC_CAP don't support TWT\n");
127 return MFALSE;
128 }
129
130 #if 0
131 /**
132 * @brief This function prints the 802.11ax HE PHY cap
133 *
134 * @param pmadapter A pointer to mlan_adapter structure
135 * @param support Support value
136 *
137 * @return N/A
138 */
139 static void wlan_show_dot11axphycap(pmlan_adapter pmadapter, t_u32 support)
140 {
141 ENTER();
142
143 LEAVE();
144 return;
145 }
146 #endif
147
148 /**
149 * @brief This function fills the HE CAP IE w/ output format LE, not CPU
150 *
151 * @param priv A pointer to mlan_private structure
152 * @param hecap_ie A pointer to IEEEtypes_HECap_t structure
153 * @param band BAND_A (5G), otherwise, 2.4G
154 *
155 * @return bytes added to the phe_cap
156 */
wlan_fill_he_cap_ie(mlan_private * pmpriv,IEEEtypes_HECap_t * hecap_ie,t_u16 band)157 t_u8 wlan_fill_he_cap_ie(mlan_private *pmpriv, IEEEtypes_HECap_t *hecap_ie,
158 t_u16 band)
159 {
160 pmlan_adapter pmadapter = pmpriv->adapter;
161 MrvlIEtypes_He_cap_t *user_hecap_tlv = MNULL;
162 MrvlIEtypes_He_cap_t *hw_hecap_tlv = MNULL;
163 IEEEtypes_HeMcsNss_t *he_mcsnss = MNULL;
164 t_u8 nss = 0;
165 t_u16 cfg_value = 0;
166 t_u16 hw_value = 0;
167
168 if (band & BAND_A) {
169 user_hecap_tlv = (MrvlIEtypes_He_cap_t *)(pmpriv->user_he_cap);
170 hw_hecap_tlv = (MrvlIEtypes_He_cap_t *)pmadapter->hw_he_cap;
171 } else {
172 user_hecap_tlv =
173 (MrvlIEtypes_He_cap_t *)(pmpriv->user_2g_he_cap);
174 hw_hecap_tlv = (MrvlIEtypes_He_cap_t *)pmadapter->hw_2g_he_cap;
175 }
176
177 // include PPE threshold
178 memcpy_ext(pmadapter, (t_u8 *)hecap_ie + sizeof(IEEEtypes_Header_t),
179 (t_u8 *)user_hecap_tlv + sizeof(MrvlIEtypesHeader_t),
180 user_hecap_tlv->len,
181 sizeof(IEEEtypes_HECap_t) - sizeof(IEEEtypes_Header_t));
182
183 hecap_ie->ieee_hdr.element_id = EXTENSION;
184 hecap_ie->ieee_hdr.len =
185 MIN(user_hecap_tlv->len,
186 sizeof(IEEEtypes_HECap_t) - sizeof(IEEEtypes_Header_t));
187 hecap_ie->ext_id = HE_CAPABILITY;
188
189 he_mcsnss = (IEEEtypes_HeMcsNss_t *)hecap_ie->he_txrx_mcs_support;
190
191 for (nss = 1; nss <= 8; nss++) {
192 cfg_value = GET_HE_NSSMCS(user_hecap_tlv->rx_mcs_80, nss);
193 hw_value = GET_HE_NSSMCS(hw_hecap_tlv->rx_mcs_80, nss);
194 if ((hw_value == NO_NSS_SUPPORT) ||
195 (cfg_value == NO_NSS_SUPPORT)) {
196 SET_HE_NSSMCS(he_mcsnss->rx_mcs, nss, NO_NSS_SUPPORT);
197 } else {
198 SET_HE_NSSMCS(he_mcsnss->rx_mcs, nss,
199 MIN(cfg_value, hw_value));
200 }
201 }
202
203 for (nss = 1; nss <= 8; nss++) {
204 cfg_value = GET_HE_NSSMCS(user_hecap_tlv->tx_mcs_80, nss);
205 hw_value = GET_HE_NSSMCS(hw_hecap_tlv->tx_mcs_80, nss);
206
207 if ((hw_value == NO_NSS_SUPPORT) ||
208 (cfg_value == NO_NSS_SUPPORT)) {
209 SET_HE_NSSMCS(he_mcsnss->tx_mcs, nss, NO_NSS_SUPPORT);
210 } else {
211 SET_HE_NSSMCS(he_mcsnss->tx_mcs, nss,
212 MIN(cfg_value, hw_value));
213 }
214 }
215 PRINTM(MCMND,
216 "fill_11ax_ie: HE rx mcs_80 = 0x%08x tx mcs 80 = 0x%08x\n",
217 he_mcsnss->rx_mcs, he_mcsnss->tx_mcs);
218
219 DBG_HEXDUMP(MCMD_D, "fill_11ax_ie", (t_u8 *)hecap_ie,
220 hecap_ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
221 return hecap_ie->ieee_hdr.len;
222 }
223
224 /**
225 * @brief This function fills the HE cap tlv out put format is LE, not CPU
226 *
227 * @param priv A pointer to mlan_private structure
228 * @param phe_cap A pointer to IEEEtypes_HECap_t structure
229 * @param band BAND_A (5G), otherwise, 2.4G
230 *
231 * @return bytes added to the phe_cap
232 */
wlan_fill_he_op_ie(mlan_private * pmpriv,IEEEtypes_HeOp_t * heop_ie)233 t_u8 wlan_fill_he_op_ie(mlan_private *pmpriv, IEEEtypes_HeOp_t *heop_ie)
234 {
235 pmlan_adapter pmadapter = pmpriv->adapter;
236 BSSDescriptor_t *pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
237 IEEEtypes_HeOp_t *bss_heop_ie = MNULL;
238
239 memset(pmadapter, (void *)heop_ie, 0, sizeof(IEEEtypes_HeOp_t));
240
241 heop_ie->ieee_hdr.element_id = EXTENSION;
242 heop_ie->ieee_hdr.len = sizeof(IEEEtypes_HeOp_t) -
243 sizeof(IEEEtypes_Header_t) -
244 sizeof(heop_ie->option);
245 heop_ie->ext_id = HE_OPERATION;
246
247 // HE Operation Parameters
248 heop_ie->he_op_param.default_pe_dur = 7;
249 heop_ie->he_op_param.twt_req = 0;
250 heop_ie->he_op_param.txop_dur_rts_threshold = 12;
251 heop_ie->he_op_param.vht_op_info_present = 0;
252 heop_ie->he_op_param.co_located_bss = 0;
253 heop_ie->he_op_param.er_su_disable = 0;
254 // HE BSS Color Information (following the AP)
255 if (pbss_desc->phe_oprat) {
256 bss_heop_ie = (IEEEtypes_HeOp_t *)(pbss_desc->phe_oprat);
257 heop_ie->bss_color_info.bss_color =
258 bss_heop_ie->bss_color_info.bss_color;
259 } else {
260 // default color
261 heop_ie->bss_color_info.bss_color = 1;
262 }
263 heop_ie->bss_color_info.partial_bss_color = 0;
264 heop_ie->bss_color_info.bss_color_disabled = 0;
265 // Rx HE MCS MAP
266 heop_ie->basic_he_mcs_nss.max_mcs_1ss = 0;
267 #if defined(SD9177)
268 heop_ie->basic_he_mcs_nss.max_mcs_2ss = 3;
269 #else
270 heop_ie->basic_he_mcs_nss.max_mcs_2ss = 0;
271 #endif
272 heop_ie->basic_he_mcs_nss.max_mcs_3ss = 3;
273 heop_ie->basic_he_mcs_nss.max_mcs_4ss = 3;
274 heop_ie->basic_he_mcs_nss.max_mcs_5ss = 3;
275 heop_ie->basic_he_mcs_nss.max_mcs_6ss = 3;
276 heop_ie->basic_he_mcs_nss.max_mcs_7ss = 3;
277 heop_ie->basic_he_mcs_nss.max_mcs_8ss = 3;
278
279 return heop_ie->ieee_hdr.len;
280 }
281
282 /**
283 * @brief This function fills the HE cap tlv out put format is LE, not CPU
284 *
285 * @param priv A pointer to mlan_private structure
286 * @param band 5G or 2.4 G
287 * @param phe_cap A pointer to MrvlIEtypes_Data_t structure
288 * @param flag TREU--pvht_cap has the setting for resp
289 * MFALSE -- pvht_cap is clean
290 *
291 * @return bytes added to the phe_cap
292 */
wlan_fill_he_cap_tlv(mlan_private * pmpriv,t_u16 band,MrvlIEtypes_Extension_t * phe_cap,t_u8 flag)293 t_u16 wlan_fill_he_cap_tlv(mlan_private *pmpriv, t_u16 band,
294 MrvlIEtypes_Extension_t *phe_cap, t_u8 flag)
295 {
296 pmlan_adapter pmadapter = pmpriv->adapter;
297 t_u16 len = 0;
298 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
299 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
300 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
301 t_u16 rx_nss = 0, tx_nss = 0;
302 #endif
303 MrvlIEtypes_He_cap_t *phecap = MNULL;
304 t_u8 nss = 0;
305 t_u16 cfg_value = 0;
306 t_u16 hw_value = 0;
307 MrvlIEtypes_He_cap_t *phw_hecap = MNULL;
308
309 if (!phe_cap) {
310 LEAVE();
311 return 0;
312 }
313 if (band & BAND_AAX) {
314 memcpy_ext(pmadapter, (t_u8 *)phe_cap, pmpriv->user_he_cap,
315 pmpriv->user_hecap_len,
316 sizeof(MrvlIEtypes_He_cap_t));
317 len = pmpriv->user_hecap_len;
318 phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_he_cap;
319 } else {
320 memcpy_ext(pmadapter, (t_u8 *)phe_cap, pmpriv->user_2g_he_cap,
321 pmpriv->user_2g_hecap_len,
322 sizeof(MrvlIEtypes_He_cap_t));
323 len = pmpriv->user_2g_hecap_len;
324 phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_2g_he_cap;
325 }
326 phe_cap->type = wlan_cpu_to_le16(phe_cap->type);
327 phe_cap->len = wlan_cpu_to_le16(phe_cap->len);
328 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
329 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
330 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
331 if (IS_CARD9098(pmpriv->adapter->card_type) ||
332 IS_CARD9097(pmpriv->adapter->card_type)) {
333 if (band & BAND_AAX) {
334 rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream >>
335 8);
336 tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream >>
337 8) &
338 0x0f;
339 } else {
340 rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream);
341 tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream) &
342 0x0f;
343 }
344 }
345 #endif
346 phecap = (MrvlIEtypes_He_cap_t *)phe_cap;
347 for (nss = 1; nss <= 8; nss++) {
348 cfg_value = GET_HE_NSSMCS(phecap->rx_mcs_80, nss);
349 hw_value = GET_HE_NSSMCS(phw_hecap->rx_mcs_80, nss);
350 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
351 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
352 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
353 if ((rx_nss != 0) && (nss > rx_nss))
354 cfg_value = NO_NSS_SUPPORT;
355 #endif
356 if ((hw_value == NO_NSS_SUPPORT) ||
357 (cfg_value == NO_NSS_SUPPORT))
358 SET_HE_NSSMCS(phecap->rx_mcs_80, nss, NO_NSS_SUPPORT);
359 else
360 SET_HE_NSSMCS(phecap->rx_mcs_80, nss,
361 MIN(cfg_value, hw_value));
362 }
363 for (nss = 1; nss <= 8; nss++) {
364 cfg_value = GET_HE_NSSMCS(phecap->tx_mcs_80, nss);
365 hw_value = GET_HE_NSSMCS(phw_hecap->tx_mcs_80, nss);
366 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
367 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
368 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
369 if ((tx_nss != 0) && (nss > tx_nss))
370 cfg_value = NO_NSS_SUPPORT;
371 #endif
372 if ((hw_value == NO_NSS_SUPPORT) ||
373 (cfg_value == NO_NSS_SUPPORT))
374 SET_HE_NSSMCS(phecap->tx_mcs_80, nss, NO_NSS_SUPPORT);
375 else
376 SET_HE_NSSMCS(phecap->tx_mcs_80, nss,
377 MIN(cfg_value, hw_value));
378 }
379 PRINTM(MCMND, "Set: HE rx mcs set 0x%08x tx mcs set 0x%08x\n",
380 phecap->rx_mcs_80, phecap->tx_mcs_80);
381
382 DBG_HEXDUMP(MCMD_D, "fill_11ax_tlv", (t_u8 *)phecap, len);
383 LEAVE();
384 return len;
385 }
386
387 /**
388 * @brief This function append the 802_11ax HE capability tlv
389 *
390 * @param pmpriv A pointer to mlan_private structure
391 * @param pbss_desc A pointer to BSSDescriptor_t structure
392 * @param ppbuffer A Pointer to command buffer pointer
393 *
394 * @return bytes added to the buffer
395 */
wlan_cmd_append_11ax_tlv(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc,t_u8 ** ppbuffer)396 int wlan_cmd_append_11ax_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
397 t_u8 **ppbuffer)
398 {
399 pmlan_adapter pmadapter = pmpriv->adapter;
400 MrvlIEtypes_He_cap_t *phecap = MNULL;
401 int len = 0;
402 t_u8 bw_80p80 = MFALSE;
403 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
404 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
405 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
406 t_u16 rx_nss = 0, tx_nss = 0;
407 #endif
408 t_u8 nss = 0;
409 t_u16 cfg_value = 0;
410 t_u16 hw_value = 0;
411 MrvlIEtypes_He_cap_t *phw_hecap = MNULL;
412 t_u16 band_selected = BAND_A;
413
414 ENTER();
415
416 /* Null Checks */
417 if (ppbuffer == MNULL) {
418 LEAVE();
419 return 0;
420 }
421 if (*ppbuffer == MNULL) {
422 LEAVE();
423 return 0;
424 }
425 /** check if AP support HE, if not return right away */
426 if (!pbss_desc->phe_cap) {
427 LEAVE();
428 return 0;
429 }
430 bw_80p80 = wlan_is_80_80_support(pmpriv, pbss_desc);
431 phecap = (MrvlIEtypes_He_cap_t *)*ppbuffer;
432 if (pbss_desc->bss_band & band_selected) {
433 memcpy_ext(pmadapter, *ppbuffer, pmpriv->user_he_cap,
434 pmpriv->user_hecap_len, pmpriv->user_hecap_len);
435 *ppbuffer += pmpriv->user_hecap_len;
436 len = pmpriv->user_hecap_len;
437 phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_he_cap;
438 } else {
439 memcpy_ext(pmadapter, *ppbuffer, pmpriv->user_2g_he_cap,
440 pmpriv->user_2g_hecap_len,
441 pmpriv->user_2g_hecap_len);
442 *ppbuffer += pmpriv->user_2g_hecap_len;
443 len = pmpriv->user_2g_hecap_len;
444 phw_hecap = (MrvlIEtypes_He_cap_t *)pmadapter->hw_2g_he_cap;
445 }
446 phecap->type = wlan_cpu_to_le16(phecap->type);
447 phecap->len = wlan_cpu_to_le16(phecap->len);
448 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
449 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
450 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
451 if (IS_CARD9098(pmpriv->adapter->card_type) ||
452 IS_CARDNW62X(pmpriv->adapter->card_type) ||
453 IS_CARD9097(pmpriv->adapter->card_type)) {
454 if (pbss_desc->bss_band & band_selected) {
455 rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream >>
456 8);
457 tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream >>
458 8) &
459 0x0f;
460 } else {
461 rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream);
462 tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream) &
463 0x0f;
464 }
465 /** force 1x1 when enable 80P80 */
466 if (bw_80p80)
467 rx_nss = tx_nss = 1;
468 }
469 #endif
470 for (nss = 1; nss <= 8; nss++) {
471 cfg_value = GET_HE_NSSMCS(phecap->rx_mcs_80, nss);
472 hw_value = GET_HE_NSSMCS(phw_hecap->rx_mcs_80, nss);
473 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
474 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
475 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
476 if ((rx_nss != 0) && (nss > rx_nss))
477 cfg_value = NO_NSS_SUPPORT;
478 #endif
479 if ((hw_value == NO_NSS_SUPPORT) ||
480 (cfg_value == NO_NSS_SUPPORT))
481 SET_HE_NSSMCS(phecap->rx_mcs_80, nss, NO_NSS_SUPPORT);
482 else
483 SET_HE_NSSMCS(phecap->rx_mcs_80, nss,
484 MIN(cfg_value, hw_value));
485 }
486 for (nss = 1; nss <= 8; nss++) {
487 cfg_value = GET_HE_NSSMCS(phecap->tx_mcs_80, nss);
488 hw_value = GET_HE_NSSMCS(phw_hecap->tx_mcs_80, nss);
489 #if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
490 defined(PCIE9097) || defined(SD9097) || defined(USB9097) || \
491 defined(SDNW62X) || defined(PCIENW62X) || defined(USBNW62X)
492 if ((tx_nss != 0) && (nss > tx_nss))
493 cfg_value = NO_NSS_SUPPORT;
494 #endif
495 if ((hw_value == NO_NSS_SUPPORT) ||
496 (cfg_value == NO_NSS_SUPPORT))
497 SET_HE_NSSMCS(phecap->tx_mcs_80, nss, NO_NSS_SUPPORT);
498 else
499 SET_HE_NSSMCS(phecap->tx_mcs_80, nss,
500 MIN(cfg_value, hw_value));
501 }
502 PRINTM(MCMND, "Set: HE rx mcs set 0x%08x tx mcs set 0x%08x\n",
503 phecap->rx_mcs_80, phecap->tx_mcs_80);
504 if (!bw_80p80) {
505 /** reset BIT3 and BIT4 channel width ,not support 80 + 80*/
506 /** not support 160Mhz now, if support,not reset bit3 */
507 phecap->he_phy_cap[0] &= ~(MBIT(3) | MBIT(4));
508 }
509 DBG_HEXDUMP(MCMD_D, "append_11ax_tlv", (t_u8 *)phecap, len);
510
511 LEAVE();
512 return len;
513 }
514
515 /**
516 * @brief This function save the 11ax cap from FW.
517 *
518 * @param pmadapater A pointer to mlan_adapter
519 * @param hw_he_cap A pointer to MrvlIEtypes_Extension_t
520 *
521 * @return N/A
522 */
wlan_update_11ax_cap(mlan_adapter * pmadapter,MrvlIEtypes_Extension_t * hw_he_cap)523 void wlan_update_11ax_cap(mlan_adapter *pmadapter,
524 MrvlIEtypes_Extension_t *hw_he_cap)
525 {
526 MrvlIEtypes_He_cap_t *phe_cap = MNULL;
527 t_u8 i = 0;
528 t_u8 he_cap_2g = 0;
529 MrvlIEtypes_He_cap_t *user_he_cap_tlv = MNULL;
530
531 ENTER();
532 if ((hw_he_cap->len + sizeof(MrvlIEtypesHeader_t)) >
533 sizeof(pmadapter->hw_he_cap)) {
534 PRINTM(MERROR, "hw_he_cap too big, len=%d\n", hw_he_cap->len);
535 LEAVE();
536 return;
537 }
538 phe_cap = (MrvlIEtypes_He_cap_t *)hw_he_cap;
539 if (phe_cap->he_phy_cap[0] &
540 (AX_2G_40MHZ_SUPPORT | AX_2G_20MHZ_SUPPORT)) {
541 pmadapter->hw_2g_hecap_len =
542 hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
543 memcpy_ext(pmadapter, pmadapter->hw_2g_he_cap,
544 (t_u8 *)hw_he_cap,
545 hw_he_cap->len + sizeof(MrvlIEtypesHeader_t),
546 sizeof(pmadapter->hw_2g_he_cap));
547 pmadapter->fw_bands |= BAND_GAX;
548 pmadapter->config_bands |= BAND_GAX;
549 he_cap_2g = MTRUE;
550 DBG_HEXDUMP(MCMD_D, "2.4G HE capability IE ",
551 (t_u8 *)pmadapter->hw_2g_he_cap,
552 pmadapter->hw_2g_hecap_len);
553 } else {
554 pmadapter->fw_bands |= BAND_AAX;
555 pmadapter->config_bands |= BAND_AAX;
556 pmadapter->hw_hecap_len =
557 hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
558 memcpy_ext(pmadapter, pmadapter->hw_he_cap, (t_u8 *)hw_he_cap,
559 hw_he_cap->len + sizeof(MrvlIEtypesHeader_t),
560 sizeof(pmadapter->hw_he_cap));
561 DBG_HEXDUMP(MCMD_D, "5G HE capability IE ",
562 (t_u8 *)pmadapter->hw_he_cap,
563 pmadapter->hw_hecap_len);
564 }
565 for (i = 0; i < pmadapter->priv_num; i++) {
566 if (pmadapter->priv[i]) {
567 pmadapter->priv[i]->config_bands =
568 pmadapter->config_bands;
569 if (he_cap_2g) {
570 pmadapter->priv[i]->user_2g_hecap_len =
571 pmadapter->hw_2g_hecap_len;
572 memcpy_ext(pmadapter,
573 pmadapter->priv[i]->user_2g_he_cap,
574 pmadapter->hw_2g_he_cap,
575 pmadapter->hw_2g_hecap_len,
576 sizeof(pmadapter->priv[i]
577 ->user_2g_he_cap));
578 } else {
579 pmadapter->priv[i]->user_hecap_len =
580 pmadapter->hw_hecap_len;
581 memcpy_ext(
582 pmadapter,
583 pmadapter->priv[i]->user_he_cap,
584 pmadapter->hw_he_cap,
585 pmadapter->hw_hecap_len,
586 sizeof(pmadapter->priv[i]->user_he_cap));
587 }
588 /**
589 * Clear TWT bits in he_mac_cap by bss role
590 * STA mode should clear TWT responder bit
591 * UAP mode should clear TWT request bit
592 */
593 if (he_cap_2g)
594 user_he_cap_tlv =
595 (MrvlIEtypes_He_cap_t *)&pmadapter
596 ->priv[i]
597 ->user_2g_he_cap;
598 else
599 user_he_cap_tlv =
600 (MrvlIEtypes_He_cap_t *)&pmadapter
601 ->priv[i]
602 ->user_he_cap;
603
604 if (pmadapter->priv[i]->bss_role == MLAN_BSS_ROLE_STA)
605 user_he_cap_tlv->he_mac_cap[0] &=
606 ~HE_MAC_CAP_TWT_RESP_SUPPORT;
607 else
608 user_he_cap_tlv->he_mac_cap[0] &=
609 ~HE_MAC_CAP_TWT_REQ_SUPPORT;
610 }
611 }
612 LEAVE();
613 return;
614 }
615
616 /**
617 * @brief This function check if 11AX is allowed in bandcfg
618 *
619 * @param pmpriv A pointer to mlan_private structure
620 * @param pbss_desc A pointer to BSSDescriptor_t
621 *
622 * @return 0--not allowed, other value allowed
623 */
wlan_11ax_bandconfig_allowed(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc)624 t_u16 wlan_11ax_bandconfig_allowed(mlan_private *pmpriv,
625 BSSDescriptor_t *pbss_desc)
626 {
627 t_u16 bss_band = pbss_desc->bss_band;
628 if (pbss_desc->disable_11n)
629 return MFALSE;
630 if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
631 if (bss_band & BAND_G)
632 return (pmpriv->adapter->adhoc_start_band & BAND_GAX);
633 else if (bss_band & BAND_A)
634 return (pmpriv->adapter->adhoc_start_band & BAND_AAX);
635 } else {
636 if (bss_band & BAND_G)
637 return (pmpriv->config_bands & BAND_GAX);
638 else if (bss_band & BAND_A)
639 return (pmpriv->config_bands & BAND_AAX);
640 }
641 return MFALSE;
642 }
643
644 /**
645 * @brief Set 11ax configuration
646 *
647 * @param pmadapter A pointer to mlan_adapter structure
648 * @param pioctl_req A pointer to ioctl request buffer
649 *
650 * @return MLAN_STATUS_PENDING --success, otherwise fail
651 */
wlan_11ax_ioctl_hecfg(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)652 static mlan_status wlan_11ax_ioctl_hecfg(pmlan_adapter pmadapter,
653 pmlan_ioctl_req pioctl_req)
654 {
655 mlan_status ret = MLAN_STATUS_SUCCESS;
656 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
657 mlan_ds_11ax_cfg *cfg = MNULL;
658 t_u16 cmd_action = 0;
659
660 ENTER();
661
662 cfg = (mlan_ds_11ax_cfg *)pioctl_req->pbuf;
663
664 if ((cfg->param.he_cfg.band & MBIT(0)) &&
665 !(pmadapter->fw_bands & BAND_GAX)) {
666 PRINTM(MERROR, "FW don't support 2.4G AX\n");
667 return MLAN_STATUS_FAILURE;
668 }
669 if ((cfg->param.he_cfg.band & MBIT(1)) &&
670 !(pmadapter->fw_bands & BAND_AAX)) {
671 PRINTM(MERROR, "FW don't support 5G AX\n");
672 return MLAN_STATUS_FAILURE;
673 }
674 if (pioctl_req->action == MLAN_ACT_SET)
675 cmd_action = HostCmd_ACT_GEN_SET;
676 else
677 cmd_action = HostCmd_ACT_GEN_GET;
678
679 /* Send request to firmware */
680 ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AX_CFG, cmd_action, 0,
681 (t_void *)pioctl_req,
682 (t_void *)&cfg->param.he_cfg);
683 if (ret == MLAN_STATUS_SUCCESS)
684 ret = MLAN_STATUS_PENDING;
685
686 LEAVE();
687 return ret;
688 }
689
690 /**
691 * @brief 11ax configuration handler
692 *
693 * @param pmadapter A pointer to mlan_adapter structure
694 * @param pioctl_req A pointer to ioctl request buffer
695 *
696 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
697 */
wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)698 mlan_status wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter,
699 pmlan_ioctl_req pioctl_req)
700 {
701 mlan_status status = MLAN_STATUS_SUCCESS;
702 mlan_ds_11ax_cfg *cfg = MNULL;
703
704 ENTER();
705
706 cfg = (mlan_ds_11ax_cfg *)pioctl_req->pbuf;
707 switch (cfg->sub_command) {
708 case MLAN_OID_11AX_HE_CFG:
709 status = wlan_11ax_ioctl_hecfg(pmadapter, pioctl_req);
710 break;
711 case MLAN_OID_11AX_CMD_CFG:
712 status = wlan_11ax_ioctl_cmd(pmadapter, pioctl_req);
713 break;
714 case MLAN_OID_11AX_TWT_CFG:
715 status = wlan_11ax_ioctl_twtcfg(pmadapter, pioctl_req);
716 break;
717 default:
718 pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
719 status = MLAN_STATUS_FAILURE;
720 break;
721 }
722 LEAVE();
723 return status;
724 }
725
726 /**
727 * @brief This function prepares 11ax cfg command
728 *
729 * @param pmpriv A pointer to mlan_private structure
730 * @param cmd A pointer to HostCmd_DS_COMMAND structure
731 * @param cmd_action the action: GET or SET
732 * @param pdata_buf A pointer to data buffer
733 * @return MLAN_STATUS_SUCCESS
734 */
wlan_cmd_11ax_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)735 mlan_status wlan_cmd_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
736 t_u16 cmd_action, t_void *pdata_buf)
737 {
738 pmlan_adapter pmadapter = pmpriv->adapter;
739 HostCmd_DS_11AX_CFG *axcfg = &cmd->params.axcfg;
740 mlan_ds_11ax_he_cfg *hecfg = (mlan_ds_11ax_he_cfg *)pdata_buf;
741 MrvlIEtypes_Extension_t *tlv = MNULL;
742 t_u8 *pos = MNULL;
743
744 ENTER();
745 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AX_CFG);
746 cmd->size = sizeof(HostCmd_DS_11AX_CFG) + S_DS_GEN;
747
748 axcfg->action = wlan_cpu_to_le16(cmd_action);
749 axcfg->band_config = hecfg->band & 0xFF;
750
751 pos = (t_u8 *)axcfg->val;
752 /**HE Capability */
753 if (hecfg->he_cap.len && (hecfg->he_cap.ext_id == HE_CAPABILITY)) {
754 tlv = (MrvlIEtypes_Extension_t *)pos;
755 tlv->type = wlan_cpu_to_le16(hecfg->he_cap.id);
756 tlv->len = wlan_cpu_to_le16(hecfg->he_cap.len);
757 memcpy_ext(pmadapter, &tlv->ext_id, &hecfg->he_cap.ext_id,
758 hecfg->he_cap.len,
759 MRVDRV_SIZE_OF_CMD_BUFFER - cmd->size);
760 cmd->size += hecfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
761 pos += hecfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
762 }
763 cmd->size = wlan_cpu_to_le16(cmd->size);
764
765 LEAVE();
766 return MLAN_STATUS_SUCCESS;
767 }
768 /**
769 * @brief This function handles the command response of 11axcfg
770 *
771 * @param pmpriv A pointer to mlan_private structure
772 * @param resp A pointer to HostCmd_DS_COMMAND
773 * @param pioctl_buf A pointer to mlan_ioctl_req structure
774 *
775 * @return MLAN_STATUS_SUCCESS
776 */
wlan_ret_11ax_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)777 mlan_status wlan_ret_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
778 mlan_ioctl_req *pioctl_buf)
779 {
780 pmlan_adapter pmadapter = pmpriv->adapter;
781 mlan_ds_11ax_cfg *cfg = MNULL;
782 mlan_ds_11ax_he_capa *hecap = MNULL;
783 HostCmd_DS_11AX_CFG *axcfg = &resp->params.axcfg;
784 MrvlIEtypes_Extension_t *tlv = MNULL;
785 t_u16 left_len = 0, tlv_type = 0, tlv_len = 0;
786
787 ENTER();
788
789 if (pioctl_buf == MNULL)
790 goto done;
791
792 cfg = (mlan_ds_11ax_cfg *)pioctl_buf->pbuf;
793 cfg->param.he_cfg.band = axcfg->band_config;
794 hecap = (mlan_ds_11ax_he_capa *)&cfg->param.he_cfg.he_cap;
795
796 /* TLV parse */
797 left_len = resp->size - sizeof(HostCmd_DS_11AX_CFG) - S_DS_GEN;
798 tlv = (MrvlIEtypes_Extension_t *)axcfg->val;
799
800 while (left_len > sizeof(MrvlIEtypesHeader_t)) {
801 tlv_type = wlan_le16_to_cpu(tlv->type);
802 tlv_len = wlan_le16_to_cpu(tlv->len);
803 if (tlv_type == EXTENSION) {
804 switch (tlv->ext_id) {
805 case HE_CAPABILITY:
806 hecap->id = tlv_type;
807 hecap->len = tlv_len;
808 memcpy_ext(pmadapter, (t_u8 *)&hecap->ext_id,
809 (t_u8 *)&tlv->ext_id, tlv_len,
810 sizeof(mlan_ds_11ax_he_capa) -
811 sizeof(MrvlIEtypesHeader_t));
812 if (cfg->param.he_cfg.band & MBIT(1)) {
813 memcpy_ext(
814 pmadapter,
815 (t_u8 *)&pmpriv->user_he_cap,
816 (t_u8 *)tlv,
817 tlv_len +
818 sizeof(MrvlIEtypesHeader_t),
819 sizeof(pmpriv->user_he_cap));
820 pmpriv->user_hecap_len = MIN(
821 tlv_len +
822 sizeof(MrvlIEtypesHeader_t),
823 sizeof(pmpriv->user_he_cap));
824 PRINTM(MCMND, "user_hecap_len=%d\n",
825 pmpriv->user_hecap_len);
826 } else {
827 memcpy_ext(
828 pmadapter,
829 (t_u8 *)&pmpriv->user_2g_he_cap,
830 (t_u8 *)tlv,
831 tlv_len +
832 sizeof(MrvlIEtypesHeader_t),
833 sizeof(pmpriv->user_2g_he_cap));
834 pmpriv->user_2g_hecap_len = MIN(
835 tlv_len +
836 sizeof(MrvlIEtypesHeader_t),
837 sizeof(pmpriv->user_2g_he_cap));
838 PRINTM(MCMND, "user_2g_hecap_len=%d\n",
839 pmpriv->user_2g_hecap_len);
840 }
841 break;
842 default:
843 break;
844 }
845 }
846
847 left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
848 tlv = (MrvlIEtypes_Extension_t *)((t_u8 *)tlv + tlv_len +
849 sizeof(MrvlIEtypesHeader_t));
850 }
851
852 done:
853 LEAVE();
854 return MLAN_STATUS_SUCCESS;
855 }
856
857 /**
858 * @brief 11ax command handler
859 *
860 * @param pmadapter A pointer to mlan_adapter structure
861 * @param pioctl_req A pointer to ioctl request buffer
862 *
863 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
864 */
wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)865 mlan_status wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter,
866 pmlan_ioctl_req pioctl_req)
867 {
868 mlan_status status = MLAN_STATUS_SUCCESS;
869 mlan_ds_11ax_cmd_cfg *cfg = MNULL;
870 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
871 t_u16 cmd_action = 0;
872
873 ENTER();
874
875 if (pioctl_req->buf_len < sizeof(mlan_ds_11ax_cmd_cfg)) {
876 PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
877 pioctl_req->data_read_written = 0;
878 pioctl_req->buf_len_needed = sizeof(mlan_ds_11ax_cmd_cfg);
879 pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
880 LEAVE();
881 return MLAN_STATUS_RESOURCE;
882 }
883 cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_req->pbuf;
884
885 if (pioctl_req->action == MLAN_ACT_SET)
886 cmd_action = HostCmd_ACT_GEN_SET;
887 else
888 cmd_action = HostCmd_ACT_GEN_GET;
889
890 /* Send request to firmware */
891 status = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AX_CMD, cmd_action, 0,
892 (t_void *)pioctl_req, (t_void *)cfg);
893 if (status == MLAN_STATUS_SUCCESS)
894 status = MLAN_STATUS_PENDING;
895
896 LEAVE();
897 return status;
898 }
899
900 /**
901 * @brief This function prepares 11ax command
902 *
903 * @param pmpriv A pointer to mlan_private structure
904 * @param cmd A pointer to HostCmd_DS_COMMAND structure
905 * @param cmd_action the action: GET or SET
906 * @param pdata_buf A pointer to data buffer
907 * @return MLAN_STATUS_SUCCESS
908 */
wlan_cmd_11ax_cmd(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)909 mlan_status wlan_cmd_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
910 t_u16 cmd_action, t_void *pdata_buf)
911 {
912 pmlan_adapter pmadapter = pmpriv->adapter;
913 HostCmd_DS_11AX_CMD_CFG *axcmd = &cmd->params.axcmd;
914 mlan_ds_11ax_cmd_cfg *ds_11ax_cmd = (mlan_ds_11ax_cmd_cfg *)pdata_buf;
915 mlan_ds_11ax_sr_cmd *sr_cmd =
916 (mlan_ds_11ax_sr_cmd *)&ds_11ax_cmd->param;
917 mlan_ds_11ax_beam_cmd *beam_cmd =
918 (mlan_ds_11ax_beam_cmd *)&ds_11ax_cmd->param;
919 mlan_ds_11ax_htc_cmd *htc_cmd =
920 (mlan_ds_11ax_htc_cmd *)&ds_11ax_cmd->param;
921 mlan_ds_11ax_txop_cmd *txop_cmd =
922 (mlan_ds_11ax_txop_cmd *)&ds_11ax_cmd->param;
923 mlan_ds_11ax_txomi_cmd *txomi_cmd =
924 (mlan_ds_11ax_txomi_cmd *)&ds_11ax_cmd->param;
925 mlan_ds_11ax_toltime_cmd *toltime_cmd =
926 (mlan_ds_11ax_toltime_cmd *)&ds_11ax_cmd->param;
927 MrvlIEtypes_Data_t *tlv = MNULL;
928
929 ENTER();
930 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AX_CMD);
931 cmd->size = sizeof(HostCmd_DS_11AX_CMD_CFG) + S_DS_GEN;
932
933 axcmd->action = wlan_cpu_to_le16(cmd_action);
934 axcmd->sub_id = wlan_cpu_to_le16(ds_11ax_cmd->sub_id);
935 switch (ds_11ax_cmd->sub_id) {
936 case MLAN_11AXCMD_SR_SUBID:
937 tlv = (MrvlIEtypes_Data_t *)axcmd->val;
938 tlv->header.type = wlan_cpu_to_le16(sr_cmd->type);
939 tlv->header.len = wlan_cpu_to_le16(sr_cmd->len);
940 memcpy_ext(pmadapter, tlv->data,
941 &sr_cmd->param.obss_pd_offset.offset, sr_cmd->len,
942 sr_cmd->len);
943 cmd->size += sizeof(MrvlIEtypesHeader_t) + sr_cmd->len;
944 break;
945 case MLAN_11AXCMD_BEAM_SUBID:
946 axcmd->val[0] = beam_cmd->value;
947 cmd->size += sizeof(t_u8);
948 break;
949 case MLAN_11AXCMD_HTC_SUBID:
950 axcmd->val[0] = htc_cmd->value;
951 cmd->size += sizeof(t_u8);
952 break;
953 case MLAN_11AXCMD_TXOPRTS_SUBID:
954 memcpy_ext(pmadapter, axcmd->val, &txop_cmd->rts_thres,
955 sizeof(t_u16), sizeof(t_u16));
956 cmd->size += sizeof(t_u16);
957 break;
958 case MLAN_11AXCMD_TXOMI_SUBID:
959 memcpy_ext(pmadapter, axcmd->val, &txomi_cmd->omi,
960 sizeof(t_u16), sizeof(t_u16));
961 cmd->size += sizeof(t_u16);
962 break;
963 case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
964 memcpy_ext(pmadapter, axcmd->val, &toltime_cmd->tol_time,
965 sizeof(t_u32), sizeof(t_u32));
966 cmd->size += sizeof(t_u32);
967 break;
968 default:
969 PRINTM(MERROR, "Unknown subcmd %x\n", ds_11ax_cmd->sub_id);
970 break;
971 }
972
973 cmd->size = wlan_cpu_to_le16(cmd->size);
974
975 LEAVE();
976 return MLAN_STATUS_SUCCESS;
977 }
978
979 /**
980 * @brief This function handles the command response of 11axcmd
981 *
982 * @param pmpriv A pointer to mlan_private structure
983 * @param resp A pointer to HostCmd_DS_COMMAND
984 * @param pioctl_buf A pointer to mlan_ioctl_req structure
985 *
986 * @return MLAN_STATUS_SUCCESS
987 */
wlan_ret_11ax_cmd(pmlan_private pmpriv,HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)988 mlan_status wlan_ret_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
989 mlan_ioctl_req *pioctl_buf)
990 {
991 pmlan_adapter pmadapter = pmpriv->adapter;
992 mlan_ds_11ax_cmd_cfg *cfg = MNULL;
993 HostCmd_DS_11AX_CMD_CFG *axcmd = &resp->params.axcmd;
994 MrvlIEtypes_Data_t *tlv = MNULL;
995 t_s16 left_len = 0;
996 t_u16 tlv_len = 0;
997
998 ENTER();
999
1000 if (pioctl_buf == MNULL)
1001 goto done;
1002
1003 cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_buf->pbuf;
1004 cfg->sub_id = wlan_le16_to_cpu(axcmd->sub_id);
1005
1006 switch (axcmd->sub_id) {
1007 case MLAN_11AXCMD_SR_SUBID:
1008 /* TLV parse */
1009 left_len =
1010 resp->size - sizeof(HostCmd_DS_11AX_CMD_CFG) - S_DS_GEN;
1011 // tlv = (MrvlIEtypes_Extension_t *)axcfg->val;
1012 tlv = (MrvlIEtypes_Data_t *)axcmd->val;
1013 while (left_len > (t_s16)sizeof(MrvlIEtypesHeader_t)) {
1014 tlv_len = wlan_le16_to_cpu(tlv->header.len);
1015 memcpy_ext(
1016 pmadapter,
1017 cfg->param.sr_cfg.param.obss_pd_offset.offset,
1018 tlv->data, tlv_len, tlv_len);
1019 left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
1020 tlv = (MrvlIEtypes_Data_t
1021 *)((t_u8 *)tlv + tlv_len +
1022 sizeof(MrvlIEtypesHeader_t));
1023 }
1024 break;
1025 case MLAN_11AXCMD_BEAM_SUBID:
1026 cfg->param.beam_cfg.value = *axcmd->val;
1027 break;
1028 case MLAN_11AXCMD_HTC_SUBID:
1029 cfg->param.htc_cfg.value = *axcmd->val;
1030 break;
1031 case MLAN_11AXCMD_TXOPRTS_SUBID:
1032 memcpy_ext(pmadapter, &cfg->param.txop_cfg.rts_thres,
1033 axcmd->val, sizeof(t_u16), sizeof(t_u16));
1034 break;
1035 case MLAN_11AXCMD_TXOMI_SUBID:
1036 memcpy_ext(pmadapter, &cfg->param.txomi_cfg.omi, axcmd->val,
1037 sizeof(t_u16), sizeof(t_u16));
1038 break;
1039 case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
1040 memcpy_ext(pmadapter, &cfg->param.toltime_cfg.tol_time,
1041 axcmd->val, sizeof(t_u32), sizeof(t_u32));
1042 break;
1043 default:
1044 PRINTM(MERROR, "Unknown subcmd %x\n", axcmd->sub_id);
1045 break;
1046 }
1047
1048 done:
1049 LEAVE();
1050 return MLAN_STATUS_SUCCESS;
1051 }
1052
1053 /**
1054 * @brief This function prepares TWT cfg command to configure
1055 * setup/teardown
1056 *
1057 * @param pmpriv A pointer to mlan_private structure
1058 * @param cmd A pointer to HostCmd_DS_COMMAND structure
1059 * @param cmd_action The action: GET or SET
1060 * @param pdata_buf A pointer to data buffer
1061 * @return Status returned
1062 */
wlan_cmd_twt_cfg(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)1063 mlan_status wlan_cmd_twt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
1064 t_u16 cmd_action, t_void *pdata_buf)
1065 {
1066 pmlan_adapter pmadapter = pmpriv->adapter;
1067 HostCmd_DS_TWT_CFG *hostcmd_twtcfg =
1068 (HostCmd_DS_TWT_CFG *)&cmd->params.twtcfg;
1069 mlan_ds_twtcfg *ds_twtcfg = (mlan_ds_twtcfg *)pdata_buf;
1070 hostcmd_twt_setup *twt_setup_params = MNULL;
1071 hostcmd_twt_teardown *twt_teardown_params = MNULL;
1072 mlan_status ret = MLAN_STATUS_SUCCESS;
1073
1074 ENTER();
1075 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TWT_CFG);
1076
1077 hostcmd_twtcfg->action = wlan_cpu_to_le16(cmd_action);
1078 hostcmd_twtcfg->sub_id = wlan_cpu_to_le16(ds_twtcfg->sub_id);
1079
1080 cmd->size = S_DS_GEN + sizeof(hostcmd_twtcfg->action) +
1081 sizeof(hostcmd_twtcfg->sub_id);
1082
1083 switch (hostcmd_twtcfg->sub_id) {
1084 case MLAN_11AX_TWT_SETUP_SUBID:
1085 twt_setup_params = &hostcmd_twtcfg->param.twt_setup;
1086 memset(pmadapter, twt_setup_params, 0x00,
1087 sizeof(hostcmd_twtcfg->param.twt_setup));
1088 twt_setup_params->implicit =
1089 ds_twtcfg->param.twt_setup.implicit;
1090 twt_setup_params->announced =
1091 ds_twtcfg->param.twt_setup.announced;
1092 twt_setup_params->trigger_enabled =
1093 ds_twtcfg->param.twt_setup.trigger_enabled;
1094 twt_setup_params->twt_info_disabled =
1095 ds_twtcfg->param.twt_setup.twt_info_disabled;
1096 twt_setup_params->negotiation_type =
1097 ds_twtcfg->param.twt_setup.negotiation_type;
1098 twt_setup_params->twt_wakeup_duration =
1099 ds_twtcfg->param.twt_setup.twt_wakeup_duration;
1100 twt_setup_params->flow_identifier =
1101 ds_twtcfg->param.twt_setup.flow_identifier;
1102 twt_setup_params->hard_constraint =
1103 ds_twtcfg->param.twt_setup.hard_constraint;
1104 twt_setup_params->twt_exponent =
1105 ds_twtcfg->param.twt_setup.twt_exponent;
1106 twt_setup_params->twt_mantissa = wlan_cpu_to_le16(
1107 ds_twtcfg->param.twt_setup.twt_mantissa);
1108 twt_setup_params->twt_request =
1109 ds_twtcfg->param.twt_setup.twt_request;
1110 cmd->size += sizeof(hostcmd_twtcfg->param.twt_setup);
1111 break;
1112 case MLAN_11AX_TWT_TEARDOWN_SUBID:
1113 twt_teardown_params = &hostcmd_twtcfg->param.twt_teardown;
1114 memset(pmadapter, twt_teardown_params, 0x00,
1115 sizeof(hostcmd_twtcfg->param.twt_teardown));
1116 twt_teardown_params->flow_identifier =
1117 ds_twtcfg->param.twt_teardown.flow_identifier;
1118 twt_teardown_params->negotiation_type =
1119 ds_twtcfg->param.twt_teardown.negotiation_type;
1120 twt_teardown_params->teardown_all_twt =
1121 ds_twtcfg->param.twt_teardown.teardown_all_twt;
1122 cmd->size += sizeof(hostcmd_twtcfg->param.twt_teardown);
1123 break;
1124 default:
1125 PRINTM(MERROR, "Unknown subcmd %x\n", ds_twtcfg->sub_id);
1126 ret = MLAN_STATUS_FAILURE;
1127 break;
1128 }
1129
1130 cmd->size = wlan_cpu_to_le16(cmd->size);
1131
1132 LEAVE();
1133 return ret;
1134 }
1135
1136 /**
1137 * @brief TWT config command handler
1138 *
1139 * @param pmadapter A pointer to mlan_adapter structure
1140 * @param pioctl_req A pointer to ioctl request buffer
1141 *
1142 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
1143 */
wlan_11ax_ioctl_twtcfg(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)1144 mlan_status wlan_11ax_ioctl_twtcfg(pmlan_adapter pmadapter,
1145 pmlan_ioctl_req pioctl_req)
1146 {
1147 mlan_status ret = MLAN_STATUS_SUCCESS;
1148 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
1149 mlan_ds_twtcfg *cfg = MNULL;
1150 t_u16 cmd_action = 0;
1151
1152 ENTER();
1153
1154 if (pioctl_req->buf_len < sizeof(mlan_ds_twtcfg)) {
1155 PRINTM(MERROR, "MLAN bss IOCTL length is too short.\n");
1156 pioctl_req->data_read_written = 0;
1157 pioctl_req->buf_len_needed = sizeof(mlan_ds_twtcfg);
1158 pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
1159 LEAVE();
1160 return MLAN_STATUS_RESOURCE;
1161 }
1162
1163 cfg = (mlan_ds_twtcfg *)pioctl_req->pbuf;
1164
1165 if (pioctl_req->action == MLAN_ACT_SET)
1166 cmd_action = HostCmd_ACT_GEN_SET;
1167 else
1168 cmd_action = HostCmd_ACT_GEN_GET;
1169
1170 /* Send request to firmware */
1171 ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TWT_CFG, cmd_action, 0,
1172 (t_void *)pioctl_req, (t_void *)cfg);
1173 if (ret == MLAN_STATUS_SUCCESS)
1174 ret = MLAN_STATUS_PENDING;
1175
1176 LEAVE();
1177 return ret;
1178 }
1179