xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlan/mlan_11n.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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