1 /** @file mlan_11n.c
2 *
3 * @brief This file provides functions for 11n handling.
4 *
5 * Copyright 2008-2024 NXP
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 /********************************************************
12 Change log:
13 11/10/2008: initial version
14 ********************************************************/
15
16 #include <mlan_api.h>
17
18 /* Additional WMSDK header files */
19 #include <wmerrno.h>
20 #include <osa.h>
21
22 /* Always keep this include at the end of all include files */
23 #include <mlan_remap_mem_operations.h>
24 /********************************************************
25 Local Variables
26 ********************************************************/
27
28 /********************************************************
29 Global Variables
30 ********************************************************/
31
32 /********************************************************
33 Local Functions
34 ********************************************************/
35
36 /* Disable the optional features of 11N */
37 #undef _80211n_OPT_FEATURES
38
39 #ifdef _80211n_OPT_FEATURES
40 #define _80211_HT_GREENFIELD
41 #define _80211_HT_SHORTGI20
42 #define _80211_HT_SHORTGI40
43 #define _80211_HT_RXSTBC
44 #define _80211_HT_MCS32
45 #endif
46
47 /**
48 * @brief Set/get htcapinfo configuration
49 *
50 * @param pmadapter A pointer to mlan_adapter structure
51 * @param pioctl_req A pointer to ioctl request buffer
52 *
53 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
54 */
wlan_11n_ioctl_htusrcfg(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)55 static mlan_status wlan_11n_ioctl_htusrcfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
56 {
57 mlan_status ret = MLAN_STATUS_SUCCESS;
58 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
59 mlan_ds_11n_cfg *cfg = MNULL;
60
61 ENTER();
62
63 cfg = (mlan_ds_11n_cfg *)(void *)pioctl_req->pbuf;
64
65 if (pioctl_req->action == MLAN_ACT_SET)
66 {
67 if (((cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP) & pmpriv->adapter->hw_dot_11n_dev_cap) !=
68 (cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP))
69 {
70 pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
71 ret = MLAN_STATUS_FAILURE;
72 }
73 else
74 {
75 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG)
76 {
77 pmadapter->usr_dot_11n_dev_cap_bg = cfg->param.htcap_cfg.htcap;
78 PRINTM(MINFO, "Set: UsrDot11nCap for 2.4GHz 0x%x\n", pmadapter->usr_dot_11n_dev_cap_bg);
79 }
80 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A)
81 {
82 pmadapter->usr_dot_11n_dev_cap_a = cfg->param.htcap_cfg.htcap;
83 PRINTM(MINFO, "Set: UsrDot11nCap for 5GHz 0x%x\n", pmadapter->usr_dot_11n_dev_cap_a);
84 }
85 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BOTH)
86 {
87 pmadapter->usr_dot_11n_dev_cap_bg = cfg->param.htcap_cfg.htcap;
88 pmadapter->usr_dot_11n_dev_cap_a = cfg->param.htcap_cfg.htcap;
89 PRINTM(MINFO, "Set: UsrDot11nCap for 2.4GHz and 5GHz 0x%x\n", cfg->param.htcap_cfg.htcap);
90 }
91 }
92 }
93 else
94 {
95 /* Hardware 11N device capability required */
96 if (cfg->param.htcap_cfg.hw_cap_req != 0U)
97 {
98 cfg->param.htcap_cfg.htcap = pmadapter->hw_dot_11n_dev_cap;
99 }
100 else
101 {
102 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG)
103 {
104 cfg->param.htcap_cfg.htcap = pmadapter->usr_dot_11n_dev_cap_bg;
105 PRINTM(MINFO, "Get: UsrDot11nCap for 2.4GHz 0x%x\n", cfg->param.htcap_cfg.htcap);
106 }
107 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A)
108 {
109 cfg->param.htcap_cfg.htcap = pmadapter->usr_dot_11n_dev_cap_a;
110 PRINTM(MINFO, "Get: UsrDot11nCap for 5GHz 0x%x\n", cfg->param.htcap_cfg.htcap);
111 }
112 }
113 }
114
115 LEAVE();
116 return ret;
117 }
118
119 /**
120 * @brief Set/get 11n configuration
121 *
122 * @param pmadapter A pointer to mlan_adapter structure
123 * @param pioctl_req A pointer to ioctl request buffer
124 *
125 * @return MLAN_STATUS_PENDING --success, otherwise fail
126 */
wlan_11n_ioctl_httxcfg(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)127 static mlan_status wlan_11n_ioctl_httxcfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
128 {
129 mlan_status ret = MLAN_STATUS_SUCCESS;
130 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
131 mlan_ds_11n_cfg *cfg = MNULL;
132 t_u16 cmd_action = 0;
133
134 ENTER();
135
136 cfg = (mlan_ds_11n_cfg *)(void *)pioctl_req->pbuf;
137 if (pioctl_req->action == MLAN_ACT_SET)
138 {
139 cmd_action = HostCmd_ACT_GEN_SET;
140 }
141 else
142 {
143 cmd_action = HostCmd_ACT_GEN_GET;
144 }
145
146 /* Send request to firmware */
147 ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_CFG, cmd_action, 0, (t_void *)pioctl_req,
148 (t_void *)&cfg->param.tx_cfg);
149 if (ret == MLAN_STATUS_SUCCESS)
150 {
151 ret = MLAN_STATUS_PENDING;
152 }
153
154 LEAVE();
155 return ret;
156 }
157
158 /**
159 * @brief This function will send DELBA to entries in the priv's
160 * Tx BA stream table
161 *
162 * @param priv A pointer to mlan_private
163 * @param pioctl_req A pointer to ioctl request buffer
164 * @param tid TID
165 * @param peer_address A pointer to peer address
166 * @param last_tx_ba_to_delete A pointer to the last entry in TxBAStreamTbl
167 *
168 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
169 */
wlan_send_delba_to_entry_in_txbastream_tbl(pmlan_private priv,pmlan_ioctl_req pioctl_req,t_u8 tid,t_u8 * peer_address,TxBAStreamTbl * last_tx_ba_to_delete)170 static mlan_status wlan_send_delba_to_entry_in_txbastream_tbl(
171 pmlan_private priv, pmlan_ioctl_req pioctl_req, t_u8 tid, t_u8 *peer_address, TxBAStreamTbl *last_tx_ba_to_delete)
172 {
173 pmlan_adapter pmadapter = priv->adapter;
174 TxBAStreamTbl *tx_ba_stream_tbl_ptr;
175 t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
176 mlan_status ret = MLAN_STATUS_SUCCESS;
177 int i;
178
179 ENTER();
180
181 wlan_request_ralist_lock(priv);
182 tx_ba_stream_tbl_ptr =
183 (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr, MNULL, MNULL);
184 if (!tx_ba_stream_tbl_ptr)
185 {
186 wlan_release_ralist_lock(priv);
187 LEAVE();
188 return ret;
189 }
190
191 if (__memcmp(pmadapter, peer_address, zero_mac, MLAN_MAC_ADDR_LENGTH))
192 {
193 if (!wlan_11n_get_txbastream_tbl(priv, peer_address))
194 return MLAN_STATUS_FAILURE;
195 }
196
197 while (tx_ba_stream_tbl_ptr != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr)
198 {
199 if (tx_ba_stream_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE)
200 {
201 if (__memcmp(pmadapter, peer_address, zero_mac, MLAN_MAC_ADDR_LENGTH) &&
202 !__memcmp(pmadapter, peer_address, tx_ba_stream_tbl_ptr->ra, MLAN_MAC_ADDR_LENGTH))
203 {
204 tx_ba_stream_tbl_ptr = wlan_11n_get_txbastream_tbl(priv, peer_address);
205
206 if (tid == DELBA_ALL_TIDS)
207 {
208 for (i = 0; i < MAX_NUM_TID; i++)
209 {
210 if (tx_ba_stream_tbl_ptr->ampdu_stat[i])
211 {
212 if (last_tx_ba_to_delete && (tx_ba_stream_tbl_ptr == last_tx_ba_to_delete))
213 ret = wlan_send_delba(priv, pioctl_req, i, tx_ba_stream_tbl_ptr->ra, 1);
214 else
215 ret = wlan_send_delba(priv, MNULL, i, tx_ba_stream_tbl_ptr->ra, 1);
216 }
217 }
218 }
219 else
220 {
221 if (tx_ba_stream_tbl_ptr->ampdu_stat[tid])
222 {
223 if (last_tx_ba_to_delete && (tx_ba_stream_tbl_ptr == last_tx_ba_to_delete))
224 ret = wlan_send_delba(priv, pioctl_req, tid, tx_ba_stream_tbl_ptr->ra, 1);
225 else
226 ret = wlan_send_delba(priv, MNULL, tid, tx_ba_stream_tbl_ptr->ra, 1);
227 }
228 }
229
230 return ret;
231 }
232 else
233 {
234 if (tid == DELBA_ALL_TIDS)
235 {
236 for (i = 0; i < MAX_NUM_TID; i++)
237 {
238 if (tx_ba_stream_tbl_ptr->ampdu_stat[i])
239 {
240 if (last_tx_ba_to_delete && (tx_ba_stream_tbl_ptr == last_tx_ba_to_delete))
241 ret = wlan_send_delba(priv, pioctl_req, i, tx_ba_stream_tbl_ptr->ra, 1);
242 else
243 ret = wlan_send_delba(priv, MNULL, i, tx_ba_stream_tbl_ptr->ra, 1);
244 }
245 }
246 }
247 else
248 {
249 if (tx_ba_stream_tbl_ptr->ampdu_stat[tid])
250 {
251 if (last_tx_ba_to_delete && (tx_ba_stream_tbl_ptr == last_tx_ba_to_delete))
252 ret = wlan_send_delba(priv, pioctl_req, tid, tx_ba_stream_tbl_ptr->ra, 1);
253 else
254 ret = wlan_send_delba(priv, MNULL, tid, tx_ba_stream_tbl_ptr->ra, 1);
255 }
256 }
257 }
258 }
259
260 tx_ba_stream_tbl_ptr = tx_ba_stream_tbl_ptr->pnext;
261 }
262 wlan_release_ralist_lock(priv);
263
264 LEAVE();
265 return ret;
266 }
267
268 /**
269 * @brief This function will send DELBA to entries in the priv's
270 * rx reordering table
271 *
272 * @param priv A pointer to mlan_private
273 * @param pioctl_req A pointer to ioctl request buffer
274 * @param tid TID
275 * @param peer_address A pointer to peer address
276 * @param last_rx_ba_to_delete A pointer to the last entry in RxReorderTbl
277 *
278 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
279 */
wlan_send_delba_to_entry_in_reorder_tbl(pmlan_private priv,pmlan_ioctl_req pioctl_req,t_u8 tid,t_u8 * peer_address,RxReorderTbl * last_rx_ba_to_delete)280 static mlan_status wlan_send_delba_to_entry_in_reorder_tbl(
281 pmlan_private priv, pmlan_ioctl_req pioctl_req, t_u8 tid, t_u8 *peer_address, RxReorderTbl *last_rx_ba_to_delete)
282 {
283 pmlan_adapter pmadapter = priv->adapter;
284 RxReorderTbl *rx_reor_tbl_ptr;
285 RxReorderTbl *next_rx_reor_tbl_ptr;
286 t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
287 mlan_status ret = MLAN_STATUS_SUCCESS;
288
289 ENTER();
290
291 rx_reor_tbl_ptr =
292 (RxReorderTbl *)util_peek_list(pmadapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
293 pmadapter->callbacks.moal_spin_lock, pmadapter->callbacks.moal_spin_unlock);
294 if (!rx_reor_tbl_ptr)
295 {
296 LEAVE();
297 return ret;
298 }
299
300 next_rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
301
302 while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr)
303 {
304 if (rx_reor_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE)
305 {
306 if (((tid == DELBA_ALL_TIDS) || (tid == rx_reor_tbl_ptr->tid)) &&
307 (!__memcmp(pmadapter, peer_address, zero_mac, MLAN_MAC_ADDR_LENGTH) ||
308 !__memcmp(pmadapter, peer_address, rx_reor_tbl_ptr->ta, MLAN_MAC_ADDR_LENGTH)))
309 {
310 if (last_rx_ba_to_delete && (rx_reor_tbl_ptr == last_rx_ba_to_delete))
311 ret = wlan_send_delba(priv, pioctl_req, rx_reor_tbl_ptr->tid, rx_reor_tbl_ptr->ta, 0);
312 else
313 ret = wlan_send_delba(priv, MNULL, rx_reor_tbl_ptr->tid, rx_reor_tbl_ptr->ta, 0);
314 }
315 }
316
317 rx_reor_tbl_ptr = next_rx_reor_tbl_ptr;
318
319 next_rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
320 }
321
322 LEAVE();
323 return ret;
324 }
325
326 /**
327 * @brief IOCTL to delete BA
328 *
329 * @param pmadapter A pointer to mlan_adapter structure
330 * @param pioctl_req A pointer to ioctl request buffer
331 *
332 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
333 */
wlan_11n_ioctl_delba(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)334 static mlan_status wlan_11n_ioctl_delba(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
335 {
336 mlan_status ret = MLAN_STATUS_SUCCESS;
337 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
338 mlan_ds_11n_cfg *cfg = MNULL;
339 TxBAStreamTbl *tx_ba_stream_tbl_ptr, *last_tx_ba_to_delete = MNULL;
340 RxReorderTbl *rx_reor_tbl_ptr, *last_rx_ba_to_delete = MNULL;
341 t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
342 t_u8 tid, *peer_address;
343
344 ENTER();
345
346 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
347 tid = cfg->param.del_ba.tid;
348 peer_address = cfg->param.del_ba.peer_mac_addr;
349
350 PRINTM(MINFO, "DelBA: direction %d, TID %d, peer address " MACSTR "\n", cfg->param.del_ba.direction, tid,
351 MAC2STR(peer_address));
352
353 if (cfg->param.del_ba.direction & DELBA_RX)
354 {
355 rx_reor_tbl_ptr =
356 (RxReorderTbl *)util_peek_list(pmadapter->pmoal_handle, &pmpriv->rx_reorder_tbl_ptr,
357 pmadapter->callbacks.moal_spin_lock, pmadapter->callbacks.moal_spin_unlock);
358
359 if (rx_reor_tbl_ptr)
360 {
361 while (rx_reor_tbl_ptr != (RxReorderTbl *)&pmpriv->rx_reorder_tbl_ptr)
362 {
363 if (rx_reor_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE)
364 {
365 if (((tid == DELBA_ALL_TIDS) || (tid == rx_reor_tbl_ptr->tid)) &&
366 (!__memcmp(pmadapter, peer_address, zero_mac, MLAN_MAC_ADDR_LENGTH) ||
367 !__memcmp(pmadapter, peer_address, rx_reor_tbl_ptr->ta, MLAN_MAC_ADDR_LENGTH)))
368 {
369 /* Found RX BA to delete */
370 last_rx_ba_to_delete = rx_reor_tbl_ptr;
371 }
372 }
373 rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
374 }
375 }
376 }
377
378 if ((last_rx_ba_to_delete == MNULL) && (cfg->param.del_ba.direction & DELBA_TX))
379 {
380 wlan_request_ralist_lock(pmpriv);
381 tx_ba_stream_tbl_ptr =
382 (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle, &pmpriv->tx_ba_stream_tbl_ptr, MNULL, MNULL);
383
384 if (tx_ba_stream_tbl_ptr)
385 {
386 while (tx_ba_stream_tbl_ptr != (TxBAStreamTbl *)&pmpriv->tx_ba_stream_tbl_ptr)
387 {
388 if (tx_ba_stream_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE)
389 {
390 if (((tid == DELBA_ALL_TIDS) || (tx_ba_stream_tbl_ptr->ampdu_stat[tid])) &&
391 (!__memcmp(pmadapter, peer_address, zero_mac, MLAN_MAC_ADDR_LENGTH) ||
392 !__memcmp(pmadapter, peer_address, tx_ba_stream_tbl_ptr->ra, MLAN_MAC_ADDR_LENGTH)))
393 {
394 /* Found TX BA to delete */
395 last_tx_ba_to_delete = tx_ba_stream_tbl_ptr;
396 }
397 }
398 tx_ba_stream_tbl_ptr = tx_ba_stream_tbl_ptr->pnext;
399 }
400 }
401 wlan_release_ralist_lock(pmpriv);
402 }
403
404 if (cfg->param.del_ba.direction & DELBA_TX)
405 {
406 if (last_rx_ba_to_delete)
407 ret = wlan_send_delba_to_entry_in_txbastream_tbl(pmpriv, MNULL, tid, peer_address, MNULL);
408 else
409 ret =
410 wlan_send_delba_to_entry_in_txbastream_tbl(pmpriv, pioctl_req, tid, peer_address, last_tx_ba_to_delete);
411 }
412 if (last_rx_ba_to_delete)
413 {
414 ret = wlan_send_delba_to_entry_in_reorder_tbl(pmpriv, pioctl_req, tid, peer_address, last_rx_ba_to_delete);
415 }
416
417 LEAVE();
418 return ret;
419 }
420
421 /********************************************************
422 Global Functions
423 ********************************************************/
424
425 #ifdef STA_SUPPORT
426 /**
427 * @brief This function fills the cap info
428 *
429 * @param priv A pointer to mlan_private structure
430 * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
431 * @param bands Band configuration
432 *
433 * @return N/A
434 */
wlan_fill_cap_info(mlan_private * priv,MrvlIETypes_HTCap_t * pht_cap,t_u16 bands)435 static void wlan_fill_cap_info(mlan_private *priv, MrvlIETypes_HTCap_t *pht_cap, t_u16 bands)
436 {
437 mlan_adapter *pmadapter = priv->adapter;
438 t_u32 usr_dot_11n_dev_cap;
439
440 ENTER();
441
442 #if CONFIG_5GHz_SUPPORT
443 if ((bands & BAND_A) != 0U)
444 {
445 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
446 }
447 else
448 #endif
449 {
450 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
451 }
452
453 if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) != 0U)
454 {
455 SETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
456 SETHT_DSSSCCK40(pht_cap->ht_cap.ht_cap_info);
457 }
458 else
459 {
460 RESETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
461 RESETHT_DSSSCCK40(pht_cap->ht_cap.ht_cap_info);
462 }
463
464 if (ISSUPP_GREENFIELD(usr_dot_11n_dev_cap) != 0U)
465 {
466 SETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
467 }
468 else
469 {
470 RESETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
471 }
472
473 if (ISSUPP_SHORTGI20(usr_dot_11n_dev_cap) != 0U)
474 {
475 SETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
476 }
477 else
478 {
479 RESETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
480 }
481
482 if (ISSUPP_SHORTGI40(usr_dot_11n_dev_cap) != 0U)
483 {
484 SETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
485 }
486 else
487 {
488 RESETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
489 }
490
491 if (ISSUPP_RXSTBC(usr_dot_11n_dev_cap) != 0U)
492 {
493 SETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info, 1U);
494 }
495 else
496 {
497 RESETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info);
498 }
499
500 if (ISENABLED_40MHZ_INTOLARENT(usr_dot_11n_dev_cap) != 0U)
501 {
502 SETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
503 }
504 else
505 {
506 RESETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
507 }
508
509 /* No user config for LDPC coding capability yet */
510 if (ISSUPP_RXLDPC(usr_dot_11n_dev_cap) != 0U)
511 {
512 SETHT_LDPCCODINGCAP(pht_cap->ht_cap.ht_cap_info);
513 }
514 else
515 {
516 RESETHT_LDPCCODINGCAP(pht_cap->ht_cap.ht_cap_info);
517 }
518
519 /* No user config for TX STBC yet */
520 if (ISSUPP_TXSTBC(usr_dot_11n_dev_cap) != 0U)
521 {
522 SETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
523 }
524 else
525 {
526 RESETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
527 }
528
529 /* No user config for Delayed BACK yet */
530 RESETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
531
532 /* Need change to support 8k AMSDU receive */
533 RESETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info);
534
535 /* SM power save */
536 if (ISSUPP_MIMOPS(priv->adapter->hw_dot_11n_dev_cap) != 0U)
537 {
538 RESETHT_SM_POWERSAVE(pht_cap->ht_cap.ht_cap_info); /* Enable HT SMPS*/
539 }
540 else
541 {
542 SETHT_STATIC_SMPS(pht_cap->ht_cap.ht_cap_info); /* Disable HT SMPS */
543 }
544
545 LEAVE();
546 }
547
548 /**
549 * @brief This function fills the HT cap tlv
550 *
551 * @param priv A pointer to mlan_private structure
552 * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
553 * @param bands Band configuration
554 *
555 * @return N/A
556 */
wlan_fill_ht_cap_tlv(mlan_private * priv,MrvlIETypes_HTCap_t * pht_cap,t_u16 bands)557 void wlan_fill_ht_cap_tlv(mlan_private *priv, MrvlIETypes_HTCap_t *pht_cap, t_u16 bands)
558 {
559 mlan_adapter *pmadapter = priv->adapter;
560 int rx_mcs_supp;
561 t_u32 usr_dot_11n_dev_cap;
562
563 ENTER();
564
565 #if CONFIG_5GHz_SUPPORT
566 if ((bands & BAND_A) != 0U)
567 {
568 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
569 }
570 else
571 #endif
572 {
573 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
574 }
575
576 /* Fill HT cap info */
577 wlan_fill_cap_info(priv, pht_cap, bands);
578 pht_cap->ht_cap.ht_cap_info = wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);
579
580 /* Set ampdu param */
581 SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
582
583 #ifdef RW610_SERIES
584 SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0x5);
585 #else
586 SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, pmadapter->hw_mpdu_density);
587 #endif
588
589 rx_mcs_supp = GET_RXMCSSUPP(pmadapter->usr_dev_mcs_support);
590 /* Set MCS for 1x1/2x2 */
591 (void)__memset(pmadapter, (t_u8 *)pht_cap->ht_cap.supported_mcs_set, 0xff, rx_mcs_supp);
592 /* Clear all the other values */
593 (void)__memset(pmadapter, (t_u8 *)&pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp], 0, NUM_MCS_FIELD - rx_mcs_supp);
594 /* Set MCS32 with 40MHz support */
595 /* if current channel only support 20MHz, we should not set 40Mz supprot*/
596 if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) != 0U)
597 {
598 SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
599 }
600
601 /* Clear RD responder bit */
602 RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);
603 pht_cap->ht_cap.ht_ext_cap = wlan_cpu_to_le16(pht_cap->ht_cap.ht_ext_cap);
604
605 /* Set Tx BF cap */
606 pht_cap->ht_cap.tx_bf_cap = wlan_cpu_to_le32(priv->tx_bf_cap);
607
608 LEAVE();
609 return;
610 }
611 #endif /* STA_SUPPORT */
612
613 /**
614 * @brief This function prints the 802.11n device capability
615 *
616 * @param pmadapter A pointer to mlan_adapter structure
617 * @param cap Capability value
618 *
619 * @return N/A
620 */
wlan_show_dot11ndevcap(pmlan_adapter pmadapter,t_u32 cap)621 void wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap)
622 {
623 ENTER();
624
625 PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = %s octets\n", (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
626 PRINTM(MINFO, "GET_HW_SPEC: Beam forming %s\n", (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
627 PRINTM(MINFO, "GET_HW_SPEC: Greenfield preamble %s\n", (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
628 PRINTM(MINFO, "GET_HW_SPEC: AMPDU %s\n", (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
629 PRINTM(MINFO, "GET_HW_SPEC: MIMO Power Save %s\n", (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
630 PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n", (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
631 PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n", (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
632 PRINTM(MINFO, "GET_HW_SPEC: Short GI for 40 Mhz %s\n", (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
633 PRINTM(MINFO, "GET_HW_SPEC: Short GI for 20 Mhz %s\n", (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
634 PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n", (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
635 PRINTM(MINFO, "GET_HW_SPEC: Number of TX BA streams supported %d\n", ISSUPP_GETTXBASTREAM(cap));
636 PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n", (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
637 PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n", (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
638 PRINTM(MINFO, "GET_HW_SPEC: 10 Mhz channel width %s\n", (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
639
640 if (ISSUPP_RXANTENNAA(cap) != 0U)
641 {
642 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna A\n");
643 }
644 if (ISSUPP_RXANTENNAB(cap) != 0U)
645 {
646 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna B\n");
647 }
648 if (ISSUPP_RXANTENNAC(cap) != 0U)
649 {
650 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna C\n");
651 }
652 if (ISSUPP_RXANTENNAD(cap) != 0U)
653 {
654 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna D\n");
655 }
656 if (ISSUPP_TXANTENNAA(cap) != 0U)
657 {
658 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna A\n");
659 }
660 if (ISSUPP_TXANTENNAB(cap) != 0U)
661 {
662 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna B\n");
663 }
664 if (ISSUPP_TXANTENNAC(cap) != 0U)
665 {
666 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna C\n");
667 }
668 if (ISSUPP_TXANTENNAD(cap) != 0U)
669 {
670 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna D\n");
671 }
672
673 LEAVE();
674 return;
675 }
676
677 /**
678 * @brief This function prints the 802.11n device MCS
679 *
680 * @param pmadapter A pointer to mlan_adapter structure
681 * @param support Support value
682 *
683 * @return N/A
684 */
wlan_show_devmcssupport(pmlan_adapter pmadapter,t_u8 support)685 void wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support)
686 {
687 ENTER();
688
689 PRINTM(MINFO, "GET_HW_SPEC: MCSs for %dx%d MIMO\n", GET_RXMCSSUPP(support), GET_TXMCSSUPP(support));
690
691 LEAVE();
692 return;
693 }
694
695 /**
696 * @brief This function prepares command of reconfigure tx buf
697 *
698 * @param priv A pointer to mlan_private structure
699 * @param cmd A pointer to HostCmd_DS_COMMAND structure
700 * @param cmd_action The action: GET or SET
701 * @param pdata_buf A pointer to data buffer
702 *
703 * @return MLAN_STATUS_SUCCESS
704 */
wlan_cmd_recfg_tx_buf(mlan_private * priv,HostCmd_DS_COMMAND * cmd,int cmd_action,void * pdata_buf)705 mlan_status wlan_cmd_recfg_tx_buf(mlan_private *priv, HostCmd_DS_COMMAND *cmd, int cmd_action, void *pdata_buf)
706 {
707 HostCmd_DS_TXBUF_CFG *ptx_buf = &cmd->params.tx_buf;
708 t_u16 action = (t_u16)cmd_action;
709 t_u16 buf_size = *((t_u16 *)pdata_buf);
710
711 ENTER();
712 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
713 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TXBUF_CFG) + S_DS_GEN);
714 ptx_buf->action = wlan_cpu_to_le16(action);
715 switch (action)
716 {
717 case HostCmd_ACT_GEN_SET:
718 PRINTM(MCMND, "set tx_buf = %d\n", buf_size);
719 ptx_buf->buff_size = wlan_cpu_to_le16(buf_size);
720 break;
721 case HostCmd_ACT_GEN_GET:
722 default:
723 ptx_buf->buff_size = 0;
724 break;
725 }
726 LEAVE();
727 return MLAN_STATUS_SUCCESS;
728 }
729
730 /**
731 * @brief This function prepares command of amsdu aggr control
732 *
733 * @param priv A pointer to mlan_private structure
734 * @param cmd A pointer to HostCmd_DS_COMMAND structure
735 * @param cmd_action The action: GET or SET
736 * @param pdata_buf A pointer to data buffer
737 *
738 * @return MLAN_STATUS_SUCCESS
739 */
wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,HostCmd_DS_COMMAND * cmd,int cmd_action,void * pdata_buf)740 mlan_status wlan_cmd_amsdu_aggr_ctrl(mlan_private *priv, HostCmd_DS_COMMAND *cmd, int cmd_action, void *pdata_buf)
741 {
742 HostCmd_DS_AMSDU_AGGR_CTRL *pamsdu_ctrl = &cmd->params.amsdu_aggr_ctrl;
743 t_u16 action = (t_u16)cmd_action;
744 mlan_ds_11n_amsdu_aggr_ctrl *aa_ctrl = (mlan_ds_11n_amsdu_aggr_ctrl *)pdata_buf;
745
746 ENTER();
747
748 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
749 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_AMSDU_AGGR_CTRL) + S_DS_GEN);
750 pamsdu_ctrl->action = wlan_cpu_to_le16(action);
751 switch (action)
752 {
753 case HostCmd_ACT_GEN_SET:
754 pamsdu_ctrl->enable = wlan_cpu_to_le16(aa_ctrl->enable);
755 pamsdu_ctrl->curr_buf_size = 0;
756 break;
757 case HostCmd_ACT_GEN_GET:
758 default:
759 pamsdu_ctrl->curr_buf_size = 0;
760 break;
761 }
762 LEAVE();
763 return MLAN_STATUS_SUCCESS;
764 }
765
766 /**
767 * @brief This function handles the command response of amsdu aggr ctrl
768 *
769 * @param pmpriv A pointer to mlan_private structure
770 * @param resp A pointer to HostCmd_DS_COMMAND
771 * @param pioctl_buf A pointer to mlan_ioctl_req structure
772 *
773 * @return MLAN_STATUS_SUCCESS
774 */
775 #if CONFIG_AMSDU_IN_AMPDU
wlan_ret_amsdu_aggr_ctrl(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)776 mlan_status wlan_ret_amsdu_aggr_ctrl(IN pmlan_private pmpriv,
777 IN HostCmd_DS_COMMAND *resp,
778 IN mlan_ioctl_req *pioctl_buf)
779 {
780 mlan_ds_11n_cfg *cfg = MNULL;
781 HostCmd_DS_AMSDU_AGGR_CTRL *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl;
782
783 ENTER();
784
785 #ifdef DEBUG_11N_AGGR
786 wmprintf(
787 "action: %d\n\r"
788 "enable: %d\n\r"
789 "curr_buf_size: %d\n\n\r",
790 amsdu_ctrl->action, amsdu_ctrl->enable, amsdu_ctrl->curr_buf_size);
791 #endif /* DEBUG_11N_AGGR */
792
793 if (pioctl_buf != NULL)
794 {
795 cfg = (mlan_ds_11n_cfg *)(void *)pioctl_buf->pbuf;
796 cfg->param.amsdu_aggr_ctrl.enable = wlan_le16_to_cpu(amsdu_ctrl->enable);
797 cfg->param.amsdu_aggr_ctrl.curr_buf_size = wlan_le16_to_cpu(amsdu_ctrl->curr_buf_size);
798 }
799 pmpriv->is_amsdu_enabled = wlan_le16_to_cpu(amsdu_ctrl->enable);
800 LEAVE();
801 return MLAN_STATUS_SUCCESS;
802 }
803 #endif
804
805 /**
806 * @brief This function prepares 11n cfg command
807 *
808 * @param pmpriv A pointer to mlan_private structure
809 * @param cmd A pointer to HostCmd_DS_COMMAND structure
810 * @param cmd_action the action: GET or SET
811 * @param pdata_buf A pointer to data buffer
812 * @return MLAN_STATUS_SUCCESS
813 */
wlan_cmd_11n_cfg(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * cmd,IN t_u16 cmd_action,IN t_void * pdata_buf)814 mlan_status wlan_cmd_11n_cfg(IN pmlan_private pmpriv,
815 IN HostCmd_DS_COMMAND *cmd,
816 IN t_u16 cmd_action,
817 IN t_void *pdata_buf)
818 {
819 HostCmd_DS_11N_CFG *htcfg = &cmd->params.htcfg;
820 mlan_ds_11n_tx_cfg *txcfg = (mlan_ds_11n_tx_cfg *)pdata_buf;
821
822 ENTER();
823 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_CFG);
824 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_CFG) + S_DS_GEN);
825 htcfg->action = wlan_cpu_to_le16(cmd_action);
826 htcfg->ht_tx_cap = wlan_cpu_to_le16(txcfg->httxcap);
827 htcfg->ht_tx_info = wlan_cpu_to_le16(txcfg->httxinfo);
828 htcfg->misc_config = wlan_cpu_to_le16(txcfg->misc_cfg);
829 LEAVE();
830 return MLAN_STATUS_SUCCESS;
831 }
832
833 /**
834 * @brief This function handles the command response of 11ncfg
835 *
836 * @param pmpriv A pointer to mlan_private structure
837 * @param resp A pointer to HostCmd_DS_COMMAND
838 * @param pioctl_buf A pointer to mlan_ioctl_req structure
839 *
840 * @return MLAN_STATUS_SUCCESS
841 */
wlan_ret_11n_cfg(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)842 mlan_status wlan_ret_11n_cfg(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND *resp, IN mlan_ioctl_req *pioctl_buf)
843 {
844 mlan_ds_11n_cfg *cfg = MNULL;
845 HostCmd_DS_11N_CFG *htcfg = &resp->params.htcfg;
846
847 #ifdef DEBUG_11N_AGGR
848 wmprintf("11n CFG response\n\r");
849 wmprintf("action: 0x%x\n\r", htcfg->action);
850 wmprintf("ht_tx_cap: 0x%x\n\r", htcfg->ht_tx_cap);
851 /** HTTxInfo */
852 wmprintf("ht_tx_info: 0x%x\n\r", htcfg->ht_tx_info);
853 /** Misc configuration */
854 wmprintf("misc_config: 0x%x\n\r", htcfg->misc_config);
855 #endif /* DEBUG_11N_AGGR */
856
857 ENTER();
858 if (pioctl_buf != MNULL && (wlan_le16_to_cpu(htcfg->action) == HostCmd_ACT_GEN_GET))
859 {
860 cfg = (mlan_ds_11n_cfg *)(void *)pioctl_buf->pbuf;
861 cfg->param.tx_cfg.httxcap = wlan_le16_to_cpu(htcfg->ht_tx_cap);
862 cfg->param.tx_cfg.httxinfo = wlan_le16_to_cpu(htcfg->ht_tx_info);
863 cfg->param.tx_cfg.misc_cfg = wlan_le16_to_cpu(htcfg->misc_config);
864 }
865 LEAVE();
866 return MLAN_STATUS_SUCCESS;
867 }
868
869 #ifdef STA_SUPPORT
870
871 /**
872 * @brief This function check if ht40 is allowed in current region
873 *
874 * @param pmpriv A pointer to mlan_private structure
875 * @param pbss_desc A pointer to BSSDescriptor_t structure
876 *
877 * @return MTRUE/MFALSE
878 */
wlan_check_chan_width_ht40_by_region(IN mlan_private * pmpriv,IN BSSDescriptor_t * pbss_desc)879 static int wlan_check_chan_width_ht40_by_region(IN mlan_private *pmpriv, IN BSSDescriptor_t *pbss_desc)
880 {
881 pmlan_adapter pmadapter = pmpriv->adapter;
882 t_u8 i = 0;
883 int cover_pri_chan = MFALSE;
884 t_u8 pri_chan;
885 t_u8 chan_offset;
886 t_u8 num_cfp;
887
888 ENTER();
889
890 if (pbss_desc->pht_info == MNULL)
891 {
892 PRINTM(MERROR, "ht_info pointer NULL, force use HT20\n");
893 LEAVE();
894 return MFALSE;
895 }
896 #if 0
897 if(pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
898 pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS){
899 LEAVE();
900 return MFALSE;
901 }
902 #endif
903 pri_chan = pbss_desc->pht_info->ht_info.pri_chan;
904 chan_offset = GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.field2);
905 #if 0
906 if((chan_offset == SEC_CHAN_ABOVE) && (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS))
907 return MFALSE;
908 if((chan_offset == SEC_CHAN_BELOW) && (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
909 return MFALSE;
910 #endif
911 num_cfp = pmadapter->region_channel[0].num_cfp;
912
913 if ((pbss_desc->bss_band & (BAND_B | BAND_G)) && pmadapter->region_channel[0].valid)
914 {
915 for (i = 0; i < num_cfp; i++)
916 {
917 if (pri_chan == pmadapter->region_channel[0].pcfp[i].channel)
918 {
919 cover_pri_chan = MTRUE;
920 break;
921 }
922 }
923 if (!cover_pri_chan)
924 {
925 PRINTM(MERROR, "Invalid channel, force use HT20\n");
926 LEAVE();
927 return MFALSE;
928 }
929
930 if (chan_offset == (t_u8)SEC_CHAN_ABOVE)
931 {
932 if (pri_chan > num_cfp - 4U)
933 {
934 PRINTM(MERROR, "Invalid second channel offset, force use HT20\n");
935 LEAVE();
936 return MFALSE;
937 }
938 }
939 }
940 LEAVE();
941 return MTRUE;
942 }
943
944 /**
945 * @brief This function append the 802_11N tlv
946 *
947 * @param pmpriv A pointer to mlan_private structure
948 * @param pbss_desc A pointer to BSSDescriptor_t structure
949 * @param ppbuffer A Pointer to command buffer pointer
950 *
951 * @return bytes added to the buffer
952 */
wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,IN BSSDescriptor_t * pbss_desc,OUT t_u8 ** ppbuffer)953 t_u32 wlan_cmd_append_11n_tlv(IN mlan_private *pmpriv, IN BSSDescriptor_t *pbss_desc, OUT t_u8 **ppbuffer)
954 {
955 pmlan_adapter pmadapter = pmpriv->adapter;
956 MrvlIETypes_HTCap_t *pht_cap;
957 MrvlIETypes_HTInfo_t *pht_info;
958 MrvlIEtypes_ChanListParamSet_t *pchan_list;
959 #if CONFIG_5GHz_SUPPORT
960 MrvlIETypes_2040BSSCo_t *p2040_bss_co;
961 #endif
962 MrvlIETypes_ExtCap_t *pext_cap;
963 t_u32 usr_dot_11n_dev_cap, orig_usr_dot_11n_dev_cap = 0;
964 t_u8 usr_dot_11ac_bw;
965 t_u32 ret_len = 0;
966
967 ENTER();
968
969 /* Null Checks */
970 if (ppbuffer == MNULL)
971 {
972 LEAVE();
973 return 0;
974 }
975 if (*ppbuffer == MNULL)
976 {
977 LEAVE();
978 return 0;
979 }
980
981 #if CONFIG_5GHz_SUPPORT
982 if ((pbss_desc->bss_band & BAND_A) != 0U)
983 {
984 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
985 }
986 else
987 #endif
988 {
989 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
990 }
991
992 if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
993 {
994 usr_dot_11ac_bw = BW_FOLLOW_VHTCAP;
995 }
996 else
997 {
998 usr_dot_11ac_bw = pmadapter->usr_dot_11ac_bw;
999 }
1000
1001 if (((pbss_desc->bss_band & (BAND_B | BAND_G
1002 #if CONFIG_5GHz_SUPPORT
1003 | BAND_A
1004 #endif
1005 )) &&
1006 ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) && !wlan_check_chan_width_ht40_by_region(pmpriv, pbss_desc)) ||
1007 (pbss_desc->bss_band & (BAND_B | BAND_G | BAND_GN)))
1008 {
1009 orig_usr_dot_11n_dev_cap = usr_dot_11n_dev_cap;
1010 #ifdef RW610
1011 RESETSUPP_CHANWIDTH40(usr_dot_11n_dev_cap);
1012 RESETSUPP_SHORTGI40(usr_dot_11n_dev_cap);
1013 #endif
1014 RESET_40MHZ_INTOLARENT(usr_dot_11n_dev_cap);
1015 pmadapter->usr_dot_11n_dev_cap_bg = usr_dot_11n_dev_cap;
1016 pbss_desc->curr_bandwidth = BW_20MHZ;
1017 }
1018
1019 if (pbss_desc->pht_cap != MNULL)
1020 {
1021 pht_cap = (MrvlIETypes_HTCap_t *)(void *)*ppbuffer;
1022 (void)__memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
1023 pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
1024 pht_cap->header.len = sizeof(HTCap_t);
1025 (void)__memcpy(pmadapter, (t_u8 *)pht_cap + sizeof(MrvlIEtypesHeader_t),
1026 (t_u8 *)pbss_desc->pht_cap + sizeof(IEEEtypes_Header_t), pht_cap->header.len);
1027
1028 if (!ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
1029 {
1030 pht_cap->ht_cap.ht_cap_info &= ~(MBIT(1) | MBIT(6));
1031 }
1032
1033 pht_cap->ht_cap.ht_cap_info = wlan_le16_to_cpu(pht_cap->ht_cap.ht_cap_info);
1034 pht_cap->ht_cap.ht_ext_cap = wlan_le16_to_cpu(pht_cap->ht_cap.ht_ext_cap);
1035 wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pbss_desc->bss_band);
1036 if (wlan_use_non_default_ht_vht_cap(pbss_desc))
1037 {
1038 /* Indicate 3 streams in TxBF cap*/
1039 pht_cap->ht_cap.tx_bf_cap = ((pht_cap->ht_cap.tx_bf_cap & (~(0x3 << 23))) | (0x2 << 23));
1040 pht_cap->ht_cap.tx_bf_cap = ((pht_cap->ht_cap.tx_bf_cap & (~(0x3 << 27))) | (0x2 << 27));
1041 }
1042
1043 HEXDUMP("HT_CAPABILITIES IE", (t_u8 *)pht_cap, sizeof(MrvlIETypes_HTCap_t));
1044 *ppbuffer += sizeof(MrvlIETypes_HTCap_t);
1045 ret_len += sizeof(MrvlIETypes_HTCap_t);
1046 pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
1047 #ifdef DEBUG_11N_ASSOC
1048 dump_htcap_info(pht_cap);
1049 #endif /* DEBUG_11N_ASSOC */
1050 }
1051
1052 if (pbss_desc->pht_info != MNULL)
1053 {
1054 if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
1055 {
1056 pht_info = (MrvlIETypes_HTInfo_t *)(void *)*ppbuffer;
1057 (void)__memset(pmadapter, pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
1058 pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
1059 pht_info->header.len = sizeof(HTInfo_t);
1060
1061 (void)__memcpy(pmadapter, (t_u8 *)pht_info + sizeof(MrvlIEtypesHeader_t),
1062 (t_u8 *)pbss_desc->pht_info + sizeof(IEEEtypes_Header_t), pht_info->header.len);
1063
1064 if (!ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
1065 {
1066 RESET_CHANWIDTH40(pht_info->ht_info.field2);
1067 }
1068
1069 *ppbuffer += sizeof(MrvlIETypes_HTInfo_t);
1070 ret_len += sizeof(MrvlIETypes_HTInfo_t);
1071 pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
1072 #ifdef DEBUG_11N_ASSOC
1073 dump_ht_info(pht_info);
1074 #endif /* DEBUG_11N_ASSOC */
1075 }
1076
1077 pchan_list = (MrvlIEtypes_ChanListParamSet_t *)(void *)*ppbuffer;
1078 (void)__memset(pmadapter, pchan_list, 0, sizeof(MrvlIEtypes_ChanListParamSet_t));
1079 pchan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
1080 pchan_list->header.len = sizeof(MrvlIEtypes_ChanListParamSet_t) - sizeof(MrvlIEtypesHeader_t);
1081 pchan_list->chan_scan_param[0].chan_number = pbss_desc->pht_info->ht_info.pri_chan;
1082 pchan_list->chan_scan_param[0].radio_type = wlan_band_to_radio_type((t_u8)pbss_desc->bss_band);
1083 /* support the VHT if the network to be join has the VHT operation */
1084 if (ISSUPP_11ACENABLED(pmadapter->fw_cap_info) && (usr_dot_11ac_bw == BW_FOLLOW_VHTCAP) &&
1085 ISSUPP_CHANWIDTH40(pmadapter->hw_dot_11n_dev_cap) &&
1086 wlan_11ac_bandconfig_allowed(pmpriv, pbss_desc->bss_band) && pbss_desc->pvht_oprat != MNULL &&
1087 pbss_desc->pvht_oprat->chan_width == VHT_OPER_CHWD_80MHZ)
1088 {
1089 // pchan_list->chan_scan_param[0].bandcfg.chanWidth = CHAN_BW_80MHZ;
1090 // pchan_list->chan_scan_param[0].bandcfg.chan2Offset =
1091 // GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.field2);
1092 SET_SECONDARYCHAN(pchan_list->chan_scan_param[0].radio_type,
1093 GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.field2));
1094 pchan_list->chan_scan_param[0].radio_type |= (MBIT(2) | MBIT(3));
1095 pbss_desc->curr_bandwidth = BW_80MHZ;
1096 }
1097 else if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
1098 ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2) &&
1099 wlan_check_chan_width_ht40_by_region(pmpriv, pbss_desc))
1100 {
1101 SET_SECONDARYCHAN(pchan_list->chan_scan_param[0].radio_type,
1102 GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.field2));
1103 pchan_list->chan_scan_param[0].radio_type |= MBIT(3);
1104 pbss_desc->curr_bandwidth = BW_40MHZ;
1105 }
1106 else
1107 {
1108 /* Do nothing */
1109 }
1110
1111 HEXDUMP("ChanList", (t_u8 *)pchan_list, sizeof(MrvlIEtypes_ChanListParamSet_t));
1112 HEXDUMP("pht_info", (t_u8 *)pbss_desc->pht_info, sizeof(MrvlIETypes_HTInfo_t) - 2);
1113 *ppbuffer += sizeof(MrvlIEtypes_ChanListParamSet_t);
1114 ret_len += sizeof(MrvlIEtypes_ChanListParamSet_t);
1115 pchan_list->header.len = wlan_cpu_to_le16(pchan_list->header.len);
1116 }
1117
1118 #if CONFIG_5GHz_SUPPORT
1119 if ((pbss_desc->bss_band & (BAND_A | BAND_AN)) && pbss_desc->pbss_co_2040 != MNULL)
1120 {
1121 p2040_bss_co = (MrvlIETypes_2040BSSCo_t *)(void *)*ppbuffer;
1122 (void)__memset(pmadapter, p2040_bss_co, 0, sizeof(MrvlIETypes_2040BSSCo_t));
1123 p2040_bss_co->header.type = wlan_cpu_to_le16(BSSCO_2040);
1124 p2040_bss_co->header.len = sizeof(BSSCo2040_t);
1125
1126 (void)__memcpy(pmadapter, (t_u8 *)p2040_bss_co + sizeof(MrvlIEtypesHeader_t),
1127 (t_u8 *)pbss_desc->pbss_co_2040 + sizeof(IEEEtypes_Header_t), p2040_bss_co->header.len);
1128
1129 HEXDUMP("20/40 BSS Coexistence IE", (t_u8 *)p2040_bss_co, sizeof(MrvlIETypes_2040BSSCo_t));
1130 *ppbuffer += sizeof(MrvlIETypes_2040BSSCo_t);
1131 ret_len += sizeof(MrvlIETypes_2040BSSCo_t);
1132 p2040_bss_co->header.len = wlan_cpu_to_le16(p2040_bss_co->header.len);
1133 }
1134 #endif
1135
1136 if (pbss_desc->pext_cap != NULL)
1137 {
1138 pext_cap = (MrvlIETypes_ExtCap_t *)(void *)*ppbuffer;
1139 (void)__memset(pmadapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
1140 pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
1141 pext_cap->header.len = sizeof(ExtCap_t);
1142
1143 (void)__memcpy(pmadapter, (t_u8 *)pext_cap + sizeof(MrvlIEtypesHeader_t),
1144 (t_u8 *)pbss_desc->pext_cap + sizeof(IEEEtypes_Header_t), pbss_desc->pext_cap->ieee_hdr.len);
1145
1146 #if CONFIG_MULTI_BSSID_SUPPORT
1147 if (pbss_desc && pbss_desc->multi_bssid_ap)
1148 SET_EXTCAP_MULTI_BSSID(pext_cap->ext_cap);
1149 #endif
1150
1151 #if !defined(SD8801) && !defined(RW610)
1152 pext_cap->ext_cap.BSS_CoexistSupport = 0x01; /*2040 CoEx support must be always set*/
1153 #endif
1154
1155 if (pmpriv->hotspot_cfg & HOTSPOT_ENABLED)
1156 {
1157 if ((((t_u8)(pmpriv->hotspot_cfg >> 8)) & HOTSPOT_ENABLE_INTERWORKING_IND) != 0U)
1158 {
1159 pext_cap->ext_cap.Interworking = 1;
1160 }
1161 if ((((t_u8)(pmpriv->hotspot_cfg >> 8)) & HOTSPOT_ENABLE_TDLS_IND) != 0U)
1162 {
1163 pext_cap->ext_cap.TDLSSupport = 1;
1164 }
1165 }
1166 #if (CONFIG_WNM_PS)
1167 if ((((mlan_private *)mlan_adap->priv[0])->wnm_set == true) && (pbss_desc->pext_cap->ext_cap.WNM_Sleep == true))
1168 {
1169 pext_cap->ext_cap.WNM_Sleep = 1;
1170 }
1171 else
1172 {
1173 pext_cap->ext_cap.WNM_Sleep = 0;
1174 }
1175 #endif
1176
1177 #if CONFIG_11V
1178 if (pbss_desc->pext_cap->ext_cap.BSS_Transition == true)
1179 {
1180 pext_cap->ext_cap.BSS_Transition = 1;
1181 }
1182 else
1183 {
1184 pext_cap->ext_cap.BSS_Transition = 0;
1185 }
1186 #endif
1187 #if CONFIG_11MC || CONFIG_11AZ
1188 pext_cap->ext_cap.FTMI = 1;
1189 #endif
1190 #if CONFIG_11MC
1191 pext_cap->ext_cap.CivicLocation = 1;
1192 #endif
1193 #if CONFIG_11AX
1194 SET_EXTCAP_TWT_REQ(pext_cap->ext_cap);
1195 pext_cap->ext_cap.TWTResp = 0;
1196 #endif
1197 HEXDUMP("Extended Capabilities IE", (t_u8 *)pext_cap, sizeof(MrvlIETypes_ExtCap_t));
1198 *ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
1199 ret_len += sizeof(MrvlIETypes_ExtCap_t);
1200 pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
1201 }
1202 else if (pmpriv->hotspot_cfg & HOTSPOT_ENABLED)
1203 {
1204 wlan_add_ext_capa_info_ie(pmpriv, pbss_desc, ppbuffer);
1205 ret_len += sizeof(MrvlIETypes_ExtCap_t);
1206 }
1207 else
1208 {
1209 /* Do nothing */
1210 }
1211 if (orig_usr_dot_11n_dev_cap != 0U)
1212 {
1213 pmadapter->usr_dot_11n_dev_cap_bg = orig_usr_dot_11n_dev_cap;
1214 }
1215 LEAVE();
1216 return ret_len;
1217 }
1218
1219 #endif /* STA_SUPPORT */
1220
1221 /**
1222 * @brief 11n configuration handler
1223 *
1224 * @param pmadapter A pointer to mlan_adapter structure
1225 * @param pioctl_req A pointer to ioctl request buffer
1226 *
1227 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
1228 */
wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)1229 mlan_status wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
1230 {
1231 mlan_status status = MLAN_STATUS_SUCCESS;
1232 mlan_ds_11n_cfg *cfg = MNULL;
1233
1234 ENTER();
1235
1236 if (pioctl_req->buf_len < sizeof(mlan_ds_11n_cfg))
1237 {
1238 PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
1239 pioctl_req->data_read_written = 0;
1240 pioctl_req->buf_len_needed = sizeof(mlan_ds_11n_cfg);
1241 pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
1242 LEAVE();
1243 return MLAN_STATUS_RESOURCE;
1244 }
1245 cfg = (mlan_ds_11n_cfg *)(void *)pioctl_req->pbuf;
1246 switch (cfg->sub_command)
1247 {
1248 case MLAN_OID_11N_CFG_TX:
1249 status = wlan_11n_ioctl_httxcfg(pmadapter, pioctl_req);
1250 break;
1251 case MLAN_OID_11N_HTCAP_CFG:
1252 status = wlan_11n_ioctl_htusrcfg(pmadapter, pioctl_req);
1253 break;
1254 case MLAN_OID_11N_CFG_DELBA:
1255 status = wlan_11n_ioctl_delba(pmadapter, pioctl_req);
1256 break;
1257 default:
1258 pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
1259 status = MLAN_STATUS_FAILURE;
1260 break;
1261 }
1262 LEAVE();
1263 return status;
1264 }
1265
1266 /**
1267 * @brief This function will delete the given entry in Tx BA Stream table
1268 *
1269 * @param priv Pointer to mlan_private
1270 * @param ptx_tbl Pointer to tx ba stream entry to delete
1271 *
1272 * @return N/A
1273 */
wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,t_u8 * ra)1274 void wlan_11n_delete_txbastream_tbl_entry(mlan_private *priv, t_u8 *ra)
1275 {
1276 TxBAStreamTbl *ptx_tbl = MNULL;
1277 pmlan_adapter pmadapter = priv->adapter;
1278
1279 ENTER();
1280
1281 (void)pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->tx_ba_stream_tbl_ptr.plock);
1282
1283 if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, ra)))
1284 {
1285 PRINTM(MINFO, "Delete BA stream table entry: %p\n", ptx_tbl);
1286
1287 util_unlink_list(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr, (pmlan_linked_list)ptx_tbl, MNULL,
1288 MNULL);
1289 }
1290
1291 (void)pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->tx_ba_stream_tbl_ptr.plock);
1292
1293 #if !CONFIG_MEM_POOLS
1294 pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *)ptx_tbl);
1295 #else
1296 OSA_MemoryPoolFree(buf_128_MemoryPool, ptx_tbl);
1297 #endif
1298
1299 LEAVE();
1300 }
1301
1302 /**
1303 * @brief This function will delete all the entries in Tx BA Stream table
1304 *
1305 * @param priv A pointer to mlan_private
1306 *
1307 * @return N/A
1308 */
wlan_11n_deleteall_txbastream_tbl(mlan_private * priv)1309 void wlan_11n_deleteall_txbastream_tbl(mlan_private *priv)
1310 {
1311 TxBAStreamTbl *del_tbl_ptr = MNULL;
1312
1313 ENTER();
1314
1315 wlan_request_ralist_lock(priv);
1316 while ((del_tbl_ptr = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr,
1317 priv->adapter->callbacks.moal_spin_lock,
1318 priv->adapter->callbacks.moal_spin_unlock)) != NULL)
1319 {
1320 wlan_11n_delete_txbastream_tbl_entry(priv, del_tbl_ptr->ra);
1321 }
1322
1323 util_init_list((pmlan_linked_list)&priv->tx_ba_stream_tbl_ptr);
1324 wlan_release_ralist_lock(priv);
1325
1326 LEAVE();
1327 }
1328
1329 /**
1330 * @brief This function will return the pointer to an entry in BA Stream
1331 * table which matches the give RA/TID pair
1332 *
1333 * @param priv A pointer to mlan_private
1334 * @param ra RA to find in reordering table
1335 *
1336 * @return A pointer to first entry matching RA/TID in BA stream
1337 * NULL if not found
1338 */
wlan_11n_get_txbastream_tbl(mlan_private * priv,t_u8 * ra)1339 TxBAStreamTbl *wlan_11n_get_txbastream_tbl(mlan_private *priv, t_u8 *ra)
1340 {
1341 TxBAStreamTbl *ptx_tbl;
1342 pmlan_adapter pmadapter = priv->adapter;
1343
1344 ENTER();
1345 ptx_tbl = (TxBAStreamTbl *)(void *)util_peek_list(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr,
1346 pmadapter->callbacks.moal_spin_lock,
1347 pmadapter->callbacks.moal_spin_unlock);
1348 if (ptx_tbl == MNULL)
1349 {
1350 LEAVE();
1351 return MNULL;
1352 }
1353
1354 while (ptx_tbl != (TxBAStreamTbl *)(void *)&priv->tx_ba_stream_tbl_ptr)
1355 {
1356 DBG_HEXDUMP(MDAT_D, "RA", ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
1357
1358 if (!__memcmp(pmadapter, ptx_tbl->ra, ra, MLAN_MAC_ADDR_LENGTH))
1359 {
1360 LEAVE();
1361 return ptx_tbl;
1362 }
1363
1364 ptx_tbl = ptx_tbl->pnext;
1365 }
1366
1367 LEAVE();
1368 return MNULL;
1369 }
1370
1371 /**
1372 * @brief This function will create a entry in tx ba stream table for the
1373 * given RA/TID.
1374 *
1375 * @param priv A pointer to mlan_private
1376 * @param ra RA to find in reordering table
1377 * @param tid TID to find in reordering table
1378 * @param ba_status BA stream status to create the stream with
1379 *
1380 * @return N/A
1381 */
wlan_11n_create_txbastream_tbl(mlan_private * priv,t_u8 * ra,baStatus_e ba_status)1382 void wlan_11n_create_txbastream_tbl(mlan_private *priv, t_u8 *ra, baStatus_e ba_status)
1383 {
1384 TxBAStreamTbl *newNode = MNULL;
1385 pmlan_adapter pmadapter = priv->adapter;
1386
1387 ENTER();
1388
1389 if (!wlan_11n_get_txbastream_tbl(priv, ra))
1390 {
1391 DBG_HEXDUMP(MDAT_D, "RA", ra, MLAN_MAC_ADDR_LENGTH);
1392
1393 #if !CONFIG_MEM_POOLS
1394 pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle, sizeof(TxBAStreamTbl), MLAN_MEM_DEF,
1395 (t_u8 **)&newNode);
1396 #else
1397 newNode = OSA_MemoryPoolAllocate(buf_128_MemoryPool);
1398 #endif
1399 if (newNode == MNULL)
1400 {
1401 return;
1402 }
1403
1404 (void)__memset(pmadapter, newNode, 0, sizeof(TxBAStreamTbl));
1405 util_init_list((pmlan_linked_list)newNode);
1406
1407 newNode->ba_status = ba_status;
1408 newNode->txba_thresh = OSA_RandRange(5, 5);
1409 (void)__memcpy(pmadapter, newNode->ra, ra, MLAN_MAC_ADDR_LENGTH);
1410 (void)__memset(priv->adapter, newNode->rx_seq, 0xff, sizeof(newNode->rx_seq));
1411
1412 util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr, (pmlan_linked_list)newNode,
1413 pmadapter->callbacks.moal_spin_lock, pmadapter->callbacks.moal_spin_unlock);
1414 }
1415
1416 LEAVE();
1417 }
1418
1419 /**
1420 * @brief This function will update ampdu status in tx ba stream table for the
1421 * given RA/TID.
1422 *
1423 * @param priv A pointer to mlan_private
1424 * @param ra RA to find in reordering table
1425 * @param tid TID to find in reordering table
1426 * @param status ampdu status
1427 *
1428 * @return N/A
1429 */
1430
wlan_11n_update_txbastream_tbl_ampdu_stat(mlan_private * priv,t_u8 * ra,t_u8 status,t_u8 tid)1431 void wlan_11n_update_txbastream_tbl_ampdu_stat(mlan_private *priv, t_u8 *ra, t_u8 status, t_u8 tid)
1432 {
1433 TxBAStreamTbl *ptx_tbl;
1434
1435 ENTER();
1436
1437 if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, ra)))
1438 {
1439 ptx_tbl->ampdu_stat[tid] = status;
1440 }
1441 else
1442 PRINTM(MERROR, "update txbastream_tbl ampdu status error\n");
1443
1444 LEAVE();
1445 return;
1446 }
1447
1448 /**
1449 * @brief This function will update ampdu supported in tx ba stream table for the
1450 * given RA.
1451 *
1452 * @param priv A pointer to mlan_private
1453 * @param ra RA to find in reordering table
1454 * @param supported ampdu support
1455 *
1456 * @return N/A
1457 */
1458
wlan_11n_update_txbastream_tbl_ampdu_supported(mlan_private * priv,t_u8 * ra,t_u8 supported)1459 void wlan_11n_update_txbastream_tbl_ampdu_supported(mlan_private *priv, t_u8 *ra, t_u8 supported)
1460 {
1461 TxBAStreamTbl *ptx_tbl;
1462 int i;
1463
1464 ENTER();
1465
1466 if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, ra)))
1467 {
1468 for (i = 0; i < MAX_NUM_TID; i++)
1469 ptx_tbl->ampdu_supported[i] = supported;
1470 }
1471 else
1472 PRINTM(MERROR, "update txbastream_tbl ampdu supported error\n");
1473
1474 LEAVE();
1475 return;
1476 }
1477
1478 /**
1479 * @brief This function will update ampdu tx threshold in tx ba stream table for the
1480 * given RA.
1481 *
1482 * @param priv A pointer to mlan_private
1483 * @param ra RA to find in reordering table
1484 * @param tx_thresh tx ba threshold
1485 *
1486 * @return N/A
1487 */
1488
wlan_11n_update_txbastream_tbl_tx_thresh(mlan_private * priv,t_u8 * ra,t_u8 tx_thresh)1489 void wlan_11n_update_txbastream_tbl_tx_thresh(mlan_private *priv, t_u8 *ra, t_u8 tx_thresh)
1490 {
1491 TxBAStreamTbl *ptx_tbl;
1492
1493 ENTER();
1494
1495 if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, ra)))
1496 {
1497 ptx_tbl->txba_thresh = tx_thresh;
1498 }
1499 else
1500 PRINTM(MERROR, "update txbastream_tbl ampdu supported error\n");
1501
1502 LEAVE();
1503 return;
1504 }
1505
1506 /**
1507 * @brief This function will update ampdu supported in tx ba stream table for the
1508 * given RA.
1509 *
1510 * @param priv A pointer to mlan_private
1511 * @param ra RA to find in reordering table
1512 *
1513 * @return N/A
1514 */
1515
wlan_11n_update_txbastream_tbl_tx_cnt(mlan_private * priv,t_u8 * ra)1516 void wlan_11n_update_txbastream_tbl_tx_cnt(mlan_private *priv, t_u8 *ra)
1517 {
1518 TxBAStreamTbl *ptx_tbl;
1519
1520 ENTER();
1521
1522 if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, ra)))
1523 {
1524 ptx_tbl->txpkt_cnt++;
1525 }
1526 else
1527 PRINTM(MERROR, "update txbastream_tbl tx cnt error\n");
1528
1529 LEAVE();
1530 return;
1531 }
1532
1533 /**
1534 * @brief This function will get sta peer amsdu
1535 *
1536 * @param priv A pointer to mlan_private
1537 *
1538 * @return amsdu value
1539 */
1540
wlan_11n_get_sta_peer_amsdu(mlan_private * priv)1541 int wlan_11n_get_sta_peer_amsdu(mlan_private *priv)
1542 {
1543 TxBAStreamTbl *ptx_tbl = MNULL;
1544 int ret = MFALSE;
1545
1546 ENTER();
1547
1548 if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, priv->curr_bss_params.bss_descriptor.mac_address)))
1549 {
1550 ret = ptx_tbl->amsdu;
1551 }
1552
1553 LEAVE();
1554
1555 return ret;
1556 }
1557
1558 /**
1559 * @brief This function will send a block ack to given tid/ra
1560 *
1561 * @param priv A pointer to mlan_private
1562 * @param tid TID to send the ADDBA
1563 * @param peer_mac MAC address to send the ADDBA
1564 *
1565 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1566 */
wlan_send_addba(mlan_private * priv,int tid,const t_u8 * peer_mac)1567 int wlan_send_addba(mlan_private *priv, int tid, const t_u8 *peer_mac)
1568 {
1569 HostCmd_DS_11N_ADDBA_REQ add_ba_req;
1570 static t_u8 dialog_tok;
1571 mlan_status ret;
1572
1573 ENTER();
1574
1575 PRINTM(MCMND, "Send addba: TID %d\n", tid);
1576 DBG_HEXDUMP(MCMD_D, "Send addba RA", peer_mac, MLAN_MAC_ADDR_LENGTH);
1577
1578 add_ba_req.block_ack_param_set =
1579 (t_u16)((tid << BLOCKACKPARAM_TID_POS) | (priv->add_ba_param.tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
1580 IMMEDIATE_BLOCK_ACK);
1581 #if CONFIG_AMSDU_IN_AMPDU
1582 /** enable AMSDU inside AMPDU */
1583 /* To be done: change priv->aggr_prio_tbl[tid].amsdu for specific AMSDU support by CLI cmd */
1584 #if 0
1585 if (priv->add_ba_param.tx_amsdu && (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
1586 #else
1587 if (priv->add_ba_param.tx_amsdu && priv->bss_type == MLAN_BSS_TYPE_STA)
1588 #endif
1589 {
1590 add_ba_req.block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK;
1591 }
1592 #endif
1593 add_ba_req.block_ack_tmo = (t_u16)priv->add_ba_param.timeout;
1594
1595 ++dialog_tok;
1596
1597 if (dialog_tok == 0U)
1598 {
1599 dialog_tok = 1;
1600 }
1601
1602 add_ba_req.dialog_token = dialog_tok;
1603 (void)__memset(priv->adapter, &add_ba_req.peer_mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
1604 (void)__memcpy(priv->adapter, &add_ba_req.peer_mac_addr, peer_mac, MLAN_MAC_ADDR_LENGTH);
1605 #ifdef DUMP_PACKET_MAC
1606 wmprintf("wlan_send_addba bss_type:%d\r\n", priv->bss_type);
1607 dump_mac_addr(NULL, peer_mac);
1608 #endif
1609 /* We don't wait for the response of this command */
1610 ret = wifi_prepare_and_send_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, 0, 0, MNULL, &add_ba_req, priv->bss_type, NULL);
1611
1612 LEAVE();
1613 return ret;
1614 }
1615
1616 /**
1617 * @brief This function will delete a block ack to given tid/ra
1618 *
1619 * @param priv A pointer to mlan_private
1620 * @param pioctl_req A pointer to ioctl request buffer
1621 * @param tid TID to send the ADDBA
1622 * @param peer_mac MAC address to send the ADDBA
1623 * @param initiator MTRUE if we have initiated ADDBA, MFALSE otherwise
1624 *
1625 * @return MLAN_STATUS_PENDING --success, otherwise fail
1626 */
wlan_send_delba(mlan_private * priv,pmlan_ioctl_req pioctl_req,int tid,t_u8 * peer_mac,int initiator)1627 mlan_status wlan_send_delba(mlan_private *priv, pmlan_ioctl_req pioctl_req, int tid, t_u8 *peer_mac, int initiator)
1628 {
1629 HostCmd_DS_11N_DELBA delba;
1630 mlan_status ret;
1631
1632 ENTER();
1633
1634 __memset(priv->adapter, &delba, 0, sizeof(delba));
1635 delba.del_ba_param_set = (tid << DELBA_TID_POS);
1636
1637 if (initiator)
1638 DELBA_INITIATOR(delba.del_ba_param_set);
1639 else
1640 DELBA_RECIPIENT(delba.del_ba_param_set);
1641
1642 (void)__memcpy(priv->adapter, &delba.peer_mac_addr, peer_mac, MLAN_MAC_ADDR_LENGTH);
1643
1644 ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req, (t_void *)&delba);
1645
1646 if (ret == MLAN_STATUS_SUCCESS)
1647 ret = MLAN_STATUS_PENDING;
1648
1649 LEAVE();
1650 return ret;
1651 }
1652
1653 /**
1654 * @brief This function handles the command response of
1655 * delete a block ack request
1656 *
1657 * @param priv A pointer to mlan_private structure
1658 * @param del_ba A pointer to command response buffer
1659 *
1660 * @return N/A
1661 */
wlan_11n_delete_bastream(mlan_private * priv,t_u8 * del_ba)1662 void wlan_11n_delete_bastream(mlan_private *priv, t_u8 *del_ba)
1663 {
1664 HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *)(void *)del_ba;
1665 int tid;
1666
1667 ENTER();
1668
1669 DBG_HEXDUMP(MCMD_D, "Delba:", (t_u8 *)pdel_ba, 20);
1670 pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
1671 pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
1672
1673 tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
1674 mlan_11n_update_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr, TYPE_DELBA_RECEIVE,
1675 INITIATOR_BIT(pdel_ba->del_ba_param_set));
1676
1677 LEAVE();
1678 }
1679