1 /** @file mlan_11n.c
2 *
3 * @brief This file contains functions for 11n handling.
4 *
5 * Copyright (C) 2008-2017, Marvell International Ltd.
6 *
7 * This software file (the "File") is distributed by Marvell International
8 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9 * (the "License"). You may use, redistribute and/or modify this File in
10 * accordance with the terms and conditions of the License, a copy of which
11 * is available by writing to the Free Software Foundation, Inc.,
12 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14 *
15 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18 * this warranty disclaimer.
19 *
20 */
21
22 /********************************************************
23 Change log:
24 11/10/2008: initial version
25 ********************************************************/
26
27 #include "mlan.h"
28 #include "mlan_join.h"
29 #include "mlan_util.h"
30 #include "mlan_fw.h"
31 #include "mlan_main.h"
32 #include "mlan_wmm.h"
33 #include "mlan_11n.h"
34 /********************************************************
35 Local Variables
36 ********************************************************/
37
38 /********************************************************
39 Global Variables
40 ********************************************************/
41
42 /********************************************************
43 Local Functions
44 ********************************************************/
45
46 /**
47 *
48 * @brief set/get max tx buf size
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 */
55 static mlan_status
wlan_11n_ioctl_max_tx_buf_size(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)56 wlan_11n_ioctl_max_tx_buf_size(IN pmlan_adapter pmadapter,
57 IN pmlan_ioctl_req pioctl_req)
58 {
59 mlan_status ret = MLAN_STATUS_SUCCESS;
60 mlan_ds_11n_cfg *cfg = MNULL;
61 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
62
63 ENTER();
64 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
65 if (pioctl_req->action == MLAN_ACT_SET) {
66 if (cfg->param.tx_buf_size == 0xffff) {
67 PRINTM(MIOCTL, "Send reconfigure tx buf to FW\n");
68 ret = wlan_prepare_cmd(pmpriv,
69 HostCmd_CMD_RECONFIGURE_TX_BUFF,
70 HostCmd_ACT_GEN_SET, 0,
71 (t_void *)pioctl_req,
72 &cfg->param.tx_buf_size);
73 if (ret == MLAN_STATUS_SUCCESS)
74 ret = MLAN_STATUS_PENDING;
75 LEAVE();
76 return ret;
77 }
78 }
79 cfg->param.tx_buf_size = (t_u32)pmadapter->max_tx_buf_size;
80 pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
81
82 LEAVE();
83 return ret;
84 }
85
86 /**
87 * @brief Set/get htcapinfo configuration
88 *
89 * @param pmadapter A pointer to mlan_adapter structure
90 * @param pioctl_req A pointer to ioctl request buffer
91 *
92 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
93 */
94 static mlan_status
wlan_11n_ioctl_htusrcfg(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)95 wlan_11n_ioctl_htusrcfg(IN pmlan_adapter pmadapter,
96 IN pmlan_ioctl_req pioctl_req)
97 {
98 mlan_status ret = MLAN_STATUS_SUCCESS;
99 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
100 mlan_ds_11n_cfg *cfg = MNULL;
101
102 ENTER();
103
104 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
105
106 if (pioctl_req->action == MLAN_ACT_SET) {
107 if (((cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP) &
108 pmpriv->adapter->hw_dot_11n_dev_cap)
109 != (cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP)) {
110 pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
111 ret = MLAN_STATUS_FAILURE;
112 } else {
113 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
114 pmpriv->usr_dot_11n_dev_cap_bg =
115 cfg->param.htcap_cfg.htcap;
116 PRINTM(MINFO,
117 "Set: UsrDot11nCap for 2.4GHz 0x%x\n",
118 pmpriv->usr_dot_11n_dev_cap_bg);
119 }
120 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
121 pmpriv->usr_dot_11n_dev_cap_a =
122 cfg->param.htcap_cfg.htcap;
123 PRINTM(MINFO,
124 "Set: UsrDot11nCap for 5GHz 0x%x\n",
125 pmpriv->usr_dot_11n_dev_cap_a);
126 }
127 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BOTH) {
128 pmpriv->usr_dot_11n_dev_cap_bg =
129 cfg->param.htcap_cfg.htcap;
130 pmpriv->usr_dot_11n_dev_cap_a =
131 cfg->param.htcap_cfg.htcap;
132 PRINTM(MINFO,
133 "Set: UsrDot11nCap for 2.4GHz and 5GHz 0x%x\n",
134 cfg->param.htcap_cfg.htcap);
135 }
136 }
137 } else {
138 /* Hardware 11N device capability required */
139 if (cfg->param.htcap_cfg.hw_cap_req)
140 cfg->param.htcap_cfg.htcap =
141 pmadapter->hw_dot_11n_dev_cap;
142 else {
143 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
144 cfg->param.htcap_cfg.htcap =
145 pmpriv->usr_dot_11n_dev_cap_bg;
146 PRINTM(MINFO,
147 "Get: UsrDot11nCap for 2.4GHz 0x%x\n",
148 cfg->param.htcap_cfg.htcap);
149 }
150 if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
151 cfg->param.htcap_cfg.htcap =
152 pmpriv->usr_dot_11n_dev_cap_a;
153 PRINTM(MINFO,
154 "Get: UsrDot11nCap for 5GHz 0x%x\n",
155 cfg->param.htcap_cfg.htcap);
156 }
157 }
158 }
159
160 LEAVE();
161 return ret;
162 }
163
164 /**
165 * @brief Enable/Disable AMSDU AGGR CTRL
166 *
167 * @param pmadapter A pointer to mlan_adapter structure
168 * @param pioctl_req A pointer to ioctl request buffer
169 *
170 * @return MLAN_STATUS_PENDING --success, otherwise fail
171 */
172 static mlan_status
wlan_11n_ioctl_amsdu_aggr_ctrl(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)173 wlan_11n_ioctl_amsdu_aggr_ctrl(IN pmlan_adapter pmadapter,
174 IN pmlan_ioctl_req pioctl_req)
175 {
176 mlan_status ret = MLAN_STATUS_SUCCESS;
177 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
178 mlan_ds_11n_cfg *cfg = MNULL;
179 t_u16 cmd_action = 0;
180
181 ENTER();
182
183 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
184 if (pioctl_req->action == MLAN_ACT_SET)
185 cmd_action = HostCmd_ACT_GEN_SET;
186 else
187 cmd_action = HostCmd_ACT_GEN_GET;
188
189 /* Send request to firmware */
190 ret = wlan_prepare_cmd(pmpriv,
191 HostCmd_CMD_AMSDU_AGGR_CTRL,
192 cmd_action,
193 0,
194 (t_void *)pioctl_req,
195 (t_void *)&cfg->param.amsdu_aggr_ctrl);
196 if (ret == MLAN_STATUS_SUCCESS)
197 ret = MLAN_STATUS_PENDING;
198
199 LEAVE();
200 return ret;
201 }
202
203 /**
204 * @brief Set/get 11n configuration
205 *
206 * @param pmadapter A pointer to mlan_adapter structure
207 * @param pioctl_req A pointer to ioctl request buffer
208 *
209 * @return MLAN_STATUS_PENDING --success, otherwise fail
210 */
211 static mlan_status
wlan_11n_ioctl_httxcfg(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)212 wlan_11n_ioctl_httxcfg(IN pmlan_adapter pmadapter,
213 IN pmlan_ioctl_req pioctl_req)
214 {
215 mlan_status ret = MLAN_STATUS_SUCCESS;
216 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
217 mlan_ds_11n_cfg *cfg = MNULL;
218 t_u16 cmd_action = 0;
219
220 ENTER();
221
222 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
223 if (pioctl_req->action == MLAN_ACT_SET)
224 cmd_action = HostCmd_ACT_GEN_SET;
225 else
226 cmd_action = HostCmd_ACT_GEN_GET;
227
228 /* Send request to firmware */
229 ret = wlan_prepare_cmd(pmpriv,
230 HostCmd_CMD_11N_CFG,
231 cmd_action,
232 0,
233 (t_void *)pioctl_req,
234 (t_void *)&cfg->param.tx_cfg);
235 if (ret == MLAN_STATUS_SUCCESS)
236 ret = MLAN_STATUS_PENDING;
237
238 LEAVE();
239 return ret;
240 }
241
242 /**
243 * @brief Set/get TX beamforming capabilities
244 *
245 * @param pmadapter A pointer to mlan_adapter structure
246 * @param pioctl_req A pointer to ioctl request buffer
247 *
248 * @return MLAN_STATUS_SUCCESS --success
249 */
250 static mlan_status
wlan_11n_ioctl_tx_bf_cap(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)251 wlan_11n_ioctl_tx_bf_cap(IN pmlan_adapter pmadapter,
252 IN pmlan_ioctl_req pioctl_req)
253 {
254 mlan_status ret = MLAN_STATUS_SUCCESS;
255 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
256 mlan_ds_11n_cfg *cfg = MNULL;
257
258 ENTER();
259
260 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
261 if (pioctl_req->action == MLAN_ACT_SET)
262 pmpriv->tx_bf_cap = cfg->param.tx_bf_cap;
263 else
264 cfg->param.tx_bf_cap = pmpriv->tx_bf_cap;
265
266 LEAVE();
267 return ret;
268 }
269
270 /**
271 * @brief Set/get TX beamforming configurations
272 *
273 * @param pmadapter A pointer to mlan_adapter structure
274 * @param pioctl_req A pointer to ioctl request buffer
275 *
276 * @return MLAN_STATUS_PENDING --success, otherwise fail
277 */
278 static mlan_status
wlan_11n_ioctl_tx_bf_cfg(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)279 wlan_11n_ioctl_tx_bf_cfg(IN pmlan_adapter pmadapter,
280 IN pmlan_ioctl_req pioctl_req)
281 {
282 mlan_status ret = MLAN_STATUS_SUCCESS;
283 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
284 mlan_ds_11n_cfg *cfg = MNULL;
285 t_u16 cmd_action = 0;
286
287 ENTER();
288
289 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
290 if (pioctl_req->action == MLAN_ACT_SET)
291 cmd_action = HostCmd_ACT_GEN_SET;
292 else
293 cmd_action = HostCmd_ACT_GEN_GET;
294
295 /* Send request to firmware */
296 ret = wlan_prepare_cmd(pmpriv,
297 HostCmd_CMD_TX_BF_CFG,
298 cmd_action,
299 0,
300 (t_void *)pioctl_req,
301 (t_void *)&cfg->param.tx_bf);
302 if (ret == MLAN_STATUS_SUCCESS)
303 ret = MLAN_STATUS_PENDING;
304
305 LEAVE();
306 return ret;
307 }
308
309 /**
310 * @brief Set/get control to coex RX window size configuration
311 *
312 * @param pmadapter A pointer to mlan_adapter structure
313 * @param pioctl_req A pointer to ioctl request buffer
314 *
315 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
316 */
317 static mlan_status
wlan_11n_ioctl_coex_rx_winsize(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)318 wlan_11n_ioctl_coex_rx_winsize(IN pmlan_adapter pmadapter,
319 IN pmlan_ioctl_req pioctl_req)
320 {
321 mlan_status ret = MLAN_STATUS_SUCCESS;
322 mlan_ds_11n_cfg *cfg = MNULL;
323
324 ENTER();
325
326 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
327 if (pioctl_req->action == MLAN_ACT_GET)
328 cfg->param.coex_rx_winsize = pmadapter->coex_rx_winsize;
329 else if (pioctl_req->action == MLAN_ACT_SET)
330 pmadapter->coex_rx_winsize = (t_u8)cfg->param.coex_rx_winsize;
331
332 LEAVE();
333 return ret;
334 }
335
336 /**
337 * @brief This function will send delba request to
338 * the peer in the TxBAStreamTbl
339 *
340 * @param priv A pointer to mlan_private
341 * @param ra MAC Address to send DELBA
342 *
343 * @return N/A
344 */
345 void
wlan_11n_send_delba_to_peer(mlan_private * priv,t_u8 * ra)346 wlan_11n_send_delba_to_peer(mlan_private *priv, t_u8 *ra)
347 {
348
349 TxBAStreamTbl *ptx_tbl;
350
351 ENTER();
352 wlan_request_ralist_lock(priv);
353 ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
354 &priv->tx_ba_stream_tbl_ptr,
355 MNULL, MNULL);
356 if (!ptx_tbl) {
357 wlan_release_ralist_lock(priv);
358 LEAVE();
359 return;
360 }
361
362 while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
363 if (!memcmp
364 (priv->adapter, ptx_tbl->ra, ra, MLAN_MAC_ADDR_LENGTH)) {
365 PRINTM(MIOCTL, "Tx:Send delba to tid=%d, " MACSTR "\n",
366 ptx_tbl->tid, MAC2STR(ptx_tbl->ra));
367 wlan_send_delba(priv, MNULL, ptx_tbl->tid, ptx_tbl->ra,
368 1);
369 }
370 ptx_tbl = ptx_tbl->pnext;
371 }
372 wlan_release_ralist_lock(priv);
373 /* Signal MOAL to trigger mlan_main_process */
374 wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
375 LEAVE();
376 return;
377 }
378
379 /**
380 * @brief Set/Get control to TX AMPDU configuration on infra link
381 *
382 * @param pmadapter A pointer to mlan_adapter structure
383 * @param pioctl_req A pointer to ioctl request buffer
384 *
385 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
386 */
387 static mlan_status
wlan_11n_ioctl_txaggrctrl(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)388 wlan_11n_ioctl_txaggrctrl(IN pmlan_adapter pmadapter,
389 IN pmlan_ioctl_req pioctl_req)
390 {
391 mlan_status ret = MLAN_STATUS_SUCCESS;
392 mlan_ds_11n_cfg *cfg = MNULL;
393 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
394
395 ENTER();
396
397 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
398 if (pioctl_req->action == MLAN_ACT_GET)
399 cfg->param.txaggrctrl = pmpriv->txaggrctrl;
400 else if (pioctl_req->action == MLAN_ACT_SET)
401 pmpriv->txaggrctrl = (t_u8)cfg->param.txaggrctrl;
402
403 if (pmpriv->media_connected == MTRUE) {
404 if (pioctl_req->action == MLAN_ACT_SET
405 && !pmpriv->txaggrctrl
406 && pmpriv->adapter->tdls_status != TDLS_NOT_SETUP)
407 wlan_11n_send_delba_to_peer(pmpriv,
408 pmpriv->curr_bss_params.
409 bss_descriptor.mac_address);
410 }
411 LEAVE();
412 return ret;
413 }
414
415 /**
416 * @brief This function will resend addba request to all
417 * the peer in the TxBAStreamTbl
418 *
419 * @param priv A pointer to mlan_private
420 *
421 * @return N/A
422 */
423 static void
wlan_11n_update_addba_request(mlan_private * priv)424 wlan_11n_update_addba_request(mlan_private *priv)
425 {
426
427 TxBAStreamTbl *ptx_tbl;
428
429 ENTER();
430
431 wlan_request_ralist_lock(priv);
432 ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
433 &priv->tx_ba_stream_tbl_ptr,
434 MNULL, MNULL);
435 if (!ptx_tbl) {
436 wlan_release_ralist_lock(priv);
437 LEAVE();
438 return;
439 }
440
441 while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
442 wlan_send_addba(priv, ptx_tbl->tid, ptx_tbl->ra);
443 ptx_tbl = ptx_tbl->pnext;
444 }
445 wlan_release_ralist_lock(priv);
446 /* Signal MOAL to trigger mlan_main_process */
447 wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
448 LEAVE();
449 return;
450 }
451
452 /**
453 * @brief Set/get addba parameter
454 *
455 * @param pmadapter A pointer to mlan_adapter structure
456 * @param pioctl_req A pointer to ioctl request buffer
457 *
458 * @return MLAN_STATUS_SUCCESS --success
459 */
460 static mlan_status
wlan_11n_ioctl_addba_param(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)461 wlan_11n_ioctl_addba_param(IN pmlan_adapter pmadapter,
462 IN pmlan_ioctl_req pioctl_req)
463 {
464 mlan_status ret = MLAN_STATUS_SUCCESS;
465 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
466 mlan_ds_11n_cfg *cfg = MNULL;
467 t_u32 timeout;
468
469 ENTER();
470
471 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
472 if (pioctl_req->action == MLAN_ACT_GET) {
473 cfg->param.addba_param.timeout = pmpriv->add_ba_param.timeout;
474 cfg->param.addba_param.txwinsize =
475 pmpriv->add_ba_param.tx_win_size;
476 cfg->param.addba_param.rxwinsize =
477 pmpriv->add_ba_param.rx_win_size;
478 cfg->param.addba_param.txamsdu = pmpriv->add_ba_param.tx_amsdu;
479 cfg->param.addba_param.rxamsdu = pmpriv->add_ba_param.rx_amsdu;
480 } else {
481 timeout = pmpriv->add_ba_param.timeout;
482 pmpriv->add_ba_param.timeout = cfg->param.addba_param.timeout;
483 pmpriv->add_ba_param.tx_win_size =
484 cfg->param.addba_param.txwinsize;
485
486 pmpriv->add_ba_param.rx_win_size =
487 cfg->param.addba_param.rxwinsize;
488 pmpriv->user_rxwinsize = pmpriv->add_ba_param.rx_win_size;
489 pmpriv->add_ba_param.tx_amsdu = cfg->param.addba_param.txamsdu;
490 pmpriv->add_ba_param.rx_amsdu = cfg->param.addba_param.rxamsdu;
491 if (timeout != pmpriv->add_ba_param.timeout)
492 wlan_11n_update_addba_request(pmpriv);
493 }
494
495 LEAVE();
496 return ret;
497 }
498
499 /**
500 * @brief This function send delba to specific tid
501 *
502 * @param priv A pointer to mlan_priv
503 * @param tid tid
504 * @return N/A
505 */
506 void
wlan_11n_delba(mlan_private * priv,int tid)507 wlan_11n_delba(mlan_private *priv, int tid)
508 {
509 RxReorderTbl *rx_reor_tbl_ptr;
510
511 ENTER();
512
513 rx_reor_tbl_ptr =
514 (RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
515 &priv->rx_reorder_tbl_ptr,
516 priv->adapter->callbacks.
517 moal_spin_lock,
518 priv->adapter->callbacks.
519 moal_spin_unlock);
520 if (!rx_reor_tbl_ptr) {
521 LEAVE();
522 return;
523 }
524
525 while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
526 if (rx_reor_tbl_ptr->tid == tid) {
527 PRINTM(MIOCTL, "Send delba to tid=%d, " MACSTR "\n",
528 tid, MAC2STR(rx_reor_tbl_ptr->ta));
529 wlan_send_delba(priv, MNULL, tid, rx_reor_tbl_ptr->ta,
530 0);
531 LEAVE();
532 return;
533 }
534 rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
535 }
536
537 LEAVE();
538 return;
539 }
540
541 /**
542 * @brief Set/get addba reject set
543 *
544 * @param pmadapter A pointer to mlan_adapter structure
545 * @param pioctl_req A pointer to ioctl request buffer
546 *
547 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
548 */
549 static mlan_status
wlan_11n_ioctl_addba_reject(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)550 wlan_11n_ioctl_addba_reject(IN pmlan_adapter pmadapter,
551 IN pmlan_ioctl_req pioctl_req)
552 {
553 int i = 0;
554 mlan_status ret = MLAN_STATUS_SUCCESS;
555 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
556 mlan_ds_11n_cfg *cfg = MNULL;
557
558 ENTER();
559
560 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
561
562 if (pioctl_req->action == MLAN_ACT_GET) {
563 PRINTM(MINFO, "Get Addba reject\n");
564 memcpy(pmadapter, cfg->param.addba_reject, pmpriv->addba_reject,
565 MAX_NUM_TID);
566 } else {
567 for (i = 0; i < MAX_NUM_TID; i++) {
568 /* For AMPDU */
569 if (cfg->param.addba_reject[i] >
570 ADDBA_RSP_STATUS_REJECT) {
571 pioctl_req->status_code =
572 MLAN_ERROR_INVALID_PARAMETER;
573 ret = MLAN_STATUS_FAILURE;
574 break;
575 }
576
577 pmpriv->addba_reject[i] = cfg->param.addba_reject[i];
578 }
579 if (pmpriv->media_connected == MTRUE) {
580 for (i = 0; i < MAX_NUM_TID; i++) {
581 if (cfg->param.addba_reject[i] ==
582 ADDBA_RSP_STATUS_REJECT) {
583 PRINTM(MIOCTL,
584 "Receive addba reject: tid=%d\n",
585 i);
586 wlan_11n_delba(pmpriv, i);
587 }
588 }
589 wlan_recv_event(pmpriv,
590 MLAN_EVENT_ID_DRV_DEFER_HANDLING,
591 MNULL);
592 }
593 }
594
595 LEAVE();
596 return ret;
597 }
598
599 /**
600 * @brief Set/get ibss ampdu param
601 *
602 * @param pmadapter A pointer to mlan_adapter structure
603 * @param pioctl_req A pointer to ioctl request buffer
604 *
605 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
606 */
607 static mlan_status
wlan_11n_ioctl_ibss_ampdu_param(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)608 wlan_11n_ioctl_ibss_ampdu_param(IN pmlan_adapter pmadapter,
609 IN pmlan_ioctl_req pioctl_req)
610 {
611 int i = 0;
612 mlan_status ret = MLAN_STATUS_SUCCESS;
613 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
614 mlan_ds_11n_cfg *cfg = MNULL;
615
616 ENTER();
617
618 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
619
620 if (pioctl_req->action == MLAN_ACT_GET) {
621 PRINTM(MINFO, "Get IBSS AMPDU param\n");
622 for (i = 0; i < MAX_NUM_TID; i++) {
623 cfg->param.ibss_ampdu.ampdu[i] = pmpriv->ibss_ampdu[i];
624 cfg->param.ibss_ampdu.addba_reject[i] =
625 pmpriv->ibss_addba_reject[i];
626 }
627 } else {
628 for (i = 0; i < MAX_NUM_TID; i++) {
629 /* For AMPDU RX */
630 if (cfg->param.ibss_ampdu.addba_reject[i] >
631 ADDBA_RSP_STATUS_REJECT) {
632 pioctl_req->status_code =
633 MLAN_ERROR_INVALID_PARAMETER;
634 ret = MLAN_STATUS_FAILURE;
635 break;
636 }
637 pmpriv->ibss_addba_reject[i] =
638 cfg->param.ibss_ampdu.addba_reject[i];
639 /* For AMPDU TX */
640 if ((cfg->param.ibss_ampdu.ampdu[i] > HIGH_PRIO_TID) &&
641 (cfg->param.ibss_ampdu.ampdu[i] !=
642 BA_STREAM_NOT_ALLOWED)) {
643 pioctl_req->status_code =
644 MLAN_ERROR_INVALID_PARAMETER;
645 ret = MLAN_STATUS_FAILURE;
646 break;
647 }
648 pmpriv->ibss_ampdu[i] = cfg->param.ibss_ampdu.ampdu[i];
649 }
650 PRINTM(MMSG, "IBSS addba reject: %d %d %d %d %d %d %d %d\n",
651 pmpriv->ibss_addba_reject[0],
652 pmpriv->ibss_addba_reject[1],
653 pmpriv->ibss_addba_reject[2],
654 pmpriv->ibss_addba_reject[3],
655 pmpriv->ibss_addba_reject[4],
656 pmpriv->ibss_addba_reject[5],
657 pmpriv->ibss_addba_reject[6],
658 pmpriv->ibss_addba_reject[7]);
659 PRINTM(MMSG, "IBSS ampdu %d %d %d %d %d %d %d %d\n",
660 pmpriv->ibss_ampdu[0], pmpriv->ibss_ampdu[1],
661 pmpriv->ibss_ampdu[2], pmpriv->ibss_ampdu[3],
662 pmpriv->ibss_ampdu[4], pmpriv->ibss_ampdu[5],
663 pmpriv->ibss_ampdu[6], pmpriv->ibss_ampdu[7]);
664 }
665 LEAVE();
666 return ret;
667 }
668
669 /**
670 * @brief This function will send DELBA to entries in the priv's
671 * Tx BA stream table
672 *
673 * @param priv A pointer to mlan_private
674 * @param pioctl_req A pointer to ioctl request buffer
675 * @param tid TID
676 * @param peer_address A pointer to peer address
677 * @param last_tx_ba_to_delete A pointer to the last entry in TxBAStreamTbl
678 *
679 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
680 */
681 static mlan_status
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)682 wlan_send_delba_to_entry_in_txbastream_tbl(pmlan_private priv,
683 pmlan_ioctl_req pioctl_req, t_u8 tid,
684 t_u8 *peer_address,
685 TxBAStreamTbl *last_tx_ba_to_delete)
686 {
687 pmlan_adapter pmadapter = priv->adapter;
688 TxBAStreamTbl *tx_ba_stream_tbl_ptr;
689 t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0 };
690 mlan_status ret = MLAN_STATUS_SUCCESS;
691
692 ENTER();
693
694 wlan_request_ralist_lock(priv);
695 tx_ba_stream_tbl_ptr =
696 (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle,
697 &priv->tx_ba_stream_tbl_ptr,
698 MNULL, MNULL);
699 if (!tx_ba_stream_tbl_ptr) {
700 wlan_release_ralist_lock(priv);
701 LEAVE();
702 return ret;
703 }
704
705 while (tx_ba_stream_tbl_ptr !=
706 (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
707 if (tx_ba_stream_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE) {
708 if (((tid == DELBA_ALL_TIDS) ||
709 (tid == tx_ba_stream_tbl_ptr->tid)) &&
710 (!memcmp
711 (pmadapter, peer_address, zero_mac,
712 MLAN_MAC_ADDR_LENGTH) ||
713 !memcmp(pmadapter, peer_address,
714 tx_ba_stream_tbl_ptr->ra,
715 MLAN_MAC_ADDR_LENGTH))) {
716 if (last_tx_ba_to_delete &&
717 (tx_ba_stream_tbl_ptr ==
718 last_tx_ba_to_delete))
719 ret = wlan_send_delba(priv, pioctl_req,
720 tx_ba_stream_tbl_ptr->
721 tid,
722 tx_ba_stream_tbl_ptr->
723 ra, 1);
724 else
725 ret = wlan_send_delba(priv, MNULL,
726 tx_ba_stream_tbl_ptr->
727 tid,
728 tx_ba_stream_tbl_ptr->
729 ra, 1);
730 }
731 }
732 tx_ba_stream_tbl_ptr = tx_ba_stream_tbl_ptr->pnext;
733 }
734 wlan_release_ralist_lock(priv);
735
736 LEAVE();
737 return ret;
738 }
739
740 /**
741 * @brief This function will send DELBA to entries in the priv's
742 * rx reordering table
743 *
744 * @param priv A pointer to mlan_private
745 * @param pioctl_req A pointer to ioctl request buffer
746 * @param tid TID
747 * @param peer_address A pointer to peer address
748 * @param last_rx_ba_to_delete A pointer to the last entry in RxReorderTbl
749 *
750 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
751 */
752 static mlan_status
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)753 wlan_send_delba_to_entry_in_reorder_tbl(pmlan_private priv,
754 pmlan_ioctl_req pioctl_req, t_u8 tid,
755 t_u8 *peer_address,
756 RxReorderTbl *last_rx_ba_to_delete)
757 {
758 pmlan_adapter pmadapter = priv->adapter;
759 RxReorderTbl *rx_reor_tbl_ptr;
760 t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0 };
761 mlan_status ret = MLAN_STATUS_SUCCESS;
762
763 ENTER();
764
765 rx_reor_tbl_ptr =
766 (RxReorderTbl *)util_peek_list(pmadapter->pmoal_handle,
767 &priv->rx_reorder_tbl_ptr,
768 pmadapter->callbacks.
769 moal_spin_lock,
770 pmadapter->callbacks.
771 moal_spin_unlock);
772 if (!rx_reor_tbl_ptr) {
773 LEAVE();
774 return ret;
775 }
776
777 while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
778 if (rx_reor_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE) {
779 if (((tid == DELBA_ALL_TIDS) ||
780 (tid == rx_reor_tbl_ptr->tid)) &&
781 (!memcmp
782 (pmadapter, peer_address, zero_mac,
783 MLAN_MAC_ADDR_LENGTH) ||
784 !memcmp(pmadapter, peer_address,
785 rx_reor_tbl_ptr->ta,
786 MLAN_MAC_ADDR_LENGTH))) {
787 if (last_rx_ba_to_delete &&
788 (rx_reor_tbl_ptr == last_rx_ba_to_delete))
789 ret = wlan_send_delba(priv, pioctl_req,
790 rx_reor_tbl_ptr->
791 tid,
792 rx_reor_tbl_ptr->
793 ta, 0);
794 else
795 ret = wlan_send_delba(priv, MNULL,
796 rx_reor_tbl_ptr->
797 tid,
798 rx_reor_tbl_ptr->
799 ta, 0);
800 }
801 }
802 rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
803 }
804
805 LEAVE();
806 return ret;
807 }
808
809 /**
810 * @brief IOCTL to delete BA
811 *
812 * @param pmadapter A pointer to mlan_adapter structure
813 * @param pioctl_req A pointer to ioctl request buffer
814 *
815 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
816 */
817 static mlan_status
wlan_11n_ioctl_delba(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)818 wlan_11n_ioctl_delba(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
819 {
820 mlan_status ret = MLAN_STATUS_SUCCESS;
821 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
822 mlan_ds_11n_cfg *cfg = MNULL;
823 TxBAStreamTbl *tx_ba_stream_tbl_ptr, *last_tx_ba_to_delete = MNULL;
824 RxReorderTbl *rx_reor_tbl_ptr, *last_rx_ba_to_delete = MNULL;
825 t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0 };
826 t_u8 tid, *peer_address;
827
828 ENTER();
829
830 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
831 tid = cfg->param.del_ba.tid;
832 peer_address = cfg->param.del_ba.peer_mac_addr;
833
834 PRINTM(MINFO, "DelBA: direction %d, TID %d, peer address " MACSTR "\n",
835 cfg->param.del_ba.direction, tid, MAC2STR(peer_address));
836
837 if (cfg->param.del_ba.direction & DELBA_RX) {
838 rx_reor_tbl_ptr =
839 (RxReorderTbl *)util_peek_list(pmadapter->pmoal_handle,
840 &pmpriv->
841 rx_reorder_tbl_ptr,
842 pmadapter->callbacks.
843 moal_spin_lock,
844 pmadapter->callbacks.
845 moal_spin_unlock);
846
847 if (rx_reor_tbl_ptr) {
848 while (rx_reor_tbl_ptr !=
849 (RxReorderTbl *)&pmpriv->rx_reorder_tbl_ptr) {
850 if (rx_reor_tbl_ptr->ba_status ==
851 BA_STREAM_SETUP_COMPLETE) {
852 if (((tid == DELBA_ALL_TIDS) ||
853 (tid == rx_reor_tbl_ptr->tid)) &&
854 (!memcmp
855 (pmadapter, peer_address, zero_mac,
856 MLAN_MAC_ADDR_LENGTH) ||
857 !memcmp(pmadapter, peer_address,
858 rx_reor_tbl_ptr->ta,
859 MLAN_MAC_ADDR_LENGTH))) {
860 /* Found RX BA to delete */
861 last_rx_ba_to_delete =
862 rx_reor_tbl_ptr;
863 }
864 }
865 rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
866 }
867 }
868 }
869
870 if ((last_rx_ba_to_delete == MNULL) &&
871 (cfg->param.del_ba.direction & DELBA_TX)) {
872 wlan_request_ralist_lock(pmpriv);
873 tx_ba_stream_tbl_ptr =
874 (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle,
875 &pmpriv->
876 tx_ba_stream_tbl_ptr,
877 MNULL, MNULL);
878
879 if (tx_ba_stream_tbl_ptr) {
880 while (tx_ba_stream_tbl_ptr !=
881 (TxBAStreamTbl *)&pmpriv->tx_ba_stream_tbl_ptr) {
882 if (tx_ba_stream_tbl_ptr->ba_status ==
883 BA_STREAM_SETUP_COMPLETE) {
884 if (((tid == DELBA_ALL_TIDS) ||
885 (tid == tx_ba_stream_tbl_ptr->tid))
886 &&
887 (!memcmp
888 (pmadapter, peer_address, zero_mac,
889 MLAN_MAC_ADDR_LENGTH) ||
890 !memcmp(pmadapter, peer_address,
891 tx_ba_stream_tbl_ptr->ra,
892 MLAN_MAC_ADDR_LENGTH))) {
893 /* Found TX BA to delete */
894 last_tx_ba_to_delete =
895 tx_ba_stream_tbl_ptr;
896 }
897 }
898 tx_ba_stream_tbl_ptr =
899 tx_ba_stream_tbl_ptr->pnext;
900 }
901 }
902 wlan_release_ralist_lock(pmpriv);
903 }
904
905 if (cfg->param.del_ba.direction & DELBA_TX) {
906 if (last_rx_ba_to_delete)
907 ret = wlan_send_delba_to_entry_in_txbastream_tbl(pmpriv,
908 MNULL,
909 tid,
910 peer_address,
911 MNULL);
912 else
913 ret = wlan_send_delba_to_entry_in_txbastream_tbl(pmpriv,
914 pioctl_req,
915 tid,
916 peer_address,
917 last_tx_ba_to_delete);
918 }
919 if (last_rx_ba_to_delete) {
920 ret = wlan_send_delba_to_entry_in_reorder_tbl(pmpriv,
921 pioctl_req, tid,
922 peer_address,
923 last_rx_ba_to_delete);
924 }
925
926 LEAVE();
927 return ret;
928 }
929
930 /**
931 * @brief IOCTL to reject addba req
932 *
933 * @param pmadapter A pointer to mlan_adapter structure
934 * @param pioctl_req A pointer to ioctl request buffer
935 *
936 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
937 */
938 static mlan_status
wlan_11n_ioctl_rejectaddbareq(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)939 wlan_11n_ioctl_rejectaddbareq(IN pmlan_adapter pmadapter,
940 IN pmlan_ioctl_req pioctl_req)
941 {
942 mlan_status ret = MLAN_STATUS_SUCCESS;
943 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
944 mlan_ds_11n_cfg *cfg = MNULL;
945 t_u16 cmd_action = 0;
946
947 ENTER();
948
949 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
950 if (pioctl_req->action == MLAN_ACT_SET)
951 cmd_action = HostCmd_ACT_GEN_SET;
952 else
953 cmd_action = HostCmd_ACT_GEN_GET;
954
955 /* Send command to firmware */
956 ret = wlan_prepare_cmd(pmpriv,
957 HostCmd_CMD_REJECT_ADDBA_REQ,
958 cmd_action,
959 0,
960 (t_void *)pioctl_req,
961 &cfg->param.reject_addba_req);
962
963 if (ret == MLAN_STATUS_SUCCESS)
964 ret = MLAN_STATUS_PENDING;
965
966 LEAVE();
967 return ret;
968 }
969
970 /**
971 * @brief This function will send DELBA to entries in the priv's
972 * Tx BA stream table
973 *
974 * @param priv A pointer to mlan_private
975 * @param tid TID
976 *
977 * @return N/A
978 */
979 static void
wlan_send_delba_txbastream_tbl(pmlan_private priv,t_u8 tid)980 wlan_send_delba_txbastream_tbl(pmlan_private priv, t_u8 tid)
981 {
982 pmlan_adapter pmadapter = priv->adapter;
983 TxBAStreamTbl *tx_ba_stream_tbl_ptr;
984
985 ENTER();
986
987 wlan_request_ralist_lock(priv);
988 tx_ba_stream_tbl_ptr =
989 (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle,
990 &priv->tx_ba_stream_tbl_ptr,
991 MNULL, MNULL);
992 if (!tx_ba_stream_tbl_ptr) {
993 wlan_release_ralist_lock(priv);
994 LEAVE();
995 return;
996 }
997
998 while (tx_ba_stream_tbl_ptr !=
999 (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
1000 if (tx_ba_stream_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE) {
1001 if (tid == tx_ba_stream_tbl_ptr->tid) {
1002 PRINTM(MIOCTL,
1003 "Tx:Send delba to tid=%d, " MACSTR "\n",
1004 tid, MAC2STR(tx_ba_stream_tbl_ptr->ra));
1005 wlan_release_ralist_lock(priv);
1006 wlan_send_delba(priv, MNULL,
1007 tx_ba_stream_tbl_ptr->tid,
1008 tx_ba_stream_tbl_ptr->ra, 1);
1009 LEAVE();
1010 return;
1011 }
1012 }
1013 tx_ba_stream_tbl_ptr = tx_ba_stream_tbl_ptr->pnext;
1014 }
1015 wlan_release_ralist_lock(priv);
1016
1017 LEAVE();
1018 return;
1019 }
1020
1021 /**
1022 * @brief update station list for the new aggr_prio_tbl setting
1023 *
1024 * @param priv A pointer to mlan_private structure
1025 *
1026 *
1027 * @return N/A
1028 */
1029 void
wlan_update_all_stations_ampdu(mlan_private * priv)1030 wlan_update_all_stations_ampdu(mlan_private *priv)
1031 {
1032 sta_node *sta_ptr;
1033 mlan_adapter *pmadapter = priv->adapter;
1034 int i = 0;
1035
1036 ENTER();
1037 pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
1038 priv->wmm.ra_list_spinlock);
1039 sta_ptr = (sta_node *)util_peek_list(pmadapter->pmoal_handle,
1040 &priv->sta_list, MNULL, MNULL);
1041 if (!sta_ptr) {
1042 pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
1043 priv->wmm.
1044 ra_list_spinlock);
1045 LEAVE();
1046 return;
1047 }
1048 while (sta_ptr != (sta_node *)&priv->sta_list) {
1049 for (i = 0; i < MAX_NUM_TID; i++) {
1050 if (sta_ptr->is_11n_enabled)
1051 sta_ptr->ampdu_sta[i] =
1052 priv->aggr_prio_tbl[i].ampdu_user;
1053 }
1054 sta_ptr = sta_ptr->pnext;
1055 }
1056 pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
1057 priv->wmm.ra_list_spinlock);
1058 LEAVE();
1059 return;
1060 }
1061
1062 /**
1063 * @brief Set/get aggr_prio_tbl
1064 *
1065 * @param pmadapter A pointer to mlan_adapter structure
1066 * @param pioctl_req A pointer to ioctl request buffer
1067 *
1068 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
1069 */
1070 static mlan_status
wlan_11n_ioctl_aggr_prio_tbl(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)1071 wlan_11n_ioctl_aggr_prio_tbl(IN pmlan_adapter pmadapter,
1072 IN pmlan_ioctl_req pioctl_req)
1073 {
1074 int i = 0;
1075 mlan_status ret = MLAN_STATUS_SUCCESS;
1076 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
1077 mlan_ds_11n_cfg *cfg = MNULL;
1078
1079 ENTER();
1080
1081 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
1082
1083 if (pioctl_req->action == MLAN_ACT_GET) {
1084 for (i = 0; i < MAX_NUM_TID; i++) {
1085 cfg->param.aggr_prio_tbl.ampdu[i] =
1086 pmpriv->aggr_prio_tbl[i].ampdu_user;
1087 cfg->param.aggr_prio_tbl.amsdu[i] =
1088 pmpriv->aggr_prio_tbl[i].amsdu;
1089 }
1090 } else {
1091 for (i = 0; i < MAX_NUM_TID; i++) {
1092 /* For AMPDU */
1093 if ((cfg->param.aggr_prio_tbl.ampdu[i] >
1094 HIGH_PRIO_TID)&&(cfg->param.aggr_prio_tbl.
1095 ampdu[i] !=
1096 BA_STREAM_NOT_ALLOWED)) {
1097 pioctl_req->status_code =
1098 MLAN_ERROR_INVALID_PARAMETER;
1099 ret = MLAN_STATUS_FAILURE;
1100 break;
1101 }
1102
1103 pmpriv->aggr_prio_tbl[i].ampdu_ap =
1104 pmpriv->aggr_prio_tbl[i].ampdu_user =
1105 cfg->param.aggr_prio_tbl.ampdu[i];
1106
1107 /* For AMSDU */
1108 if ((cfg->param.aggr_prio_tbl.amsdu[i] > HIGH_PRIO_TID
1109 && cfg->param.aggr_prio_tbl.amsdu[i] !=
1110 BA_STREAM_NOT_ALLOWED)) {
1111 pioctl_req->status_code =
1112 MLAN_ERROR_INVALID_PARAMETER;
1113 ret = MLAN_STATUS_FAILURE;
1114 break;
1115 } else {
1116 pmpriv->aggr_prio_tbl[i].amsdu =
1117 cfg->param.aggr_prio_tbl.amsdu[i];
1118 }
1119 }
1120 if (pmpriv->media_connected == MTRUE) {
1121 for (i = 0; i < MAX_NUM_TID; i++) {
1122 if (cfg->param.aggr_prio_tbl.ampdu[i] ==
1123 BA_STREAM_NOT_ALLOWED) {
1124 PRINTM(MIOCTL,
1125 "Receive aggrpriotbl: BA not allowed tid=%d\n",
1126 i);
1127 wlan_send_delba_txbastream_tbl(pmpriv,
1128 i);
1129 }
1130 }
1131 wlan_update_all_stations_ampdu(pmpriv);
1132 wlan_recv_event(pmpriv,
1133 MLAN_EVENT_ID_DRV_DEFER_HANDLING,
1134 MNULL);
1135 }
1136 }
1137
1138 LEAVE();
1139 return ret;
1140 }
1141
1142 /**
1143 * @brief This function update all the tx_win_size
1144 *
1145 * @param pmadapter A pointer to mlan_adapter
1146 *
1147 *
1148 * @return N/A
1149 */
1150 void
wlan_update_ampdu_txwinsize(pmlan_adapter pmadapter)1151 wlan_update_ampdu_txwinsize(pmlan_adapter pmadapter)
1152 {
1153 t_u8 i;
1154 t_u32 tx_win_size = 0;
1155 pmlan_private priv = MNULL;
1156
1157 ENTER();
1158
1159 for (i = 0; i < pmadapter->priv_num; i++) {
1160 if (pmadapter->priv[i]) {
1161 priv = pmadapter->priv[i];
1162 tx_win_size = priv->add_ba_param.tx_win_size;
1163 #ifdef STA_SUPPORT
1164 if (priv->bss_type == MLAN_BSS_TYPE_STA)
1165 priv->add_ba_param.tx_win_size =
1166 MLAN_STA_AMPDU_DEF_TXWINSIZE;
1167 #endif
1168 #ifdef WIFI_DIRECT_SUPPORT
1169 if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
1170 priv->add_ba_param.tx_win_size =
1171 MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
1172 #endif
1173 #ifdef UAP_SUPPORT
1174 if (priv->bss_type == MLAN_BSS_TYPE_UAP)
1175 priv->add_ba_param.tx_win_size =
1176 MLAN_UAP_AMPDU_DEF_TXWINSIZE;
1177 #endif
1178 if (pmadapter->coex_win_size &&
1179 pmadapter->coex_tx_win_size)
1180 priv->add_ba_param.tx_win_size =
1181 pmadapter->coex_tx_win_size;
1182
1183 if (tx_win_size != priv->add_ba_param.tx_win_size) {
1184 if (priv->media_connected == MTRUE) {
1185 for (i = 0; i < MAX_NUM_TID; i++)
1186 wlan_send_delba_txbastream_tbl
1187 (priv, i);
1188 wlan_recv_event(priv,
1189 MLAN_EVENT_ID_DRV_DEFER_HANDLING,
1190 MNULL);
1191 }
1192 }
1193 }
1194 }
1195 LEAVE();
1196 return;
1197 }
1198
1199 /**
1200 * @brief Get supported MCS set
1201 *
1202 * @param pmadapter A pointer to mlan_adapter structure
1203 * @param pioctl_req A pointer to ioctl request buffer
1204 *
1205 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
1206 */
1207 static mlan_status
wlan_11n_ioctl_supported_mcs_set(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)1208 wlan_11n_ioctl_supported_mcs_set(IN pmlan_adapter pmadapter,
1209 IN pmlan_ioctl_req pioctl_req)
1210 {
1211 mlan_ds_11n_cfg *cfg = MNULL;
1212 int rx_mcs_supp;
1213 t_u8 mcs_set[NUM_MCS_FIELD];
1214 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
1215
1216 ENTER();
1217
1218 if (pioctl_req->action == MLAN_ACT_SET) {
1219 PRINTM(MERROR, "Set operation is not supported\n");
1220 pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
1221 LEAVE();
1222 return MLAN_STATUS_FAILURE;
1223 }
1224 rx_mcs_supp = GET_RXMCSSUPP(pmpriv->usr_dev_mcs_support);
1225 /* Set MCS for 1x1/2x2 */
1226 memset(pmadapter, (t_u8 *)mcs_set, 0xff, rx_mcs_supp);
1227 /* Clear all the other values */
1228 memset(pmadapter, (t_u8 *)&mcs_set[rx_mcs_supp], 0,
1229 NUM_MCS_FIELD - rx_mcs_supp);
1230 /* Set MCS32 with 40MHz support */
1231 if ((ISSUPP_CHANWIDTH40(pmpriv->usr_dot_11n_dev_cap_bg)
1232 || ISSUPP_CHANWIDTH40(pmpriv->usr_dot_11n_dev_cap_a)
1233 ) && !(pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS
1234 && pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
1235 SETHT_MCS32(mcs_set);
1236
1237 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
1238 memcpy(pmadapter, cfg->param.supported_mcs_set, mcs_set, NUM_MCS_FIELD);
1239
1240 LEAVE();
1241 return MLAN_STATUS_SUCCESS;
1242 }
1243
1244 /**
1245 * @brief This function checks if the given pointer is valid entry of
1246 * Tx BA Stream table
1247 *
1248 * @param priv Pointer to mlan_private
1249 * @param ptxtblptr Pointer to tx ba stream entry
1250 *
1251 * @return MTRUE or MFALSE
1252 */
1253 static int
wlan_is_txbastreamptr_valid(mlan_private * priv,TxBAStreamTbl * ptxtblptr)1254 wlan_is_txbastreamptr_valid(mlan_private *priv, TxBAStreamTbl *ptxtblptr)
1255 {
1256 TxBAStreamTbl *ptx_tbl;
1257
1258 ENTER();
1259
1260 ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
1261 &priv->tx_ba_stream_tbl_ptr,
1262 MNULL, MNULL);
1263 if (!ptx_tbl) {
1264 LEAVE();
1265 return MFALSE;
1266 }
1267
1268 while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
1269 if (ptx_tbl == ptxtblptr) {
1270 LEAVE();
1271 return MTRUE;
1272 }
1273 ptx_tbl = ptx_tbl->pnext;
1274 }
1275 LEAVE();
1276 return MFALSE;
1277 }
1278
1279 /**
1280 * @brief This function will return the pointer to a entry in BA Stream
1281 * table which matches the ba_status requested
1282 *
1283 * @param priv A pointer to mlan_private
1284 * @param ba_status Current status of the BA stream
1285 *
1286 * @return A pointer to first entry matching status in BA stream
1287 * NULL if not found
1288 */
1289 static TxBAStreamTbl *
wlan_11n_get_txbastream_status(mlan_private * priv,baStatus_e ba_status)1290 wlan_11n_get_txbastream_status(mlan_private *priv, baStatus_e ba_status)
1291 {
1292 TxBAStreamTbl *ptx_tbl;
1293
1294 ENTER();
1295
1296 ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
1297 &priv->tx_ba_stream_tbl_ptr,
1298 MNULL, MNULL);
1299 if (!ptx_tbl) {
1300 LEAVE();
1301 return MNULL;
1302 }
1303
1304 while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
1305 if (ptx_tbl->ba_status == ba_status) {
1306 LEAVE();
1307 return ptx_tbl;
1308 }
1309 ptx_tbl = ptx_tbl->pnext;
1310 }
1311
1312 LEAVE();
1313 return MNULL;
1314 }
1315
1316 /********************************************************
1317 Global Functions
1318 ********************************************************/
1319
1320 #ifdef STA_SUPPORT
1321 /**
1322 * @brief This function fills the cap info
1323 *
1324 * @param priv A pointer to mlan_private structure
1325 * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
1326 * @param bands Band configuration
1327 *
1328 * @return N/A
1329 */
1330 static void
wlan_fill_cap_info(mlan_private * priv,HTCap_t * ht_cap,t_u8 bands)1331 wlan_fill_cap_info(mlan_private *priv, HTCap_t *ht_cap, t_u8 bands)
1332 {
1333 t_u32 usr_dot_11n_dev_cap;
1334
1335 ENTER();
1336
1337 if (bands & BAND_A)
1338 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
1339 else
1340 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
1341
1342 if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
1343 SETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
1344 else
1345 RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
1346
1347 if (ISSUPP_GREENFIELD(usr_dot_11n_dev_cap))
1348 SETHT_GREENFIELD(ht_cap->ht_cap_info);
1349 else
1350 RESETHT_GREENFIELD(ht_cap->ht_cap_info);
1351
1352 if (ISSUPP_SHORTGI20(usr_dot_11n_dev_cap))
1353 SETHT_SHORTGI20(ht_cap->ht_cap_info);
1354 else
1355 RESETHT_SHORTGI20(ht_cap->ht_cap_info);
1356
1357 if (ISSUPP_SHORTGI40(usr_dot_11n_dev_cap))
1358 SETHT_SHORTGI40(ht_cap->ht_cap_info);
1359 else
1360 RESETHT_SHORTGI40(ht_cap->ht_cap_info);
1361 if (ISSUPP_RXSTBC(usr_dot_11n_dev_cap))
1362 SETHT_RXSTBC(ht_cap->ht_cap_info, 1);
1363 else
1364 RESETHT_RXSTBC(ht_cap->ht_cap_info);
1365
1366 if (ISENABLED_40MHZ_INTOLARENT(usr_dot_11n_dev_cap))
1367 SETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
1368 else
1369 RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
1370
1371 /** if current channel only allow 20Mhz, we should cler 40Mhz support */
1372 if (priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
1373 priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS) {
1374 RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
1375 RESETHT_SHORTGI40(ht_cap->ht_cap_info);
1376 RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
1377 }
1378 /* No user config for LDPC coding capability yet */
1379 if (ISSUPP_RXLDPC(usr_dot_11n_dev_cap))
1380 SETHT_LDPCCODINGCAP(ht_cap->ht_cap_info);
1381 else
1382 RESETHT_LDPCCODINGCAP(ht_cap->ht_cap_info);
1383
1384 /* No user config for TX STBC yet */
1385 if (ISSUPP_TXSTBC(usr_dot_11n_dev_cap))
1386 SETHT_TXSTBC(ht_cap->ht_cap_info);
1387 else
1388 RESETHT_TXSTBC(ht_cap->ht_cap_info);
1389
1390 /* No user config for Delayed BACK yet */
1391 RESETHT_DELAYEDBACK(ht_cap->ht_cap_info);
1392
1393 /* Need change to support 8k AMSDU receive */
1394 RESETHT_MAXAMSDU(ht_cap->ht_cap_info);
1395 /* SM power save */
1396 if (ISSUPP_MIMOPS(priv->adapter->hw_dot_11n_dev_cap))
1397 RESETHT_SM_POWERSAVE(ht_cap->ht_cap_info); /* Enable HT SMPS */
1398 else
1399 SETHT_STATIC_SMPS(ht_cap->ht_cap_info); /* Disable HT SMPS */
1400
1401 LEAVE();
1402 }
1403
1404 /**
1405 * @brief This function clear the bit in cap info which we don't support
1406 *
1407 * @param priv A pointer to mlan_private structure
1408 * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
1409 * @param bands Band configuration
1410 *
1411 * @return N/A
1412 */
1413 static void
wlan_reset_cap_info(mlan_private * priv,HTCap_t * ht_cap,t_u8 bands)1414 wlan_reset_cap_info(mlan_private *priv, HTCap_t *ht_cap, t_u8 bands)
1415 {
1416 t_u32 usr_dot_11n_dev_cap;
1417
1418 ENTER();
1419
1420 if (bands & BAND_A)
1421 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
1422 else
1423 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
1424
1425 if (!ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
1426 RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
1427
1428 if (!ISSUPP_GREENFIELD(usr_dot_11n_dev_cap))
1429 RESETHT_GREENFIELD(ht_cap->ht_cap_info);
1430
1431 if (!ISSUPP_SHORTGI20(usr_dot_11n_dev_cap))
1432 RESETHT_SHORTGI20(ht_cap->ht_cap_info);
1433
1434 if (!ISSUPP_SHORTGI40(usr_dot_11n_dev_cap))
1435 RESETHT_SHORTGI40(ht_cap->ht_cap_info);
1436 if (!ISSUPP_RXSTBC(usr_dot_11n_dev_cap))
1437 RESETHT_RXSTBC(ht_cap->ht_cap_info);
1438
1439 if (!ISENABLED_40MHZ_INTOLARENT(usr_dot_11n_dev_cap))
1440 RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
1441
1442 /** if current channel only allow 20Mhz, we should cler 40Mhz support */
1443 if (priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
1444 priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS) {
1445 RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
1446 RESETHT_SHORTGI40(ht_cap->ht_cap_info);
1447 RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
1448 }
1449 /* No user config for LDPC coding capability yet */
1450 if (!ISSUPP_RXLDPC(usr_dot_11n_dev_cap))
1451 RESETHT_LDPCCODINGCAP(ht_cap->ht_cap_info);
1452
1453 /* No user config for TX STBC yet */
1454 if (!ISSUPP_TXSTBC(usr_dot_11n_dev_cap))
1455 RESETHT_TXSTBC(ht_cap->ht_cap_info);
1456
1457 /* No user config for Delayed BACK yet */
1458 RESETHT_DELAYEDBACK(ht_cap->ht_cap_info);
1459
1460 /* Need change to support 8k AMSDU receive */
1461 RESETHT_MAXAMSDU(ht_cap->ht_cap_info);
1462 /* SM power save */
1463 if (!ISSUPP_MIMOPS(priv->adapter->hw_dot_11n_dev_cap))
1464 SETHT_STATIC_SMPS(ht_cap->ht_cap_info); /* Disable HT SMPS */
1465
1466 LEAVE();
1467 }
1468
1469 /**
1470 * @brief This function fills the HT cap tlv
1471 *
1472 * @param priv A pointer to mlan_private structure
1473 * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
1474 * @param bands Band configuration
1475 * @param fill A flag for fill the htcap info
1476 *
1477 * @return N/A
1478 */
1479 void
wlan_fill_ht_cap_tlv(mlan_private * priv,MrvlIETypes_HTCap_t * pht_cap,t_u8 bands,t_u8 fill)1480 wlan_fill_ht_cap_tlv(mlan_private *priv,
1481 MrvlIETypes_HTCap_t *pht_cap, t_u8 bands, t_u8 fill)
1482 {
1483 mlan_adapter *pmadapter = priv->adapter;
1484 int rx_mcs_supp;
1485 t_u32 usr_dot_11n_dev_cap;
1486
1487 ENTER();
1488
1489 if (bands & BAND_A)
1490 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
1491 else
1492 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
1493
1494 /* Fill HT cap info */
1495 if (fill)
1496 wlan_fill_cap_info(priv, &pht_cap->ht_cap, bands);
1497 else
1498 wlan_reset_cap_info(priv, &pht_cap->ht_cap, bands);
1499
1500 pht_cap->ht_cap.ht_cap_info =
1501 wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);
1502
1503 /* Set ampdu param */
1504 SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
1505 SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);
1506
1507 rx_mcs_supp = GET_RXMCSSUPP(priv->usr_dev_mcs_support);
1508 /* Clear all the other values to get the minimum mcs set btw STA and AP */
1509 memset(pmadapter,
1510 (t_u8 *)&pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp], 0,
1511 NUM_MCS_FIELD - rx_mcs_supp);
1512 /* Set MCS32 with 40MHz support */
1513 /* if current channel only support 20MHz, we should not set 40Mz supprot */
1514 if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
1515 !(priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS
1516 && priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
1517 SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
1518
1519 /* Clear RD responder bit */
1520 RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);
1521 pht_cap->ht_cap.ht_ext_cap =
1522 wlan_cpu_to_le16(pht_cap->ht_cap.ht_ext_cap);
1523
1524 /* Set Tx BF cap */
1525 pht_cap->ht_cap.tx_bf_cap = wlan_cpu_to_le32(priv->tx_bf_cap);
1526
1527 LEAVE();
1528 return;
1529 }
1530
1531 /**
1532 * @brief This function fills the HT cap ie
1533 *
1534 * @param priv A pointer to mlan_private structure
1535 * @param pht_cap A pointer to IEEEtypes_HTCap_t structure
1536 * @param bands Band configuration
1537 *
1538 * @return N/A
1539 */
1540 void
wlan_fill_ht_cap_ie(mlan_private * priv,IEEEtypes_HTCap_t * pht_cap,t_u8 bands)1541 wlan_fill_ht_cap_ie(mlan_private *priv, IEEEtypes_HTCap_t *pht_cap, t_u8 bands)
1542 {
1543 mlan_adapter *pmadapter = priv->adapter;
1544 int rx_mcs_supp;
1545 t_u32 usr_dot_11n_dev_cap;
1546
1547 ENTER();
1548
1549 pht_cap->ieee_hdr.element_id = HT_CAPABILITY;
1550 pht_cap->ieee_hdr.len = sizeof(HTCap_t);
1551 if (bands & BAND_A)
1552 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
1553 else
1554 usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
1555
1556 /* Fill HT cap info */
1557 wlan_fill_cap_info(priv, &pht_cap->ht_cap, bands);
1558
1559 /* Set ampdu param */
1560 SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
1561 SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);
1562
1563 rx_mcs_supp = GET_RXMCSSUPP(priv->usr_dev_mcs_support);
1564 memset(pmadapter, (t_u8 *)pht_cap->ht_cap.supported_mcs_set, 0xff,
1565 rx_mcs_supp);
1566 /* Clear all the other values to get the minimum mcs set btw STA and AP */
1567 memset(pmadapter,
1568 (t_u8 *)&pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp], 0,
1569 NUM_MCS_FIELD - rx_mcs_supp);
1570 /* Set MCS32 with 40MHz support */
1571 /* if current channel only support 20MHz, we should not set 40Mz supprot */
1572 if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
1573 !(priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS
1574 && priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
1575 SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
1576
1577 /* Clear RD responder bit */
1578 RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);
1579
1580 /* Set Tx BF cap */
1581 pht_cap->ht_cap.tx_bf_cap = priv->tx_bf_cap;
1582
1583 LEAVE();
1584 return;
1585 }
1586 #endif /* STA_SUPPORT */
1587
1588 /**
1589 * @brief This function prints the 802.11n device capability
1590 *
1591 * @param pmadapter A pointer to mlan_adapter structure
1592 * @param cap Capability value
1593 *
1594 * @return N/A
1595 */
1596 void
wlan_show_dot11ndevcap(pmlan_adapter pmadapter,t_u32 cap)1597 wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap)
1598 {
1599 ENTER();
1600
1601 PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = %s octets\n",
1602 (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
1603 PRINTM(MINFO, "GET_HW_SPEC: Beam forming %s\n",
1604 (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
1605 PRINTM(MINFO, "GET_HW_SPEC: Greenfield preamble %s\n",
1606 (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
1607 PRINTM(MINFO, "GET_HW_SPEC: AMPDU %s\n",
1608 (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
1609 PRINTM(MINFO, "GET_HW_SPEC: MIMO Power Save %s\n",
1610 (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
1611 PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
1612 (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
1613 PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
1614 (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
1615 PRINTM(MINFO, "GET_HW_SPEC: Short GI for 40 Mhz %s\n",
1616 (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
1617 PRINTM(MINFO, "GET_HW_SPEC: Short GI for 20 Mhz %s\n",
1618 (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
1619 PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n",
1620 (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
1621
1622 PRINTM(MINFO, "GET_HW_SPEC: Number of Tx BA streams supported = %d\n",
1623 ISSUPP_GETTXBASTREAM(cap));
1624 PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n",
1625 (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
1626 PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n",
1627 (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
1628 PRINTM(MINFO, "GET_HW_SPEC: 10 Mhz channel width %s\n",
1629 (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
1630
1631 if (ISSUPP_RXANTENNAA(cap))
1632 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna A\n");
1633 if (ISSUPP_RXANTENNAB(cap))
1634 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna B\n");
1635 if (ISSUPP_RXANTENNAC(cap))
1636 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna C\n");
1637 if (ISSUPP_RXANTENNAD(cap))
1638 PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna D\n");
1639 if (ISSUPP_TXANTENNAA(cap))
1640 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna A\n");
1641 if (ISSUPP_TXANTENNAB(cap))
1642 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna B\n");
1643 if (ISSUPP_TXANTENNAC(cap))
1644 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna C\n");
1645 if (ISSUPP_TXANTENNAD(cap))
1646 PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna D\n");
1647
1648 LEAVE();
1649 return;
1650 }
1651
1652 /**
1653 * @brief This function prints the 802.11n device MCS
1654 *
1655 * @param pmadapter A pointer to mlan_adapter structure
1656 * @param support Support value
1657 *
1658 * @return N/A
1659 */
1660 void
wlan_show_devmcssupport(pmlan_adapter pmadapter,t_u8 support)1661 wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support)
1662 {
1663 ENTER();
1664
1665 PRINTM(MINFO, "GET_HW_SPEC: MCSs for %dx%d MIMO\n",
1666 GET_RXMCSSUPP(support), GET_TXMCSSUPP(support));
1667
1668 LEAVE();
1669 return;
1670 }
1671
1672 /**
1673 * @brief This function handles the command response of
1674 * delete a block ack request
1675 *
1676 * @param priv A pointer to mlan_private structure
1677 * @param resp A pointer to HostCmd_DS_COMMAND
1678 *
1679 * @return MLAN_STATUS_SUCCESS
1680 */
1681 mlan_status
wlan_ret_11n_delba(mlan_private * priv,HostCmd_DS_COMMAND * resp)1682 wlan_ret_11n_delba(mlan_private *priv, HostCmd_DS_COMMAND *resp)
1683 {
1684 int tid;
1685 TxBAStreamTbl *ptx_ba_tbl;
1686 HostCmd_DS_11N_DELBA *pdel_ba =
1687 (HostCmd_DS_11N_DELBA *)&resp->params.del_ba;
1688
1689 ENTER();
1690
1691 pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
1692 pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
1693
1694 tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
1695 if (pdel_ba->del_result == BA_RESULT_SUCCESS) {
1696 mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
1697 TYPE_DELBA_SENT,
1698 INITIATOR_BIT(pdel_ba->
1699 del_ba_param_set),
1700 0);
1701 wlan_request_ralist_lock(priv);
1702 ptx_ba_tbl = wlan_11n_get_txbastream_status(priv,
1703 BA_STREAM_SETUP_INPROGRESS);
1704 wlan_release_ralist_lock(priv);
1705 if (ptx_ba_tbl)
1706 wlan_send_addba(priv, ptx_ba_tbl->tid, ptx_ba_tbl->ra);
1707 } else { /*
1708 * In case of failure, recreate
1709 * the deleted stream in case
1710 * we initiated the ADDBA
1711 */
1712 if (INITIATOR_BIT(pdel_ba->del_ba_param_set)) {
1713 wlan_request_ralist_lock(priv);
1714 if (!wlan_11n_get_txbastream_tbl
1715 (priv, tid, pdel_ba->peer_mac_addr, MFALSE))
1716 wlan_11n_create_txbastream_tbl(priv,
1717 pdel_ba->
1718 peer_mac_addr,
1719 tid,
1720 BA_STREAM_SETUP_INPROGRESS);
1721 ptx_ba_tbl =
1722 wlan_11n_get_txbastream_status(priv,
1723 BA_STREAM_SETUP_INPROGRESS);
1724 wlan_release_ralist_lock(priv);
1725 if (ptx_ba_tbl) {
1726 mlan_11n_delete_bastream_tbl(priv,
1727 ptx_ba_tbl->tid,
1728 ptx_ba_tbl->ra,
1729 TYPE_DELBA_SENT,
1730 MTRUE, 0);
1731 }
1732
1733 }
1734 }
1735
1736 LEAVE();
1737 return MLAN_STATUS_SUCCESS;
1738 }
1739
1740 /**
1741 * @brief This function handles the command response of
1742 * add a block ack request
1743 *
1744 * @param priv A pointer to mlan_private structure
1745 * @param resp A pointer to HostCmd_DS_COMMAND
1746 *
1747 * @return MLAN_STATUS_SUCCESS
1748 */
1749 mlan_status
wlan_ret_11n_addba_req(mlan_private * priv,HostCmd_DS_COMMAND * resp)1750 wlan_ret_11n_addba_req(mlan_private *priv, HostCmd_DS_COMMAND *resp)
1751 {
1752 t_u8 tid;
1753 HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
1754 (HostCmd_DS_11N_ADDBA_RSP *)&resp->params.add_ba_rsp;
1755 TxBAStreamTbl *ptx_ba_tbl;
1756 raListTbl *ra_list = MNULL;
1757 int tid_down;
1758
1759 ENTER();
1760
1761 padd_ba_rsp->block_ack_param_set =
1762 wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
1763 padd_ba_rsp->block_ack_tmo =
1764 wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
1765 padd_ba_rsp->ssn = (wlan_le16_to_cpu(padd_ba_rsp->ssn)) & SSN_MASK;
1766 padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
1767
1768 tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
1769 >> BLOCKACKPARAM_TID_POS;
1770 tid_down = wlan_get_wmm_tid_down(priv, tid);
1771 ra_list =
1772 wlan_wmm_get_ralist_node(priv, tid_down,
1773 padd_ba_rsp->peer_mac_addr);
1774 if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
1775 ptx_ba_tbl = wlan_11n_get_txbastream_tbl(priv, tid,
1776 padd_ba_rsp->
1777 peer_mac_addr, MTRUE);
1778 if (ptx_ba_tbl) {
1779 PRINTM(MCMND,
1780 "ADDBA REQ: " MACSTR
1781 " tid=%d ssn=%d win_size=%d,amsdu=%d\n",
1782 MAC2STR(padd_ba_rsp->peer_mac_addr), tid,
1783 padd_ba_rsp->ssn,
1784 ((padd_ba_rsp->
1785 block_ack_param_set &
1786 BLOCKACKPARAM_WINSIZE_MASK) >>
1787 BLOCKACKPARAM_WINSIZE_POS),
1788 padd_ba_rsp->
1789 block_ack_param_set &
1790 BLOCKACKPARAM_AMSDU_SUPP_MASK);
1791 ptx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
1792 if ((padd_ba_rsp->
1793 block_ack_param_set &
1794 BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
1795 priv->add_ba_param.tx_amsdu &&
1796 (priv->aggr_prio_tbl[tid].amsdu !=
1797 BA_STREAM_NOT_ALLOWED))
1798 ptx_ba_tbl->amsdu = MTRUE;
1799 else
1800 ptx_ba_tbl->amsdu = MFALSE;
1801 if (ra_list) {
1802 ra_list->amsdu_in_ampdu = ptx_ba_tbl->amsdu;
1803 ra_list->ba_status = BA_STREAM_SETUP_COMPLETE;
1804 }
1805 } else {
1806 PRINTM(MERROR, "BA stream not created\n");
1807 }
1808 } else {
1809 if (ra_list) {
1810 ra_list->amsdu_in_ampdu = MFALSE;
1811 ra_list->ba_status = BA_STREAM_NOT_SETUP;
1812
1813 }
1814 mlan_11n_delete_bastream_tbl(priv, tid,
1815 padd_ba_rsp->peer_mac_addr,
1816 TYPE_DELBA_SENT, MTRUE, 0);
1817 if (padd_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) {
1818 #ifdef UAP_SUPPORT
1819 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
1820 disable_station_ampdu(priv, tid,
1821 padd_ba_rsp->
1822 peer_mac_addr);
1823 #endif /* UAP_SUPPORT */
1824 if (priv->bss_mode == MLAN_BSS_MODE_IBSS)
1825 disable_station_ampdu(priv, tid,
1826 padd_ba_rsp->
1827 peer_mac_addr);
1828 if (ra_list && ra_list->is_tdls_link)
1829 disable_station_ampdu(priv, tid,
1830 padd_ba_rsp->
1831 peer_mac_addr);
1832 priv->aggr_prio_tbl[tid].ampdu_ap =
1833 BA_STREAM_NOT_ALLOWED;
1834
1835 } else {
1836
1837 if (ra_list) {
1838 ra_list->packet_count = 0;
1839 ra_list->ba_packet_threshold =
1840 wlan_get_random_ba_threshold(priv->
1841 adapter);
1842 }
1843 }
1844 }
1845
1846 LEAVE();
1847 return MLAN_STATUS_SUCCESS;
1848 }
1849
1850 /**
1851 * @brief This function restore tx_pause flag
1852 *
1853 * @param priv A pointer to mlan_private structure
1854 * @param flag MTRUE/MFALSE;
1855 *
1856 * @return N/A
1857 */
1858 void
wlan_set_tx_pause_flag(mlan_private * priv,t_u8 flag)1859 wlan_set_tx_pause_flag(mlan_private *priv, t_u8 flag)
1860 {
1861 mlan_private *pmpriv = MNULL;
1862 t_u8 i;
1863 for (i = 0; i < priv->adapter->priv_num; i++) {
1864 pmpriv = priv->adapter->priv[i];
1865 if (pmpriv)
1866 pmpriv->tx_pause = flag;
1867 }
1868 }
1869
1870 /**
1871 * @brief This function prepares command of reconfigure tx buf
1872 *
1873 * @param priv A pointer to mlan_private structure
1874 * @param cmd A pointer to HostCmd_DS_COMMAND structure
1875 * @param cmd_action The action: GET or SET
1876 * @param pdata_buf A pointer to data buffer
1877 *
1878 * @return MLAN_STATUS_SUCCESS
1879 */
1880 mlan_status
wlan_cmd_recfg_tx_buf(mlan_private * priv,HostCmd_DS_COMMAND * cmd,int cmd_action,void * pdata_buf)1881 wlan_cmd_recfg_tx_buf(mlan_private *priv,
1882 HostCmd_DS_COMMAND *cmd, int cmd_action, void *pdata_buf)
1883 {
1884 HostCmd_DS_TXBUF_CFG *ptx_buf = &cmd->params.tx_buf;
1885 t_u16 action = (t_u16)cmd_action;
1886 t_u16 buf_size = *((t_u16 *)pdata_buf);
1887
1888 ENTER();
1889 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
1890 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TXBUF_CFG)
1891 + S_DS_GEN);
1892 ptx_buf->action = wlan_cpu_to_le16(action);
1893 switch (action) {
1894 case HostCmd_ACT_GEN_SET:
1895 PRINTM(MCMND, "set tx_buf = %d\n", buf_size);
1896 ptx_buf->buff_size = wlan_cpu_to_le16(buf_size);
1897 /** stop tx traffic */
1898 wlan_set_tx_pause_flag(priv, MTRUE);
1899 break;
1900 case HostCmd_ACT_GEN_GET:
1901 default:
1902 ptx_buf->buff_size = 0;
1903 break;
1904 }
1905 LEAVE();
1906 return MLAN_STATUS_SUCCESS;
1907 }
1908
1909 /**
1910 * @brief This function prepares command of amsdu aggr control
1911 *
1912 * @param priv A pointer to mlan_private structure
1913 * @param cmd A pointer to HostCmd_DS_COMMAND structure
1914 * @param cmd_action The action: GET or SET
1915 * @param pdata_buf A pointer to data buffer
1916 *
1917 * @return MLAN_STATUS_SUCCESS
1918 */
1919 mlan_status
wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,HostCmd_DS_COMMAND * cmd,int cmd_action,void * pdata_buf)1920 wlan_cmd_amsdu_aggr_ctrl(mlan_private *priv,
1921 HostCmd_DS_COMMAND *cmd,
1922 int cmd_action, void *pdata_buf)
1923 {
1924 HostCmd_DS_AMSDU_AGGR_CTRL *pamsdu_ctrl = &cmd->params.amsdu_aggr_ctrl;
1925 t_u16 action = (t_u16)cmd_action;
1926 mlan_ds_11n_amsdu_aggr_ctrl *aa_ctrl = (mlan_ds_11n_amsdu_aggr_ctrl *)
1927 pdata_buf;
1928
1929 ENTER();
1930
1931 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
1932 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_AMSDU_AGGR_CTRL)
1933 + S_DS_GEN);
1934 pamsdu_ctrl->action = wlan_cpu_to_le16(action);
1935 switch (action) {
1936 case HostCmd_ACT_GEN_SET:
1937 pamsdu_ctrl->enable = wlan_cpu_to_le16(aa_ctrl->enable);
1938 pamsdu_ctrl->curr_buf_size = 0;
1939 break;
1940 case HostCmd_ACT_GEN_GET:
1941 default:
1942 pamsdu_ctrl->curr_buf_size = 0;
1943 break;
1944 }
1945 LEAVE();
1946 return MLAN_STATUS_SUCCESS;
1947 }
1948
1949 /**
1950 * @brief This function handles the command response of amsdu aggr ctrl
1951 *
1952 * @param pmpriv A pointer to mlan_private structure
1953 * @param resp A pointer to HostCmd_DS_COMMAND
1954 * @param pioctl_buf A pointer to mlan_ioctl_req structure
1955 *
1956 * @return MLAN_STATUS_SUCCESS
1957 */
1958 mlan_status
wlan_ret_amsdu_aggr_ctrl(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)1959 wlan_ret_amsdu_aggr_ctrl(IN pmlan_private pmpriv,
1960 IN HostCmd_DS_COMMAND *resp,
1961 IN mlan_ioctl_req *pioctl_buf)
1962 {
1963 mlan_ds_11n_cfg *cfg = MNULL;
1964 HostCmd_DS_AMSDU_AGGR_CTRL *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl;
1965
1966 ENTER();
1967
1968 if (pioctl_buf) {
1969 cfg = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
1970 cfg->param.amsdu_aggr_ctrl.enable =
1971 wlan_le16_to_cpu(amsdu_ctrl->enable);
1972 cfg->param.amsdu_aggr_ctrl.curr_buf_size =
1973 wlan_le16_to_cpu(amsdu_ctrl->curr_buf_size);
1974 }
1975 LEAVE();
1976 return MLAN_STATUS_SUCCESS;
1977 }
1978
1979 /**
1980 * @brief This function prepares 11n cfg command
1981 *
1982 * @param pmpriv A pointer to mlan_private structure
1983 * @param cmd A pointer to HostCmd_DS_COMMAND structure
1984 * @param cmd_action the action: GET or SET
1985 * @param pdata_buf A pointer to data buffer
1986 * @return MLAN_STATUS_SUCCESS
1987 */
1988 mlan_status
wlan_cmd_11n_cfg(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * cmd,IN t_u16 cmd_action,IN t_void * pdata_buf)1989 wlan_cmd_11n_cfg(IN pmlan_private pmpriv,
1990 IN HostCmd_DS_COMMAND *cmd,
1991 IN t_u16 cmd_action, IN t_void *pdata_buf)
1992 {
1993 HostCmd_DS_11N_CFG *htcfg = &cmd->params.htcfg;
1994 mlan_ds_11n_tx_cfg *txcfg = (mlan_ds_11n_tx_cfg *)pdata_buf;
1995
1996 ENTER();
1997 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_CFG);
1998 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_CFG) + S_DS_GEN);
1999 htcfg->action = wlan_cpu_to_le16(cmd_action);
2000 htcfg->ht_tx_cap = wlan_cpu_to_le16(txcfg->httxcap);
2001 htcfg->ht_tx_info = wlan_cpu_to_le16(txcfg->httxinfo);
2002 htcfg->misc_config = wlan_cpu_to_le16(txcfg->misc_cfg);
2003 LEAVE();
2004 return MLAN_STATUS_SUCCESS;
2005 }
2006
2007 /**
2008 * @brief This function handles the command response of 11ncfg
2009 *
2010 * @param pmpriv A pointer to mlan_private structure
2011 * @param resp A pointer to HostCmd_DS_COMMAND
2012 * @param pioctl_buf A pointer to mlan_ioctl_req structure
2013 *
2014 * @return MLAN_STATUS_SUCCESS
2015 */
2016 mlan_status
wlan_ret_11n_cfg(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)2017 wlan_ret_11n_cfg(IN pmlan_private pmpriv,
2018 IN HostCmd_DS_COMMAND *resp, IN mlan_ioctl_req *pioctl_buf)
2019 {
2020 mlan_ds_11n_cfg *cfg = MNULL;
2021 HostCmd_DS_11N_CFG *htcfg = &resp->params.htcfg;
2022
2023 ENTER();
2024 if (pioctl_buf &&
2025 (wlan_le16_to_cpu(htcfg->action) == HostCmd_ACT_GEN_GET)) {
2026 cfg = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
2027 cfg->param.tx_cfg.httxcap = wlan_le16_to_cpu(htcfg->ht_tx_cap);
2028 cfg->param.tx_cfg.httxinfo =
2029 wlan_le16_to_cpu(htcfg->ht_tx_info);
2030 cfg->param.tx_cfg.misc_cfg =
2031 wlan_le16_to_cpu(htcfg->misc_config);
2032 }
2033 LEAVE();
2034 return MLAN_STATUS_SUCCESS;
2035 }
2036
2037 /**
2038 * @brief This function prepares reject addba req command
2039 *
2040 * @param pmpriv A pointer to mlan_private structure
2041 * @param cmd A pointer to HostCmd_DS_COMMAND structure
2042 * @param cmd_action the action: GET or SET
2043 * @param pdata_buf A pointer to data buffer
2044 * @return MLAN_STATUS_SUCCESS
2045 */
2046 mlan_status
wlan_cmd_reject_addba_req(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * cmd,IN t_u16 cmd_action,IN t_void * pdata_buf)2047 wlan_cmd_reject_addba_req(IN pmlan_private pmpriv,
2048 IN HostCmd_DS_COMMAND *cmd,
2049 IN t_u16 cmd_action, IN t_void *pdata_buf)
2050 {
2051 HostCmd_DS_REJECT_ADDBA_REQ *preject_addba_req =
2052 &cmd->params.rejectaddbareq;
2053 mlan_ds_reject_addba_req *prejaddbareq =
2054 (mlan_ds_reject_addba_req *)pdata_buf;
2055
2056 ENTER();
2057 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_REJECT_ADDBA_REQ);
2058 cmd->size =
2059 wlan_cpu_to_le16(sizeof(HostCmd_DS_REJECT_ADDBA_REQ) +
2060 S_DS_GEN);
2061 preject_addba_req->action = wlan_cpu_to_le16(cmd_action);
2062 preject_addba_req->conditions =
2063 wlan_cpu_to_le32(prejaddbareq->conditions);
2064 LEAVE();
2065 return MLAN_STATUS_SUCCESS;
2066 }
2067
2068 /**
2069 * @brief This function handles the command response of reject addba req
2070 *
2071 * @param pmpriv A pointer to mlan_private structure
2072 * @param resp A pointer to HostCmd_DS_COMMAND
2073 * @param pioctl_buf A pointer to mlan_ioctl_req structure
2074 *
2075 * @return MLAN_STATUS_SUCCESS
2076 */
2077 mlan_status
wlan_ret_reject_addba_req(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)2078 wlan_ret_reject_addba_req(IN pmlan_private pmpriv,
2079 IN HostCmd_DS_COMMAND *resp,
2080 IN mlan_ioctl_req *pioctl_buf)
2081 {
2082 mlan_ds_11n_cfg *cfg = MNULL;
2083 HostCmd_DS_REJECT_ADDBA_REQ *preject_addba_req =
2084 &resp->params.rejectaddbareq;
2085
2086 ENTER();
2087 if (pioctl_buf &&
2088 (wlan_le16_to_cpu(preject_addba_req->action) ==
2089 HostCmd_ACT_GEN_GET)) {
2090 cfg = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
2091 cfg->param.reject_addba_req.conditions =
2092 wlan_le32_to_cpu(preject_addba_req->conditions);
2093 }
2094 LEAVE();
2095 return MLAN_STATUS_SUCCESS;
2096 }
2097
2098 /**
2099 * @brief This function prepares TX BF configuration command
2100 *
2101 * @param pmpriv A pointer to mlan_private structure
2102 * @param cmd A pointer to HostCmd_DS_COMMAND structure
2103 * @param cmd_action The action: GET or SET
2104 * @param pdata_buf A pointer to data buffer
2105 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2106 */
2107 mlan_status
wlan_cmd_tx_bf_cfg(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * cmd,IN t_u16 cmd_action,IN t_void * pdata_buf)2108 wlan_cmd_tx_bf_cfg(IN pmlan_private pmpriv,
2109 IN HostCmd_DS_COMMAND *cmd,
2110 IN t_u16 cmd_action, IN t_void *pdata_buf)
2111 {
2112 pmlan_adapter pmadapter = pmpriv->adapter;
2113 HostCmd_DS_TX_BF_CFG *txbfcfg = &cmd->params.tx_bf_cfg;
2114 mlan_ds_11n_tx_bf_cfg *txbf = (mlan_ds_11n_tx_bf_cfg *)pdata_buf;
2115
2116 ENTER();
2117
2118 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_BF_CFG);
2119 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TX_BF_CFG) + S_DS_GEN);
2120
2121 if (txbf->bf_action == SET_GET_BF_PERIODICITY) {
2122 memcpy(pmadapter, txbfcfg->body.bf_periodicity.peer_mac,
2123 txbf->body.bf_periodicity[0].peer_mac,
2124 MLAN_MAC_ADDR_LENGTH);
2125 }
2126 txbfcfg->action = wlan_cpu_to_le16(txbf->action);
2127 txbfcfg->bf_action = wlan_cpu_to_le16(txbf->bf_action);
2128 if (cmd_action == HostCmd_ACT_GEN_SET) {
2129 switch (txbf->bf_action) {
2130 case BF_GLOBAL_CONFIGURATION:
2131 txbfcfg->body.bf_global_cfg.bf_enbl =
2132 txbf->body.bf_global_cfg.bf_enbl;
2133 txbfcfg->body.bf_global_cfg.sounding_enbl =
2134 txbf->body.bf_global_cfg.sounding_enbl;
2135 txbfcfg->body.bf_global_cfg.fb_type =
2136 txbf->body.bf_global_cfg.fb_type;
2137 txbfcfg->body.bf_global_cfg.snr_threshold =
2138 txbf->body.bf_global_cfg.snr_threshold;
2139 txbfcfg->body.bf_global_cfg.sounding_interval =
2140 wlan_cpu_to_le16(txbf->body.bf_global_cfg.
2141 sounding_interval);
2142 txbfcfg->body.bf_global_cfg.bf_mode =
2143 txbf->body.bf_global_cfg.bf_mode;
2144 break;
2145 case TRIGGER_SOUNDING_FOR_PEER:
2146 memcpy(pmadapter, txbfcfg->body.bf_sound_args.peer_mac,
2147 txbf->body.bf_sound[0].peer_mac,
2148 MLAN_MAC_ADDR_LENGTH);
2149 break;
2150 case SET_GET_BF_PERIODICITY:
2151 txbfcfg->body.bf_periodicity.interval =
2152 wlan_cpu_to_le16(txbf->body.bf_periodicity->
2153 interval);
2154 break;
2155 case TX_BF_FOR_PEER_ENBL:
2156 memcpy(pmadapter, txbfcfg->body.tx_bf_peer.peer_mac,
2157 txbf->body.tx_bf_peer[0].peer_mac,
2158 MLAN_MAC_ADDR_LENGTH);
2159 txbfcfg->body.tx_bf_peer.bf_enbl =
2160 txbf->body.tx_bf_peer[0].bf_enbl;
2161 txbfcfg->body.tx_bf_peer.sounding_enbl =
2162 txbf->body.tx_bf_peer[0].sounding_enbl;
2163 txbfcfg->body.tx_bf_peer.fb_type =
2164 txbf->body.tx_bf_peer[0].fb_type;
2165 break;
2166 case SET_SNR_THR_PEER:
2167 memcpy(pmadapter, txbfcfg->body.bf_snr.peer_mac,
2168 txbf->body.bf_snr[0].peer_mac,
2169 MLAN_MAC_ADDR_LENGTH);
2170 txbfcfg->body.bf_snr.snr = txbf->body.bf_snr[0].snr;
2171 break;
2172 default:
2173 LEAVE();
2174 return MLAN_STATUS_FAILURE;
2175 }
2176 }
2177
2178 LEAVE();
2179 return MLAN_STATUS_SUCCESS;
2180 }
2181
2182 /**
2183 * @brief This function handles the command response
2184 * of TX BF configuration
2185 *
2186 * @param pmpriv A pointer to mlan_private structure
2187 * @param resp A pointer to HostCmd_DS_COMMAND
2188 * @param pioctl_buf A pointer to mlan_ioctl_req structure
2189 *
2190 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2191 */
2192 mlan_status
wlan_ret_tx_bf_cfg(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)2193 wlan_ret_tx_bf_cfg(IN pmlan_private pmpriv,
2194 IN HostCmd_DS_COMMAND *resp, IN mlan_ioctl_req *pioctl_buf)
2195 {
2196 pmlan_adapter pmadapter = pmpriv->adapter;
2197 HostCmd_DS_TX_BF_CFG *txbfcfg = &resp->params.tx_bf_cfg;
2198 mlan_ds_11n_cfg *cfg_11n = MNULL;
2199 mlan_ds_11n_tx_bf_cfg *txbf = MNULL;
2200 bf_peer_args *tx_bf_peer;
2201 bf_snr_thr_t *bf_snr;
2202 int i;
2203
2204 ENTER();
2205
2206 if (pioctl_buf) {
2207 cfg_11n = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
2208 txbf = (mlan_ds_11n_tx_bf_cfg *)&cfg_11n->param.tx_bf;
2209 txbf->bf_action = wlan_le16_to_cpu(txbfcfg->bf_action);
2210 switch (txbf->bf_action) {
2211 case BF_GLOBAL_CONFIGURATION:
2212 txbf->body.bf_global_cfg.bf_enbl =
2213 txbfcfg->body.bf_global_cfg.bf_enbl;
2214 txbf->body.bf_global_cfg.sounding_enbl =
2215 txbfcfg->body.bf_global_cfg.sounding_enbl;
2216 txbf->body.bf_global_cfg.fb_type =
2217 txbfcfg->body.bf_global_cfg.fb_type;
2218 txbf->body.bf_global_cfg.snr_threshold =
2219 txbfcfg->body.bf_global_cfg.snr_threshold;
2220 txbf->body.bf_global_cfg.sounding_interval =
2221 wlan_le16_to_cpu(txbfcfg->body.bf_global_cfg.
2222 sounding_interval);
2223 txbf->body.bf_global_cfg.bf_mode =
2224 txbfcfg->body.bf_global_cfg.bf_mode;
2225 break;
2226 case TRIGGER_SOUNDING_FOR_PEER:
2227 memcpy(pmadapter, txbf->body.bf_sound[0].peer_mac,
2228 txbfcfg->body.bf_sound_args.peer_mac,
2229 MLAN_MAC_ADDR_LENGTH);
2230 txbf->body.bf_sound[0].status =
2231 txbfcfg->body.bf_sound_args.status;
2232 break;
2233 case SET_GET_BF_PERIODICITY:
2234 memcpy(pmadapter, txbf->body.bf_periodicity->peer_mac,
2235 txbfcfg->body.bf_periodicity.peer_mac,
2236 MLAN_MAC_ADDR_LENGTH);
2237 txbf->body.bf_periodicity->interval =
2238 wlan_le16_to_cpu(txbfcfg->body.bf_periodicity.
2239 interval);
2240 break;
2241 case TX_BF_FOR_PEER_ENBL:
2242 txbf->no_of_peers = *(t_u8 *)&txbfcfg->body;
2243 tx_bf_peer =
2244 (bf_peer_args *)((t_u8 *)&txbfcfg->body +
2245 sizeof(t_u8));
2246 for (i = 0; i < txbf->no_of_peers; i++) {
2247 memcpy(pmadapter,
2248 txbf->body.tx_bf_peer[i].peer_mac,
2249 (t_u8 *)tx_bf_peer->peer_mac,
2250 MLAN_MAC_ADDR_LENGTH);
2251 txbf->body.tx_bf_peer[i].bf_enbl =
2252 tx_bf_peer->bf_enbl;
2253 txbf->body.tx_bf_peer[i].sounding_enbl =
2254 tx_bf_peer->sounding_enbl;
2255 txbf->body.tx_bf_peer[i].fb_type =
2256 tx_bf_peer->fb_type;
2257 tx_bf_peer++;
2258 }
2259 break;
2260 case SET_SNR_THR_PEER:
2261 txbf->no_of_peers = *(t_u8 *)&txbfcfg->body;
2262 bf_snr = (bf_snr_thr_t *)((t_u8 *)&txbfcfg->body +
2263 sizeof(t_u8));
2264 for (i = 0; i < txbf->no_of_peers; i++) {
2265 memcpy(pmadapter, txbf->body.bf_snr[i].peer_mac,
2266 (t_u8 *)bf_snr->peer_mac,
2267 MLAN_MAC_ADDR_LENGTH);
2268 txbf->body.bf_snr[i].snr = bf_snr->snr;
2269 bf_snr++;
2270 }
2271 break;
2272 default:
2273 LEAVE();
2274 return MLAN_STATUS_FAILURE;
2275 }
2276 }
2277
2278 LEAVE();
2279 return MLAN_STATUS_SUCCESS;
2280 }
2281
2282 /**
2283 * @brief Get second channel offset
2284 *
2285 * @param chan channel num
2286 * @return second channel offset
2287 */
2288 t_u8
wlan_get_second_channel_offset(int chan)2289 wlan_get_second_channel_offset(int chan)
2290 {
2291 t_u8 chan2Offset = SEC_CHAN_NONE;
2292
2293 switch (chan) {
2294 case 36:
2295 case 44:
2296 case 52:
2297 case 60:
2298 case 100:
2299 case 108:
2300 case 116:
2301 case 124:
2302 case 132:
2303 case 149:
2304 case 157:
2305 chan2Offset = SEC_CHAN_ABOVE;
2306 break;
2307 case 40:
2308 case 48:
2309 case 56:
2310 case 64:
2311 case 104:
2312 case 112:
2313 case 120:
2314 case 128:
2315 case 136:
2316 case 153:
2317 case 161:
2318 chan2Offset = SEC_CHAN_BELOW;
2319 break;
2320 case 165:
2321 /* Special Case: 20Mhz-only Channel */
2322 chan2Offset = SEC_CHAN_NONE;
2323 break;
2324 }
2325 return chan2Offset;
2326 }
2327
2328 #ifdef STA_SUPPORT
2329 /**
2330 * @brief validate the channel offset for Infra/Ad-hoc band configuration
2331 *
2332 * @param pmpriv A pointer to mlan_private structure
2333 * @param band band
2334 * @param chan primary channel
2335 * @param chan_bw channel bandwidth
2336 *
2337 * @return channel offset (NO_SEC_CHANNEL, SEC_CHANNEL_ABOVE,
2338 * SEC_CHANNEL_BELOW)
2339 */
2340 t_u8
wlan_validate_chan_offset(IN mlan_private * pmpriv,IN t_u8 band,IN t_u32 chan,IN t_u8 chan_bw)2341 wlan_validate_chan_offset(IN mlan_private *pmpriv,
2342 IN t_u8 band, IN t_u32 chan, IN t_u8 chan_bw)
2343 {
2344 t_u8 chan_offset;
2345 pmlan_adapter pmadapter = pmpriv->adapter;
2346
2347 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE)
2348 chan_offset = SEC_CHAN_ABOVE;
2349 else if (chan_bw == CHANNEL_BW_40MHZ_BELOW)
2350 chan_offset = SEC_CHAN_BELOW;
2351 else
2352 chan_offset = SEC_CHAN_NONE;
2353
2354 /* validation */
2355 if (chan_offset != SEC_CHAN_NONE) {
2356 if (band & BAND_GN) {
2357 if ((chan == 1) || (chan == 2) || (chan == 3) ||
2358 (chan == 4))
2359 chan_offset = SEC_CHAN_ABOVE;
2360 else if ((chan == 10) || (chan == 11) ||
2361 (chan == 12) || (chan == 13))
2362 chan_offset = SEC_CHAN_BELOW;
2363
2364 /* check if channel 12 is supported in the region */
2365 if (!wlan_find_cfp_by_band_and_channel
2366 (pmadapter, band, 12))
2367 if ((chan == 8) || (chan == 9))
2368 chan_offset = SEC_CHAN_BELOW;
2369 } else if (band & BAND_AN)
2370 chan_offset = wlan_get_second_channel_offset(chan);
2371 }
2372 return chan_offset;
2373 }
2374
2375 /**
2376 * @brief This function check if ht40 is allowed in current region
2377 *
2378 * @param pmpriv A pointer to mlan_private structure
2379 * @param pbss_desc A pointer to BSSDescriptor_t structure
2380 *
2381 * @return MTRUE/MFALSE
2382 */
2383 static int
wlan_check_chan_width_ht40_by_region(IN mlan_private * pmpriv,IN BSSDescriptor_t * pbss_desc)2384 wlan_check_chan_width_ht40_by_region(IN mlan_private *pmpriv,
2385 IN BSSDescriptor_t *pbss_desc)
2386 {
2387 pmlan_adapter pmadapter = pmpriv->adapter;
2388 int i = 0;
2389 int cover_pri_chan = MFALSE;
2390 t_u8 pri_chan;
2391 t_u8 chan_offset;
2392 t_u8 num_cfp;
2393
2394 ENTER();
2395
2396 if (pbss_desc->pht_info == MNULL) {
2397 PRINTM(MERROR, "ht_info pointer NULL, force use HT20\n");
2398 LEAVE();
2399 return MFALSE;
2400 }
2401 if (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
2402 pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS) {
2403 LEAVE();
2404 return MFALSE;
2405 }
2406
2407 pri_chan = pbss_desc->pht_info->ht_info.pri_chan;
2408 chan_offset = GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.field2);
2409 if ((chan_offset == SEC_CHAN_ABOVE) &&
2410 (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS))
2411 return MFALSE;
2412 if ((chan_offset == SEC_CHAN_BELOW) &&
2413 (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
2414 return MFALSE;
2415
2416 num_cfp = pmadapter->region_channel[0].num_cfp;
2417
2418 if ((pbss_desc->bss_band & (BAND_B | BAND_G)) &&
2419 pmadapter->region_channel && pmadapter->region_channel[0].valid) {
2420 for (i = 0; i < num_cfp; i++) {
2421 if (pri_chan ==
2422 pmadapter->region_channel[0].pcfp[i].channel) {
2423 cover_pri_chan = MTRUE;
2424 break;
2425 }
2426 }
2427 if (!cover_pri_chan) {
2428 PRINTM(MERROR, "Invalid channel, force use HT20\n");
2429 LEAVE();
2430 return MFALSE;
2431 }
2432
2433 if (chan_offset == SEC_CHAN_ABOVE) {
2434 if (pri_chan > num_cfp - 4) {
2435 PRINTM(MERROR,
2436 "Invalid second channel offset, force use HT20\n");
2437 LEAVE();
2438 return MFALSE;
2439 }
2440 }
2441 }
2442 LEAVE();
2443 return MTRUE;
2444 }
2445
2446 /**
2447 * @brief This function append the 802_11N tlv
2448 *
2449 * @param pmpriv A pointer to mlan_private structure
2450 * @param pbss_desc A pointer to BSSDescriptor_t structure
2451 * @param ppbuffer A Pointer to command buffer pointer
2452 *
2453 * @return bytes added to the buffer
2454 */
2455 int
wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,IN BSSDescriptor_t * pbss_desc,OUT t_u8 ** ppbuffer)2456 wlan_cmd_append_11n_tlv(IN mlan_private *pmpriv,
2457 IN BSSDescriptor_t *pbss_desc, OUT t_u8 **ppbuffer)
2458 {
2459 pmlan_adapter pmadapter = pmpriv->adapter;
2460 MrvlIETypes_HTCap_t *pht_cap;
2461 MrvlIETypes_HTInfo_t *pht_info;
2462 MrvlIEtypes_ChanListParamSet_t *pchan_list;
2463 MrvlIETypes_2040BSSCo_t *p2040_bss_co;
2464 MrvlIETypes_ExtCap_t *pext_cap;
2465 t_u32 usr_dot_11n_dev_cap, orig_usr_dot_11n_dev_cap = 0;
2466 int ret_len = 0;
2467
2468 ENTER();
2469
2470 /* Null Checks */
2471 if (ppbuffer == MNULL) {
2472 LEAVE();
2473 return 0;
2474 }
2475 if (*ppbuffer == MNULL) {
2476 LEAVE();
2477 return 0;
2478 }
2479
2480 if (pbss_desc->bss_band & BAND_A)
2481 usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_a;
2482 else
2483 usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_bg;
2484
2485 if ((pbss_desc->bss_band & (BAND_B | BAND_G)) &&
2486 ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
2487 !wlan_check_chan_width_ht40_by_region(pmpriv, pbss_desc)) {
2488 orig_usr_dot_11n_dev_cap = usr_dot_11n_dev_cap;
2489 RESETSUPP_CHANWIDTH40(usr_dot_11n_dev_cap);
2490 RESET_40MHZ_INTOLARENT(usr_dot_11n_dev_cap);
2491 RESETSUPP_SHORTGI40(usr_dot_11n_dev_cap);
2492 pmpriv->usr_dot_11n_dev_cap_bg = usr_dot_11n_dev_cap;
2493 pbss_desc->curr_bandwidth = BW_20MHZ;
2494 }
2495 if (pbss_desc->pht_cap) {
2496 pht_cap = (MrvlIETypes_HTCap_t *)*ppbuffer;
2497 memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
2498 pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
2499 pht_cap->header.len = sizeof(HTCap_t);
2500 memcpy(pmadapter, (t_u8 *)pht_cap + sizeof(MrvlIEtypesHeader_t),
2501 (t_u8 *)pbss_desc->pht_cap + sizeof(IEEEtypes_Header_t),
2502 pht_cap->header.len);
2503
2504 pht_cap->ht_cap.ht_cap_info =
2505 wlan_le16_to_cpu(pht_cap->ht_cap.ht_cap_info);
2506 pht_cap->ht_cap.ht_ext_cap =
2507 wlan_le16_to_cpu(pht_cap->ht_cap.ht_ext_cap);
2508 wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pbss_desc->bss_band,
2509 MTRUE);
2510
2511 HEXDUMP("HT_CAPABILITIES IE", (t_u8 *)pht_cap,
2512 sizeof(MrvlIETypes_HTCap_t));
2513 *ppbuffer += sizeof(MrvlIETypes_HTCap_t);
2514 ret_len += sizeof(MrvlIETypes_HTCap_t);
2515 pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
2516 } else {
2517 //AP don't support 11N
2518 LEAVE();
2519 return 0;
2520 }
2521
2522 if (pbss_desc->pht_info) {
2523 if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
2524 pht_info = (MrvlIETypes_HTInfo_t *)*ppbuffer;
2525 memset(pmadapter, pht_info, 0,
2526 sizeof(MrvlIETypes_HTInfo_t));
2527 pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
2528 pht_info->header.len = sizeof(HTInfo_t);
2529
2530 memcpy(pmadapter,
2531 (t_u8 *)pht_info + sizeof(MrvlIEtypesHeader_t),
2532 (t_u8 *)pbss_desc->pht_info +
2533 sizeof(IEEEtypes_Header_t),
2534 pht_info->header.len);
2535
2536 if (!ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
2537 RESET_CHANWIDTH40(pht_info->ht_info.field2);
2538
2539 *ppbuffer += sizeof(MrvlIETypes_HTInfo_t);
2540 ret_len += sizeof(MrvlIETypes_HTInfo_t);
2541 pht_info->header.len =
2542 wlan_cpu_to_le16(pht_info->header.len);
2543 }
2544
2545 pchan_list = (MrvlIEtypes_ChanListParamSet_t *)*ppbuffer;
2546 memset(pmadapter, pchan_list, 0,
2547 sizeof(MrvlIEtypes_ChanListParamSet_t));
2548 pchan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
2549 pchan_list->header.len =
2550 sizeof(MrvlIEtypes_ChanListParamSet_t) -
2551 sizeof(MrvlIEtypesHeader_t);
2552 pchan_list->chan_scan_param[0].chan_number =
2553 pbss_desc->pht_info->ht_info.pri_chan;
2554 pchan_list->chan_scan_param[0].bandcfg.chanBand =
2555 wlan_band_to_radio_type((t_u8)pbss_desc->bss_band);
2556 if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
2557 ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2)
2558 && wlan_check_chan_width_ht40_by_region(pmpriv,
2559 pbss_desc)) {
2560 pchan_list->chan_scan_param[0].bandcfg.chan2Offset =
2561 GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.
2562 field2);
2563 pbss_desc->curr_bandwidth = BW_40MHZ;
2564 pchan_list->chan_scan_param[0].bandcfg.chanWidth =
2565 CHAN_BW_40MHZ;
2566 }
2567 pchan_list->chan_scan_param[0].bandcfg.scanMode =
2568 SCAN_MODE_USER;
2569 HEXDUMP("ChanList", (t_u8 *)pchan_list,
2570 sizeof(MrvlIEtypes_ChanListParamSet_t));
2571 HEXDUMP("pht_info", (t_u8 *)pbss_desc->pht_info,
2572 sizeof(MrvlIETypes_HTInfo_t) - 2);
2573 *ppbuffer += sizeof(MrvlIEtypes_ChanListParamSet_t);
2574 ret_len += sizeof(MrvlIEtypes_ChanListParamSet_t);
2575 pchan_list->header.len =
2576 wlan_cpu_to_le16(pchan_list->header.len);
2577 }
2578
2579 if (pbss_desc->pbss_co_2040) {
2580 p2040_bss_co = (MrvlIETypes_2040BSSCo_t *)*ppbuffer;
2581 memset(pmadapter, p2040_bss_co, 0,
2582 sizeof(MrvlIETypes_2040BSSCo_t));
2583 p2040_bss_co->header.type = wlan_cpu_to_le16(BSSCO_2040);
2584 p2040_bss_co->header.len = sizeof(BSSCo2040_t);
2585
2586 memcpy(pmadapter,
2587 (t_u8 *)p2040_bss_co + sizeof(MrvlIEtypesHeader_t),
2588 (t_u8 *)pbss_desc->pbss_co_2040 +
2589 sizeof(IEEEtypes_Header_t), p2040_bss_co->header.len);
2590
2591 HEXDUMP("20/40 BSS Coexistence IE", (t_u8 *)p2040_bss_co,
2592 sizeof(MrvlIETypes_2040BSSCo_t));
2593 *ppbuffer += sizeof(MrvlIETypes_2040BSSCo_t);
2594 ret_len += sizeof(MrvlIETypes_2040BSSCo_t);
2595 p2040_bss_co->header.len =
2596 wlan_cpu_to_le16(p2040_bss_co->header.len);
2597 }
2598
2599 if (pbss_desc->pext_cap) {
2600 pext_cap = (MrvlIETypes_ExtCap_t *)*ppbuffer;
2601 memset(pmadapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
2602 pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
2603 pext_cap->header.len = sizeof(ExtCap_t);
2604
2605 memcpy(pmadapter,
2606 (t_u8 *)pext_cap + sizeof(MrvlIEtypesHeader_t),
2607 (t_u8 *)&pmpriv->ext_cap, sizeof(ExtCap_t));
2608 if (!pmadapter->ecsa_enable)
2609 RESET_EXTCAP_EXT_CHANNEL_SWITCH(pext_cap->ext_cap);
2610 else
2611 SET_EXTCAP_EXT_CHANNEL_SWITCH(pext_cap->ext_cap);
2612
2613 HEXDUMP("Extended Capabilities IE", (t_u8 *)pext_cap,
2614 sizeof(MrvlIETypes_ExtCap_t));
2615 *ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
2616 ret_len += sizeof(MrvlIETypes_ExtCap_t);
2617 pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
2618 }
2619 PRINTM(MCMND, "curr_bandwidth=%d\n", pbss_desc->curr_bandwidth);
2620 if (orig_usr_dot_11n_dev_cap)
2621 pmpriv->usr_dot_11n_dev_cap_bg = orig_usr_dot_11n_dev_cap;
2622
2623 LEAVE();
2624 return ret_len;
2625 }
2626
2627 #endif /* STA_SUPPORT */
2628
2629 /**
2630 * @brief 11n configuration handler
2631 *
2632 * @param pmadapter A pointer to mlan_adapter structure
2633 * @param pioctl_req A pointer to ioctl request buffer
2634 *
2635 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
2636 */
2637 mlan_status
wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter,IN pmlan_ioctl_req pioctl_req)2638 wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
2639 {
2640 mlan_status status = MLAN_STATUS_SUCCESS;
2641 mlan_ds_11n_cfg *cfg = MNULL;
2642
2643 ENTER();
2644
2645 if (pioctl_req->buf_len < sizeof(mlan_ds_11n_cfg)) {
2646 PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
2647 pioctl_req->data_read_written = 0;
2648 pioctl_req->buf_len_needed = sizeof(mlan_ds_11n_cfg);
2649 pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
2650 LEAVE();
2651 return MLAN_STATUS_RESOURCE;
2652 }
2653 cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
2654 switch (cfg->sub_command) {
2655 case MLAN_OID_11N_CFG_TX:
2656 status = wlan_11n_ioctl_httxcfg(pmadapter, pioctl_req);
2657 break;
2658 case MLAN_OID_11N_HTCAP_CFG:
2659 status = wlan_11n_ioctl_htusrcfg(pmadapter, pioctl_req);
2660 break;
2661 case MLAN_OID_11N_CFG_AGGR_PRIO_TBL:
2662 status = wlan_11n_ioctl_aggr_prio_tbl(pmadapter, pioctl_req);
2663 break;
2664 case MLAN_OID_11N_CFG_ADDBA_REJECT:
2665 status = wlan_11n_ioctl_addba_reject(pmadapter, pioctl_req);
2666 break;
2667 case MLAN_OID_11N_CFG_ADDBA_PARAM:
2668 status = wlan_11n_ioctl_addba_param(pmadapter, pioctl_req);
2669 break;
2670 case MLAN_OID_11N_CFG_DELBA:
2671 status = wlan_11n_ioctl_delba(pmadapter, pioctl_req);
2672 break;
2673 case MLAN_OID_11N_CFG_REJECT_ADDBA_REQ:
2674 status = wlan_11n_ioctl_rejectaddbareq(pmadapter, pioctl_req);
2675 break;
2676 case MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE:
2677 status = wlan_11n_ioctl_max_tx_buf_size(pmadapter, pioctl_req);
2678 break;
2679 case MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL:
2680 status = wlan_11n_ioctl_amsdu_aggr_ctrl(pmadapter, pioctl_req);
2681 break;
2682 case MLAN_OID_11N_CFG_SUPPORTED_MCS_SET:
2683 status = wlan_11n_ioctl_supported_mcs_set(pmadapter,
2684 pioctl_req);
2685 break;
2686 case MLAN_OID_11N_CFG_TX_BF_CAP:
2687 status = wlan_11n_ioctl_tx_bf_cap(pmadapter, pioctl_req);
2688 break;
2689 case MLAN_OID_11N_CFG_TX_BF_CFG:
2690 status = wlan_11n_ioctl_tx_bf_cfg(pmadapter, pioctl_req);
2691 break;
2692 case MLAN_OID_11N_CFG_COEX_RX_WINSIZE:
2693 status = wlan_11n_ioctl_coex_rx_winsize(pmadapter, pioctl_req);
2694 break;
2695 case MLAN_OID_11N_CFG_TX_AGGR_CTRL:
2696 status = wlan_11n_ioctl_txaggrctrl(pmadapter, pioctl_req);
2697 break;
2698 case MLAN_OID_11N_CFG_IBSS_AMPDU_PARAM:
2699 status = wlan_11n_ioctl_ibss_ampdu_param(pmadapter, pioctl_req);
2700 break;
2701 default:
2702 pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
2703 status = MLAN_STATUS_FAILURE;
2704 break;
2705 }
2706 LEAVE();
2707 return status;
2708 }
2709
2710 /**
2711 * @brief This function will delete the given entry in Tx BA Stream table
2712 *
2713 * @param priv Pointer to mlan_private
2714 * @param ptx_tbl Pointer to tx ba stream entry to delete
2715 *
2716 * @return N/A
2717 */
2718 void
wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,TxBAStreamTbl * ptx_tbl)2719 wlan_11n_delete_txbastream_tbl_entry(mlan_private *priv, TxBAStreamTbl *ptx_tbl)
2720 {
2721 pmlan_adapter pmadapter = priv->adapter;
2722
2723 ENTER();
2724
2725 if (!ptx_tbl || !wlan_is_txbastreamptr_valid(priv, ptx_tbl))
2726 goto exit;
2727 PRINTM(MINFO, "Delete BA stream table entry: %p\n", ptx_tbl);
2728 util_unlink_list(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr,
2729 (pmlan_linked_list)ptx_tbl, MNULL, MNULL);
2730 pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
2731 (t_u8 *)ptx_tbl);
2732 exit:
2733 LEAVE();
2734 }
2735
2736 /**
2737 * @brief This function will delete all the entries in Tx BA Stream table
2738 *
2739 * @param priv A pointer to mlan_private
2740 *
2741 * @return N/A
2742 */
2743 void
wlan_11n_deleteall_txbastream_tbl(mlan_private * priv)2744 wlan_11n_deleteall_txbastream_tbl(mlan_private *priv)
2745 {
2746 int i;
2747 TxBAStreamTbl *del_tbl_ptr = MNULL;
2748
2749 ENTER();
2750
2751 wlan_request_ralist_lock(priv);
2752 while ((del_tbl_ptr = (TxBAStreamTbl *)
2753 util_peek_list(priv->adapter->pmoal_handle,
2754 &priv->tx_ba_stream_tbl_ptr, MNULL, MNULL))) {
2755 wlan_11n_delete_txbastream_tbl_entry(priv, del_tbl_ptr);
2756 }
2757
2758 util_init_list((pmlan_linked_list)&priv->tx_ba_stream_tbl_ptr);
2759 wlan_release_ralist_lock(priv);
2760 for (i = 0; i < MAX_NUM_TID; ++i) {
2761 priv->aggr_prio_tbl[i].ampdu_ap =
2762 priv->aggr_prio_tbl[i].ampdu_user;
2763 }
2764
2765 LEAVE();
2766 }
2767
2768 /**
2769 * @brief This function will return the pointer to an entry in BA Stream
2770 * table which matches the give RA/TID pair
2771 *
2772 * @param priv A pointer to mlan_private
2773 * @param tid TID to find in reordering table
2774 * @param ra RA to find in reordering table
2775 * @param lock flag for request the spin_lock
2776 *
2777 * @return A pointer to first entry matching RA/TID in BA stream
2778 * NULL if not found
2779 */
2780 TxBAStreamTbl *
wlan_11n_get_txbastream_tbl(mlan_private * priv,int tid,t_u8 * ra,int lock)2781 wlan_11n_get_txbastream_tbl(mlan_private *priv, int tid, t_u8 *ra, int lock)
2782 {
2783 TxBAStreamTbl *ptx_tbl;
2784 pmlan_adapter pmadapter = priv->adapter;
2785
2786 ENTER();
2787
2788 if (lock)
2789 wlan_request_ralist_lock(priv);
2790 ptx_tbl = (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle,
2791 &priv->tx_ba_stream_tbl_ptr,
2792 MNULL, MNULL);
2793 if (!ptx_tbl) {
2794 if (lock)
2795 wlan_release_ralist_lock(priv);
2796 LEAVE();
2797 return MNULL;
2798 }
2799
2800 while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
2801
2802 PRINTM(MDAT_D, "get_txbastream_tbl TID %d\n", ptx_tbl->tid);
2803 DBG_HEXDUMP(MDAT_D, "RA", ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
2804
2805 if ((!memcmp(pmadapter, ptx_tbl->ra, ra, MLAN_MAC_ADDR_LENGTH))
2806 && (ptx_tbl->tid == tid)) {
2807 if (lock)
2808 wlan_release_ralist_lock(priv);
2809 LEAVE();
2810 return ptx_tbl;
2811 }
2812
2813 ptx_tbl = ptx_tbl->pnext;
2814 }
2815 if (lock)
2816 wlan_release_ralist_lock(priv);
2817 LEAVE();
2818 return MNULL;
2819 }
2820
2821 /**
2822 * @brief This function will create a entry in tx ba stream table for the
2823 * given RA/TID.
2824 *
2825 * @param priv A pointer to mlan_private
2826 * @param ra RA to find in reordering table
2827 * @param tid TID to find in reordering table
2828 * @param ba_status BA stream status to create the stream with
2829 *
2830 * @return N/A
2831 */
2832 void
wlan_11n_create_txbastream_tbl(mlan_private * priv,t_u8 * ra,int tid,baStatus_e ba_status)2833 wlan_11n_create_txbastream_tbl(mlan_private *priv,
2834 t_u8 *ra, int tid, baStatus_e ba_status)
2835 {
2836 TxBAStreamTbl *new_node = MNULL;
2837 pmlan_adapter pmadapter = priv->adapter;
2838 raListTbl *ra_list = MNULL;
2839 int tid_down;
2840
2841 ENTER();
2842
2843 PRINTM(MDAT_D, "create_txbastream_tbl TID %d\n", tid);
2844 DBG_HEXDUMP(MDAT_D, "RA", ra, MLAN_MAC_ADDR_LENGTH);
2845
2846 if (pmadapter->callbacks.
2847 moal_malloc(pmadapter->pmoal_handle, sizeof(TxBAStreamTbl),
2848 MLAN_MEM_DEF, (t_u8 **)&new_node)) {
2849 PRINTM(MERROR,
2850 "wlan_11n_create_txbastream_tbl Failed to allocate new_node\n");
2851 LEAVE();
2852 return;
2853 }
2854 tid_down = wlan_get_wmm_tid_down(priv, tid);
2855 ra_list = wlan_wmm_get_ralist_node(priv, tid_down, ra);
2856 if (ra_list) {
2857 ra_list->amsdu_in_ampdu = MFALSE;
2858 ra_list->ba_status = ba_status;
2859 }
2860 util_init_list((pmlan_linked_list)new_node);
2861
2862 new_node->tid = tid;
2863 new_node->ba_status = ba_status;
2864 memcpy(pmadapter, new_node->ra, ra, MLAN_MAC_ADDR_LENGTH);
2865
2866 util_enqueue_list_tail(pmadapter->pmoal_handle,
2867 &priv->tx_ba_stream_tbl_ptr,
2868 (pmlan_linked_list)new_node, MNULL, MNULL);
2869
2870 LEAVE();
2871 }
2872
2873 /**
2874 * @brief This function will send a block ack to given tid/ra
2875 *
2876 * @param priv A pointer to mlan_private
2877 * @param tid TID to send the ADDBA
2878 * @param peer_mac MAC address to send the ADDBA
2879 *
2880 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2881 */
2882 int
wlan_send_addba(mlan_private * priv,int tid,t_u8 * peer_mac)2883 wlan_send_addba(mlan_private *priv, int tid, t_u8 *peer_mac)
2884 {
2885 HostCmd_DS_11N_ADDBA_REQ add_ba_req;
2886 static t_u8 dialog_tok;
2887 mlan_status ret;
2888
2889 ENTER();
2890
2891 PRINTM(MCMND, "Send addba: TID %d\n", tid);
2892 DBG_HEXDUMP(MCMD_D, "Send addba RA", peer_mac, MLAN_MAC_ADDR_LENGTH);
2893
2894 add_ba_req.block_ack_param_set =
2895 (t_u16)((tid << BLOCKACKPARAM_TID_POS) |
2896 (priv->add_ba_param.
2897 tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
2898 IMMEDIATE_BLOCK_ACK);
2899 /** enable AMSDU inside AMPDU */
2900 if (priv->add_ba_param.tx_amsdu &&
2901 (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
2902 add_ba_req.block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK;
2903 add_ba_req.block_ack_tmo = (t_u16)priv->add_ba_param.timeout;
2904
2905 ++dialog_tok;
2906
2907 if (dialog_tok == 0)
2908 dialog_tok = 1;
2909
2910 add_ba_req.dialog_token = dialog_tok;
2911 memcpy(priv->adapter, &add_ba_req.peer_mac_addr, peer_mac,
2912 MLAN_MAC_ADDR_LENGTH);
2913
2914 /* We don't wait for the response of this command */
2915 ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
2916 0, 0, MNULL, &add_ba_req);
2917
2918 LEAVE();
2919 return ret;
2920 }
2921
2922 /**
2923 * @brief This function will delete a block ack to given tid/ra
2924 *
2925 * @param priv A pointer to mlan_private
2926 * @param pioctl_req A pointer to ioctl request buffer
2927 * @param tid TID to send the ADDBA
2928 * @param peer_mac MAC address to send the ADDBA
2929 * @param initiator MTRUE if we have initiated ADDBA, MFALSE otherwise
2930 *
2931 * @return MLAN_STATUS_PENDING --success, otherwise fail
2932 */
2933 int
wlan_send_delba(mlan_private * priv,pmlan_ioctl_req pioctl_req,int tid,t_u8 * peer_mac,int initiator)2934 wlan_send_delba(mlan_private *priv, pmlan_ioctl_req pioctl_req, int tid,
2935 t_u8 *peer_mac, int initiator)
2936 {
2937 HostCmd_DS_11N_DELBA delba;
2938 mlan_status ret;
2939
2940 ENTER();
2941
2942 memset(priv->adapter, &delba, 0, sizeof(delba));
2943 delba.del_ba_param_set = (tid << DELBA_TID_POS);
2944
2945 if (initiator)
2946 DELBA_INITIATOR(delba.del_ba_param_set);
2947 else
2948 DELBA_RECIPIENT(delba.del_ba_param_set);
2949
2950 memcpy(priv->adapter, &delba.peer_mac_addr, peer_mac,
2951 MLAN_MAC_ADDR_LENGTH);
2952
2953 ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
2954 HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
2955 (t_void *)&delba);
2956
2957 if (ret == MLAN_STATUS_SUCCESS)
2958 ret = MLAN_STATUS_PENDING;
2959
2960 LEAVE();
2961 return ret;
2962 }
2963
2964 /**
2965 * @brief This function handles the command response of
2966 * delete a block ack request
2967 *
2968 * @param priv A pointer to mlan_private structure
2969 * @param del_ba A pointer to command response buffer
2970 *
2971 * @return N/A
2972 */
2973 void
wlan_11n_delete_bastream(mlan_private * priv,t_u8 * del_ba)2974 wlan_11n_delete_bastream(mlan_private *priv, t_u8 *del_ba)
2975 {
2976 HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *)del_ba;
2977 int tid;
2978
2979 ENTER();
2980
2981 DBG_HEXDUMP(MCMD_D, "Delba:", (t_u8 *)pdel_ba, 20);
2982 pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
2983 pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
2984
2985 tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
2986
2987 mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
2988 TYPE_DELBA_RECEIVE,
2989 INITIATOR_BIT(pdel_ba->del_ba_param_set),
2990 pdel_ba->reason_code);
2991
2992 LEAVE();
2993 }
2994
2995 /**
2996 * @brief Get Rx reordering table
2997 *
2998 * @param priv A pointer to mlan_private structure
2999 * @param buf A pointer to rx_reorder_tbl structure
3000 * @return number of rx reorder table entry
3001 */
3002 int
wlan_get_rxreorder_tbl(mlan_private * priv,rx_reorder_tbl * buf)3003 wlan_get_rxreorder_tbl(mlan_private *priv, rx_reorder_tbl *buf)
3004 {
3005 int i;
3006 rx_reorder_tbl *ptbl = buf;
3007 RxReorderTbl *rx_reorder_tbl_ptr;
3008 int count = 0;
3009 ENTER();
3010 rx_reorder_tbl_ptr =
3011 (RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
3012 &priv->rx_reorder_tbl_ptr,
3013 priv->adapter->callbacks.
3014 moal_spin_lock,
3015 priv->adapter->callbacks.
3016 moal_spin_unlock);
3017 if (!rx_reorder_tbl_ptr) {
3018 LEAVE();
3019 return count;
3020 }
3021 while (rx_reorder_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
3022 ptbl->tid = (t_u16)rx_reorder_tbl_ptr->tid;
3023 memcpy(priv->adapter, ptbl->ta, rx_reorder_tbl_ptr->ta,
3024 MLAN_MAC_ADDR_LENGTH);
3025 ptbl->start_win = rx_reorder_tbl_ptr->start_win;
3026 ptbl->win_size = rx_reorder_tbl_ptr->win_size;
3027 ptbl->amsdu = rx_reorder_tbl_ptr->amsdu;
3028 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
3029 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
3030 ptbl->buffer[i] = MTRUE;
3031 else
3032 ptbl->buffer[i] = MFALSE;
3033 }
3034 rx_reorder_tbl_ptr = rx_reorder_tbl_ptr->pnext;
3035 ptbl++;
3036 count++;
3037 if (count >= MLAN_MAX_RX_BASTREAM_SUPPORTED)
3038 break;
3039 }
3040 LEAVE();
3041 return count;
3042 }
3043
3044 /**
3045 * @brief Get transmit BA stream table
3046 *
3047 * @param priv A pointer to mlan_private structure
3048 * @param buf A pointer to tx_ba_stream_tbl structure
3049 * @return number of ba stream table entry
3050 */
3051 int
wlan_get_txbastream_tbl(mlan_private * priv,tx_ba_stream_tbl * buf)3052 wlan_get_txbastream_tbl(mlan_private *priv, tx_ba_stream_tbl *buf)
3053 {
3054 TxBAStreamTbl *ptxtbl;
3055 tx_ba_stream_tbl *ptbl = buf;
3056 int count = 0;
3057 t_u32 bastream_max = 0;
3058
3059 ENTER();
3060
3061 wlan_request_ralist_lock(priv);
3062 ptxtbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
3063 &priv->tx_ba_stream_tbl_ptr,
3064 MNULL, MNULL);
3065 if (!ptxtbl) {
3066 wlan_release_ralist_lock(priv);
3067 LEAVE();
3068 return count;
3069 }
3070 bastream_max = ISSUPP_GETTXBASTREAM(priv->adapter->hw_dot_11n_dev_cap);
3071 if (bastream_max == 0)
3072 bastream_max = MLAN_MAX_TX_BASTREAM_DEFAULT;
3073
3074 while (ptxtbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
3075 ptbl->tid = (t_u16)ptxtbl->tid;
3076 PRINTM(MINFO, "tid=%d\n", ptbl->tid);
3077 memcpy(priv->adapter, ptbl->ra, ptxtbl->ra,
3078 MLAN_MAC_ADDR_LENGTH);
3079 ptbl->amsdu = ptxtbl->amsdu;
3080 ptxtbl = ptxtbl->pnext;
3081 ptbl++;
3082 count++;
3083 if (count >= bastream_max)
3084 break;
3085 }
3086 wlan_release_ralist_lock(priv);
3087 LEAVE();
3088 return count;
3089 }
3090
3091 /**
3092 * @brief This function check if 11AC is allowed in bandcfg
3093 *
3094 * @param pmpriv A pointer to mlan_private structure
3095 * @param bss_band bss band
3096 *
3097 * @return 0--not allowed, other value allowed
3098 */
3099 t_u8
wlan_11n_bandconfig_allowed(mlan_private * pmpriv,t_u8 bss_band)3100 wlan_11n_bandconfig_allowed(mlan_private *pmpriv, t_u8 bss_band)
3101 {
3102 if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
3103 if (bss_band & BAND_G)
3104 return (pmpriv->adapter->adhoc_start_band & BAND_GN);
3105 else if (bss_band & BAND_A)
3106 return (pmpriv->adapter->adhoc_start_band & BAND_AN);
3107 } else {
3108 if (bss_band & BAND_G)
3109 return (pmpriv->config_bands & BAND_GN);
3110 else if (bss_band & BAND_A)
3111 return (pmpriv->config_bands & BAND_AN);
3112 }
3113 return 0;
3114 }
3115
3116 /**
3117 * @brief This function cleans up txbastream_tbl for specific station
3118 *
3119 * @param priv A pointer to mlan_private
3120 * @param ra RA to find in txbastream_tbl
3121 * @return N/A
3122 */
3123 void
wlan_11n_cleanup_txbastream_tbl(mlan_private * priv,t_u8 * ra)3124 wlan_11n_cleanup_txbastream_tbl(mlan_private *priv, t_u8 *ra)
3125 {
3126 TxBAStreamTbl *ptx_tbl = MNULL;
3127 t_u8 i;
3128 ENTER();
3129
3130 wlan_request_ralist_lock(priv);
3131 for (i = 0; i < MAX_NUM_TID; ++i) {
3132 ptx_tbl = wlan_11n_get_txbastream_tbl(priv, i, ra, MFALSE);
3133 if (ptx_tbl)
3134 wlan_11n_delete_txbastream_tbl_entry(priv, ptx_tbl);
3135 }
3136 wlan_release_ralist_lock(priv);
3137 LEAVE();
3138 return;
3139 }
3140
3141 void
wlan_update_11n_cap(mlan_private * pmpriv)3142 wlan_update_11n_cap(mlan_private *pmpriv)
3143 {
3144 mlan_adapter *pmadapter = pmpriv->adapter;
3145
3146 pmpriv->usr_dev_mcs_support = pmadapter->hw_dev_mcs_support;
3147 pmpriv->usr_dot_11n_dev_cap_bg =
3148 pmadapter->hw_dot_11n_dev_cap & DEFAULT_11N_CAP_MASK_BG;
3149 pmpriv->usr_dot_11n_dev_cap_a =
3150 pmadapter->hw_dot_11n_dev_cap & DEFAULT_11N_CAP_MASK_A;
3151 }
3152