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