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