xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_eth_ioctl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 
2 /** @file  moal_eth_ioctl.c
3   *
4   * @brief This file contains private ioctl functions
5 
6   *
7   * Copyright 2014-2022 NXP
8   *
9   * This software file (the File) is distributed by NXP
10   * under the terms of the GNU General Public License Version 2, June 1991
11   * (the License).  You may use, redistribute and/or modify the File in
12   * accordance with the terms and conditions of the License, a copy of which
13   * is available by writing to the Free Software Foundation, Inc.,
14   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
15   * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16   *
17   * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
19   * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
20   * this warranty disclaimer.
21   *
22   */
23 
24 /************************************************************************
25 Change log:
26     01/05/2012: initial version
27 ************************************************************************/
28 
29 #include "moal_main.h"
30 #include "moal_eth_ioctl.h"
31 #include "mlan_ioctl.h"
32 #if defined(STA_WEXT) || defined(UAP_WEXT)
33 #include "moal_priv.h"
34 #endif
35 
36 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
37 #include "moal_cfg80211.h"
38 #endif
39 #ifdef UAP_SUPPORT
40 #include "moal_uap.h"
41 #endif
42 #ifdef USB
43 #include "moal_usb.h"
44 #endif
45 #ifdef SDIO
46 #include "moal_sdio.h"
47 #endif
48 #ifdef PCIE
49 #include "moal_pcie.h"
50 #endif
51 #ifdef STA_CFG80211
52 #include "moal_sta_cfg80211.h"
53 #endif
54 #ifdef STA_CFG80211
55 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
56 #include "moal_cfg80211_util.h"
57 #endif
58 #endif
59 
60 /********************************************************
61 			Local Variables
62 ********************************************************/
63 
64 /** Bands supported in Infra mode */
65 static t_u16 SupportedInfraBand[] = {
66 	BAND_B,
67 	BAND_B | BAND_G,
68 	BAND_G,
69 	BAND_GN,
70 	BAND_B | BAND_G | BAND_GN,
71 	BAND_G | BAND_GN,
72 	BAND_A,
73 	BAND_B | BAND_A,
74 	BAND_B | BAND_G | BAND_A,
75 	BAND_G | BAND_A,
76 	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
77 	BAND_A | BAND_G | BAND_AN | BAND_GN,
78 	BAND_A | BAND_AN,
79 	BAND_GN | BAND_GAC,
80 	BAND_B | BAND_G | BAND_GN | BAND_GAC,
81 	BAND_G | BAND_GN | BAND_GAC,
82 	BAND_GN | BAND_GAC | BAND_GAX,
83 	BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
84 	BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
85 	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
86 	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC,
87 	BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
88 	BAND_A | BAND_AN | BAND_AAC,
89 	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
90 	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC |
91 		BAND_AAX,
92 	BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
93 	BAND_A | BAND_AN | BAND_AAC | BAND_AAX,
94 };
95 
96 /** Bands supported in Ad-Hoc mode */
97 static t_u16 SupportedAdhocBand[] = {
98 	BAND_B,
99 	BAND_B | BAND_G,
100 	BAND_G,
101 	BAND_A,
102 };
103 
104 /********************************************************
105 			Global Variables
106 ********************************************************/
107 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
108 #ifdef UAP_SUPPORT
109 /** Network device handlers for uAP */
110 extern const struct net_device_ops woal_uap_netdev_ops;
111 #endif
112 #ifdef STA_SUPPORT
113 /** Network device handlers for STA */
114 extern const struct net_device_ops woal_netdev_ops;
115 #endif
116 #endif
117 
118 /********************************************************
119 			Local Functions
120 ********************************************************/
121 /**
122  * @brief Parse a string to extract numerical arguments
123  *
124  * @param pos           Pointer to the arguments string
125  * @param data          Pointer to the arguments buffer
126  * @param datalen       Length of the arguments buffer
127  * @param user_data_len Pointer to the number of arguments extracted
128  *
129  * @return              MLAN_STATUS_SUCCESS
130  */
parse_arguments(t_u8 * pos,int * data,int datalen,int * user_data_len)131 static mlan_status parse_arguments(t_u8 *pos, int *data, int datalen,
132 				   int *user_data_len)
133 {
134 	int i, j, k;
135 	char cdata[10];
136 	int is_hex = 0;
137 
138 	if (strlen(pos) == 0) {
139 		*user_data_len = 0;
140 		return MLAN_STATUS_SUCCESS;
141 	}
142 
143 	memset(cdata, 0, sizeof(cdata));
144 	for (i = 0, j = 0, k = 0; i <= (int)strlen(pos); i++) {
145 		if ((k == 0) && (i <= (int)(strlen(pos) - 2))) {
146 			if ((pos[i] == '0') && (pos[i + 1] == 'x')) {
147 				is_hex = 1;
148 				i = i + 2;
149 			}
150 		}
151 		if (pos[i] == '\0' || pos[i] == ' ') {
152 			if (j >= datalen) {
153 				j++;
154 				break;
155 			}
156 			if (is_hex) {
157 				data[j] = woal_atox(cdata);
158 				is_hex = 0;
159 			} else {
160 				woal_atoi(&data[j], cdata);
161 			}
162 			j++;
163 			k = 0;
164 			memset(cdata, 0, sizeof(cdata));
165 			if (pos[i] == '\0')
166 				break;
167 		} else {
168 			if (k >= (int)sizeof(cdata)) {
169 				PRINTM(MERROR, "Invalid numerical arguments\n");
170 				break;
171 			}
172 			cdata[k] = pos[i];
173 			k++;
174 		}
175 	}
176 
177 	*user_data_len = j;
178 	return MLAN_STATUS_SUCCESS;
179 }
180 
181 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
182 /**
183  *  @brief Set wps & p2p ie in AP mode
184  *
185  *  @param priv         Pointer to priv stucture
186  *  @param ie           Pointer to ies data
187  *  @param len          Length of data
188  *
189  *  @return             MLAN_STATUS_SUCCESS -- success, otherwise fail
190  */
woal_set_ap_wps_p2p_ie(moal_private * priv,t_u8 * ie,size_t len)191 mlan_status woal_set_ap_wps_p2p_ie(moal_private *priv, t_u8 *ie, size_t len)
192 {
193 	mlan_status ret = MLAN_STATUS_SUCCESS;
194 	t_u8 *pos = ie;
195 	int ie_len;
196 
197 	ENTER();
198 
199 	ie_len = len - 2;
200 	if (ie_len <= 0) {
201 		PRINTM(MERROR, "IE len error: %d\n", ie_len);
202 		ret = -EFAULT;
203 		goto done;
204 	}
205 
206 	/* Android cmd format:
207 	 * "SET_AP_WPS_P2P_IE 1"  -- beacon IE
208 	 * "SET_AP_WPS_P2P_IE 2"  -- proberesp IE
209 	 * "SET_AP_WPS_P2P_IE 4"  -- assocresp IE
210 	 */
211 	if (*pos == '1') {
212 		/* set the beacon wps/p2p ies */
213 		pos += 2;
214 		if (MLAN_STATUS_SUCCESS !=
215 		    woal_cfg80211_mgmt_frame_ie(
216 			    priv, pos, ie_len, NULL, 0, NULL, 0, NULL, 0,
217 			    MGMT_MASK_BEACON_WPS_P2P, MOAL_IOCTL_WAIT)) {
218 			PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
219 			ret = -EFAULT;
220 			goto done;
221 		}
222 	} else if (*pos == '2') {
223 		/* set the probe resp ies */
224 		pos += 2;
225 		if (MLAN_STATUS_SUCCESS !=
226 		    woal_cfg80211_mgmt_frame_ie(
227 			    priv, NULL, 0, pos, ie_len, NULL, 0, NULL, 0,
228 			    MGMT_MASK_PROBE_RESP, MOAL_IOCTL_WAIT)) {
229 			PRINTM(MERROR, "Failed to set probe resp ie\n");
230 			ret = -EFAULT;
231 			goto done;
232 		}
233 	} else if (*pos == '4') {
234 		/* set the assoc resp ies */
235 		pos += 2;
236 		if (MLAN_STATUS_SUCCESS !=
237 		    woal_cfg80211_mgmt_frame_ie(
238 			    priv, NULL, 0, NULL, 0, pos, ie_len, NULL, 0,
239 			    MGMT_MASK_ASSOC_RESP, MOAL_IOCTL_WAIT)) {
240 			PRINTM(MERROR, "Failed to set assoc resp ie\n");
241 			ret = -EFAULT;
242 			goto done;
243 		}
244 	}
245 
246 done:
247 	LEAVE();
248 	return ret;
249 }
250 #endif
251 
252 #ifdef WIFI_DIRECT_SUPPORT
253 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
254 /**
255  *  @brief Set miracast mode
256  *
257  *  @param priv         Pointer to priv stucture
258  *  @param pdata        Pointer to cmd buffer
259  *  @param len          Length of data
260  *
261  *  @return             MLAN_STATUS_SUCCESS -- success, otherwise fail
262  */
woal_set_miracast_mode(moal_private * priv,t_u8 * pdata,size_t len)263 static mlan_status woal_set_miracast_mode(moal_private *priv, t_u8 *pdata,
264 					  size_t len)
265 {
266 	mlan_status ret = MLAN_STATUS_SUCCESS;
267 	t_u8 *pos = pdata;
268 
269 	ENTER();
270 	if (!pos || (len == 0)) {
271 		PRINTM(MERROR, "%s: Null buf!\n", __func__);
272 		ret = MLAN_STATUS_FAILURE;
273 		goto done;
274 	}
275 	while (!isdigit(*pos) && --len > 0)
276 		pos++;
277 	switch (*pos) {
278 	case '0':
279 		/* disable miracast mode */
280 		priv->phandle->miracast_mode = 0;
281 		break;
282 	case '1':
283 		/* Source */
284 		priv->phandle->miracast_mode = 1;
285 		break;
286 	case '2':
287 		/* Sink */
288 		priv->phandle->miracast_mode = 2;
289 		break;
290 	default:
291 		PRINTM(MERROR, "%s: Unknown miracast mode (%c)\n",
292 		       priv->netdev->name, *pos);
293 		ret = MLAN_STATUS_FAILURE;
294 		break;
295 	}
296 done:
297 	LEAVE();
298 	return ret;
299 }
300 #endif
301 #endif
302 
303 /**
304  *  @brief Get Driver Version
305  *
306  *  @param priv         A pointer to moal_private structure
307  *  @param respbuf      A pointer to response buffer
308  *  @param respbuflen   Available length of response buffer
309  *
310  *  @return             Number of bytes written, negative for failure.
311  */
woal_get_priv_driver_version(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)312 static int woal_get_priv_driver_version(moal_private *priv, t_u8 *respbuf,
313 					t_u32 respbuflen)
314 {
315 	int len = 0, ret = -1;
316 	char buf[MLAN_MAX_VER_STR_LEN];
317 
318 	ENTER();
319 
320 	if (!respbuf) {
321 		LEAVE();
322 		return 0;
323 	}
324 
325 	memset(buf, 0, sizeof(buf));
326 
327 	/* Get version string to local buffer */
328 	woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
329 	len = strlen(buf);
330 
331 	if (len) {
332 		/* Copy back the retrieved version string */
333 		PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
334 		ret = MIN(len, (int)(respbuflen - 1));
335 		moal_memcpy_ext(priv->phandle, respbuf, buf, ret,
336 				respbuflen - 1);
337 	} else {
338 		ret = -1;
339 		PRINTM(MERROR, "Get version failed!\n");
340 	}
341 
342 	LEAVE();
343 	return ret;
344 }
345 /**
346  *  @brief Hostcmd interface from application
347  *
348  *  @param priv         A pointer to moal_private structure
349  *  @param respbuf      A pointer to response buffer
350  *  @param respbuflen   Available length of response buffer
351  *  @param wait_option  Wait option
352  *
353  *  @return             Number of bytes written, negative for failure.
354  */
woal_priv_hostcmd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,t_u8 wait_option)355 int woal_priv_hostcmd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
356 		      t_u8 wait_option)
357 {
358 	int ret = 0;
359 	t_u8 *data_ptr;
360 	t_u32 buf_len = 0;
361 	HostCmd_Header cmd_header;
362 	mlan_ioctl_req *req = NULL;
363 	mlan_ds_misc_cfg *misc_cfg = NULL;
364 	mlan_status status = MLAN_STATUS_SUCCESS;
365 
366 	ENTER();
367 
368 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD));
369 	buf_len = *((t_u32 *)data_ptr);
370 	moal_memcpy_ext(priv->phandle, &cmd_header, data_ptr + sizeof(buf_len),
371 			sizeof(HostCmd_Header), sizeof(HostCmd_Header));
372 
373 	PRINTM(MINFO, "Host command len = %d\n",
374 	       woal_le16_to_cpu(cmd_header.size));
375 	if (woal_le16_to_cpu(cmd_header.size) > MRVDRV_SIZE_OF_CMD_BUFFER) {
376 		LEAVE();
377 		return -EINVAL;
378 	}
379 
380 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
381 	if (req == NULL) {
382 		ret = -ENOMEM;
383 		goto error;
384 	}
385 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
386 	misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
387 	req->req_id = MLAN_IOCTL_MISC_CFG;
388 	req->action = MLAN_ACT_SET;
389 	misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
390 	/* get the whole command */
391 	moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd,
392 			data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.len,
393 			MRVDRV_SIZE_OF_CMD_BUFFER);
394 
395 	status = woal_request_ioctl(priv, req, wait_option);
396 	if (status != MLAN_STATUS_SUCCESS) {
397 		ret = -EFAULT;
398 		goto error;
399 	}
400 	ret = misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_NXP) +
401 	      strlen(PRIV_CMD_HOSTCMD);
402 	if (ret > (int)respbuflen) {
403 		ret = -EFAULT;
404 		goto error;
405 	}
406 	moal_memcpy_ext(
407 		priv->phandle, data_ptr + sizeof(buf_len),
408 		misc_cfg->param.hostcmd.cmd, misc_cfg->param.hostcmd.len,
409 		respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD) +
410 			      sizeof(buf_len)));
411 	moal_memcpy_ext(priv->phandle, data_ptr,
412 			(t_u8 *)&misc_cfg->param.hostcmd.len, sizeof(t_u32),
413 			sizeof(t_u32));
414 
415 error:
416 	if (status != MLAN_STATUS_PENDING)
417 		kfree(req);
418 
419 	LEAVE();
420 	return ret;
421 }
422 
423 /**
424  * @brief               configure 11ax HE capability or HE operation
425  *
426  *
427  *  @param priv    Pointer to the mlan_private driver data struct
428  *  @param respbuf      A pointer to response buffer
429  *  @param len          length used
430  *  @param respbuflen   Available length of response buffer
431  *
432  *  @return         Number of bytes written if successful else negative value
433  */
woal_setget_priv_11axcmdcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,t_u8 wait_option)434 static int woal_setget_priv_11axcmdcfg(moal_private *priv, t_u8 *respbuf,
435 				       t_u32 respbuflen, t_u8 wait_option)
436 {
437 	mlan_ioctl_req *req = NULL;
438 	mlan_ds_11ax_cmd_cfg *cfg = NULL;
439 	int ret = 0;
440 	mlan_status status = MLAN_STATUS_SUCCESS;
441 	int header_len = 0, user_data_len = 0;
442 	int data[3] = {0};
443 	ENTER();
444 
445 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cmd_cfg));
446 	if (req == NULL) {
447 		ret = -ENOMEM;
448 		goto done;
449 	}
450 
451 	req->req_id = MLAN_IOCTL_11AX_CFG;
452 	req->action = MLAN_ACT_SET;
453 
454 	cfg = (mlan_ds_11ax_cmd_cfg *)req->pbuf;
455 	cfg->sub_command = MLAN_OID_11AX_CMD_CFG;
456 
457 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
458 			&user_data_len);
459 	PRINTM(MINFO, "data_len=%d,data=%d,%d,%d\n", user_data_len, data[0],
460 	       data[1], data[2]);
461 
462 	if (user_data_len > 3 || user_data_len == 0) {
463 		PRINTM(MERROR, "Invalid parameters\n");
464 		ret = -EFAULT;
465 		goto done;
466 	} else if (user_data_len == 1) {
467 		req->action = MLAN_ACT_GET;
468 	}
469 
470 	switch (data[0]) {
471 	case MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET:
472 		cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
473 		cfg->param.sr_cfg.type = MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID;
474 		cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_obss_pd_offset);
475 		cfg->param.sr_cfg.param.obss_pd_offset.offset[0] = data[1];
476 		cfg->param.sr_cfg.param.obss_pd_offset.offset[1] = data[2];
477 		break;
478 	case MLAN_11AXCMD_CFG_ID_SR_ENABLE:
479 		cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
480 		cfg->param.sr_cfg.type = MRVL_DOT11AX_ENABLE_SR_TLV_ID;
481 		cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_sr_control);
482 		cfg->param.sr_cfg.param.sr_control.control = data[1];
483 		break;
484 	case MLAN_11AXCMD_CFG_ID_BEAM_CHANGE:
485 		cfg->sub_id = MLAN_11AXCMD_BEAM_SUBID;
486 		cfg->param.beam_cfg.value = data[1];
487 		break;
488 	case MLAN_11AXCMD_CFG_ID_HTC_ENABLE:
489 		cfg->sub_id = MLAN_11AXCMD_HTC_SUBID;
490 		cfg->param.htc_cfg.value = data[1];
491 		break;
492 	case MLAN_11AXCMD_CFG_ID_TXOP_RTS:
493 		cfg->sub_id = MLAN_11AXCMD_TXOPRTS_SUBID;
494 		cfg->param.txop_cfg.rts_thres = data[1];
495 		break;
496 	case MLAN_11AXCMD_CFG_ID_TX_OMI:
497 		cfg->sub_id = MLAN_11AXCMD_TXOMI_SUBID;
498 		cfg->param.txomi_cfg.omi = data[1];
499 		break;
500 	case MLAN_11AXCMD_CFG_ID_OBSSNBRU_TOLTIME:
501 		cfg->sub_id = MLAN_11AXCMD_OBSS_TOLTIME_SUBID;
502 		cfg->param.toltime_cfg.tol_time = data[1];
503 		break;
504 	default:
505 		PRINTM(MERROR, "unknown 11axcmd\n");
506 		ret = -EFAULT;
507 		goto done;
508 	}
509 
510 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
511 	if (status != MLAN_STATUS_SUCCESS) {
512 		ret = -EFAULT;
513 		goto done;
514 	}
515 	moal_memcpy_ext(priv->phandle, respbuf, &req->action,
516 			sizeof(req->action), sizeof(req->action));
517 	respbuf += sizeof(req->action);
518 
519 	cfg = (mlan_ds_11ax_cmd_cfg *)respbuf;
520 	moal_memcpy_ext(priv->phandle, cfg, req->pbuf,
521 			sizeof(mlan_ds_11ax_cmd_cfg), respbuflen);
522 
523 	ret = sizeof(req->action) + sizeof(mlan_ds_11ax_cmd_cfg);
524 
525 done:
526 	if (status != MLAN_STATUS_PENDING)
527 		kfree(req);
528 	LEAVE();
529 	return ret;
530 }
531 
532 /**
533  *  @brief             Set/get range ext mode
534  *
535  *
536  *  @param priv    Pointer to the mlan_private driver data struct
537  *  @param respbuf      A pointer to response buffer
538  *  @param len          length used
539  *  @param respbuflen   Available length of response buffer
540  *
541  *  @return         Number of bytes written if successful else negative value
542  */
woal_setget_priv_range_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)543 static int woal_setget_priv_range_ext(moal_private *priv, t_u8 *respbuf,
544 				      t_u32 respbuflen)
545 {
546 	mlan_ioctl_req *req = NULL;
547 	mlan_ds_misc_cfg *misc = NULL;
548 	int ret = 0;
549 	int data[1];
550 	int header_len = 0, user_data_len = 0;
551 	mlan_status status = MLAN_STATUS_SUCCESS;
552 
553 	ENTER();
554 
555 	if (!respbuf) {
556 		PRINTM(MERROR, "response buffer is not available!\n");
557 		ret = -EINVAL;
558 		goto done;
559 	}
560 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RANGE_EXT);
561 	user_data_len = strlen(respbuf) - header_len;
562 
563 	/* Allocate an IOCTL request buffer */
564 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
565 	if (req == NULL) {
566 		ret = -ENOMEM;
567 		goto done;
568 	}
569 	/* Fill request buffer */
570 	misc = (mlan_ds_misc_cfg *)req->pbuf;
571 	misc->sub_command = MLAN_OID_MISC_RANGE_EXT;
572 	req->req_id = MLAN_IOCTL_MISC_CFG;
573 	if ((int)strlen(respbuf) == header_len) {
574 		/* GET operation */
575 		user_data_len = 0;
576 		req->action = MLAN_ACT_GET;
577 	} else {
578 		/* SET operation */
579 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
580 				&user_data_len);
581 		if (user_data_len != 1) {
582 			PRINTM(MERROR, "Invalid Parameter\n");
583 			ret = -EFAULT;
584 			goto done;
585 		}
586 		if (data[0] < 0 || data[0] > 2) {
587 			PRINTM(MERROR,
588 			       "Invalid Parameter: range_ext mode 0-2\n");
589 			ret = -EFAULT;
590 			goto done;
591 		}
592 		misc->param.range_ext_mode = (t_u8)data[0];
593 		req->action = MLAN_ACT_SET;
594 	}
595 	/* Send IOCTL request to MLAN */
596 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
597 	if (status != MLAN_STATUS_SUCCESS) {
598 		ret = -EFAULT;
599 		goto done;
600 	}
601 
602 	data[0] = misc->param.range_ext_mode;
603 	moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
604 			respbuflen);
605 	ret = sizeof(data);
606 done:
607 	if (status != MLAN_STATUS_PENDING)
608 		kfree(req);
609 
610 	LEAVE();
611 	return ret;
612 }
613 
614 /**
615  *  @brief Custom IE setting
616  *
617  *  @param priv         A pointer to moal_private structure
618  *  @param respbuf      A pointer to response buffer
619  *  @param respbuflen   Available length of response buffer
620  *
621  *  @return             Number of bytes written, negative for failure.
622  */
woal_priv_customie(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)623 static int woal_priv_customie(moal_private *priv, t_u8 *respbuf,
624 			      t_u32 respbuflen)
625 {
626 	int ret = 0;
627 	t_u8 *data_ptr;
628 	mlan_ioctl_req *ioctl_req = NULL;
629 	mlan_ds_misc_cfg *misc = NULL;
630 	mlan_ds_misc_custom_ie *pcustom_ie = NULL;
631 	mlan_status status = MLAN_STATUS_SUCCESS;
632 
633 	ENTER();
634 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE));
635 
636 	pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
637 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
638 	if (ioctl_req == NULL) {
639 		ret = -ENOMEM;
640 		goto done;
641 	}
642 
643 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
644 	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
645 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
646 	if ((pcustom_ie->len == 0) ||
647 	    (pcustom_ie->len == sizeof(pcustom_ie->ie_data_list[0].ie_index)))
648 		ioctl_req->action = MLAN_ACT_GET;
649 	else
650 		ioctl_req->action = MLAN_ACT_SET;
651 
652 	moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, pcustom_ie,
653 			sizeof(mlan_ds_misc_custom_ie),
654 			sizeof(mlan_ds_misc_custom_ie));
655 
656 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
657 	if (status != MLAN_STATUS_SUCCESS) {
658 		ret = -EFAULT;
659 		goto done;
660 	}
661 	pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
662 	moal_memcpy_ext(priv->phandle, pcustom_ie, &misc->param.cust_ie,
663 			sizeof(mlan_ds_misc_custom_ie),
664 			respbuflen -
665 				(strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE)));
666 	ret = sizeof(mlan_ds_misc_custom_ie);
667 	if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
668 		/* send a separate error code to indicate error from driver */
669 		ret = EFAULT;
670 	}
671 done:
672 	if (status != MLAN_STATUS_PENDING)
673 		kfree(ioctl_req);
674 	LEAVE();
675 	return ret;
676 }
677 
678 /**
679  *  @brief Set/Get Band and Adhoc-band setting
680  *
681  *  @param priv         A pointer to moal_private structure
682  *  @param respbuf      A pointer to response buffer
683  *  @param respbuflen   Available length of response buffer
684  *
685  *  @return             Number of bytes written, negative for failure.
686  */
woal_setget_priv_bandcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)687 static int woal_setget_priv_bandcfg(moal_private *priv, t_u8 *respbuf,
688 				    t_u32 respbuflen)
689 {
690 	int ret = 0;
691 	unsigned int i;
692 	int data[3];
693 	int user_data_len = 0;
694 	t_u32 infra_band = 0;
695 	t_u32 adhoc_band = 0;
696 	t_u32 adhoc_channel = 0;
697 	mlan_ioctl_req *req = NULL;
698 	mlan_ds_radio_cfg *radio_cfg = NULL;
699 	mlan_ds_band_cfg *band_cfg = NULL;
700 	mlan_status status = MLAN_STATUS_SUCCESS;
701 
702 	ENTER();
703 
704 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BANDCFG))) {
705 		/* GET operation */
706 		user_data_len = 0;
707 	} else {
708 		/* SET operation */
709 		memset((char *)data, 0, sizeof(data));
710 		parse_arguments(respbuf + strlen(CMD_NXP) +
711 					strlen(PRIV_CMD_BANDCFG),
712 				data, ARRAY_SIZE(data), &user_data_len);
713 	}
714 
715 	if (sizeof(int) * user_data_len > sizeof(data)) {
716 		PRINTM(MERROR, "Too many arguments\n");
717 		LEAVE();
718 		return -EINVAL;
719 	}
720 
721 	if (user_data_len > 0) {
722 		if (priv->media_connected == MTRUE) {
723 			LEAVE();
724 			return -EOPNOTSUPP;
725 		}
726 	}
727 
728 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
729 	if (req == NULL) {
730 		ret = -ENOMEM;
731 		goto error;
732 	}
733 	radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
734 	radio_cfg->sub_command = MLAN_OID_BAND_CFG;
735 	req->req_id = MLAN_IOCTL_RADIO_CFG;
736 
737 	if (user_data_len == 0) {
738 		/* Get config_bands, adhoc_start_band and adhoc_channel values
739 		 * from MLAN
740 		 */
741 		req->action = MLAN_ACT_GET;
742 	} else {
743 		/* To support only <b/bg/bgn/n/aac/gac> */
744 		infra_band = data[0];
745 
746 		for (i = 0; i < (sizeof(SupportedInfraBand) /
747 				 sizeof(SupportedInfraBand[0]));
748 		     i++)
749 			if (infra_band == SupportedInfraBand[i])
750 				break;
751 		if (i == sizeof(SupportedInfraBand)) {
752 			ret = -EINVAL;
753 			goto error;
754 		}
755 
756 		/* Set Adhoc band */
757 		if (user_data_len >= 2) {
758 			adhoc_band = data[1];
759 			for (i = 0; i < (sizeof(SupportedAdhocBand) /
760 					 sizeof(SupportedAdhocBand[0]));
761 			     i++)
762 				if (adhoc_band == SupportedAdhocBand[i])
763 					break;
764 			if (i == sizeof(SupportedAdhocBand)) {
765 				ret = -EINVAL;
766 				goto error;
767 			}
768 		}
769 
770 		/* Set Adhoc channel */
771 		if (user_data_len >= 3) {
772 			adhoc_channel = data[2];
773 			if (adhoc_channel == 0) {
774 				/* Check if specified adhoc channel is non-zero
775 				 */
776 				ret = -EINVAL;
777 				goto error;
778 			}
779 		}
780 		/* Set config_bands and adhoc_start_band values to MLAN */
781 		req->action = MLAN_ACT_SET;
782 		radio_cfg->param.band_cfg.config_bands = infra_band;
783 		radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
784 		radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
785 	}
786 
787 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
788 	if (status != MLAN_STATUS_SUCCESS) {
789 		ret = -EFAULT;
790 		goto error;
791 	}
792 
793 	band_cfg = (mlan_ds_band_cfg *)respbuf;
794 
795 	moal_memcpy_ext(priv->phandle, band_cfg, &radio_cfg->param.band_cfg,
796 			sizeof(mlan_ds_band_cfg), respbuflen);
797 
798 	ret = sizeof(mlan_ds_band_cfg);
799 
800 error:
801 	if (status != MLAN_STATUS_PENDING)
802 		kfree(req);
803 
804 	LEAVE();
805 	return ret;
806 }
807 
808 /**
809  *  @brief Set/Get 11n configurations
810  *
811  *  @param priv         A pointer to moal_private structure
812  *  @param respbuf      A pointer to response buffer
813  *  @param respbuflen   Available length of response buffer
814  *
815  *  @return             Number of bytes written, negative for failure.
816  */
woal_setget_priv_httxcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)817 static int woal_setget_priv_httxcfg(moal_private *priv, t_u8 *respbuf,
818 				    t_u32 respbuflen)
819 {
820 	t_u32 data[2];
821 	mlan_ioctl_req *req = NULL;
822 	mlan_ds_11n_cfg *cfg_11n = NULL;
823 	int ret = 0;
824 	int user_data_len = 0;
825 	mlan_status status = MLAN_STATUS_SUCCESS;
826 
827 	ENTER();
828 
829 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTTXCFG))) {
830 		/* GET operation */
831 		user_data_len = 0;
832 	} else {
833 		/* SET operation */
834 		memset((char *)data, 0, sizeof(data));
835 		parse_arguments(respbuf + strlen(CMD_NXP) +
836 					strlen(PRIV_CMD_HTTXCFG),
837 				data, ARRAY_SIZE(data), &user_data_len);
838 	}
839 
840 	if (user_data_len > 2) {
841 		PRINTM(MERROR, "Too many arguments\n");
842 		ret = -EINVAL;
843 		goto done;
844 	}
845 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
846 	if (req == NULL) {
847 		ret = -ENOMEM;
848 		goto done;
849 	}
850 
851 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
852 	cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
853 	req->req_id = MLAN_IOCTL_11N_CFG;
854 
855 	if (user_data_len == 0) {
856 		/* Get 11n tx parameters from MLAN */
857 		req->action = MLAN_ACT_GET;
858 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
859 	} else {
860 		cfg_11n->param.tx_cfg.httxcap = data[0];
861 		PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
862 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
863 		if (user_data_len == 2) {
864 			if (data[1] != BAND_SELECT_BG &&
865 			    data[1] != BAND_SELECT_A &&
866 			    data[1] != BAND_SELECT_BOTH) {
867 				PRINTM(MERROR, "Invalid band selection\n");
868 				ret = -EINVAL;
869 				goto done;
870 			}
871 			cfg_11n->param.tx_cfg.misc_cfg = data[1];
872 			PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
873 		}
874 		/* Update 11n tx parameters in MLAN */
875 		req->action = MLAN_ACT_SET;
876 	}
877 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
878 	if (status != MLAN_STATUS_SUCCESS) {
879 		ret = -EFAULT;
880 		goto done;
881 	}
882 	data[0] = cfg_11n->param.tx_cfg.httxcap;
883 	PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
884 
885 	if (req->action == MLAN_ACT_GET) {
886 		cfg_11n->param.tx_cfg.httxcap = 0;
887 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
888 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
889 		if (status != MLAN_STATUS_SUCCESS) {
890 			ret = -EFAULT;
891 			goto done;
892 		}
893 		data[1] = cfg_11n->param.tx_cfg.httxcap;
894 		PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
895 	}
896 
897 	moal_memcpy_ext(priv->phandle, respbuf, data, sizeof(data), respbuflen);
898 	ret = sizeof(data);
899 
900 done:
901 	if (status != MLAN_STATUS_PENDING)
902 		kfree(req);
903 	LEAVE();
904 	return ret;
905 }
906 
907 /**
908  *  @brief Set/Get 11n capability information
909  *
910  *  @param priv         A pointer to moal_private structure
911  *  @param respbuf      A pointer to response buffer
912  *  @param respbuflen   Available length of response buffer
913  *
914  *  @return             Number of bytes written, negative for failure.
915  */
woal_setget_priv_htcapinfo(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)916 static int woal_setget_priv_htcapinfo(moal_private *priv, t_u8 *respbuf,
917 				      t_u32 respbuflen)
918 {
919 	int data[2];
920 	mlan_ioctl_req *req = NULL;
921 	mlan_ds_11n_cfg *cfg_11n = NULL;
922 	woal_ht_cap_info *ht_cap = NULL;
923 	int ret = 0;
924 	int user_data_len = 0;
925 	mlan_status status = MLAN_STATUS_SUCCESS;
926 
927 	ENTER();
928 
929 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTCAPINFO))) {
930 		/* GET operation */
931 		user_data_len = 0;
932 	} else {
933 		/* SET operation */
934 		memset((char *)data, 0, sizeof(data));
935 		parse_arguments(respbuf + strlen(CMD_NXP) +
936 					strlen(PRIV_CMD_HTCAPINFO),
937 				data, ARRAY_SIZE(data), &user_data_len);
938 	}
939 
940 	if (user_data_len > 2) {
941 		PRINTM(MERROR, "Too many arguments\n");
942 		ret = -EINVAL;
943 		goto done;
944 	}
945 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
946 	if (req == NULL) {
947 		ret = -ENOMEM;
948 		goto done;
949 	}
950 
951 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
952 	cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
953 	req->req_id = MLAN_IOCTL_11N_CFG;
954 
955 	if (user_data_len == 0) {
956 		/* Get 11n tx parameters from MLAN */
957 		req->action = MLAN_ACT_GET;
958 		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
959 	} else {
960 		cfg_11n->param.htcap_cfg.htcap = data[0];
961 		PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
962 		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
963 		if (user_data_len == 2) {
964 			if (data[1] != BAND_SELECT_BG &&
965 			    data[1] != BAND_SELECT_A &&
966 			    data[1] != BAND_SELECT_BOTH) {
967 				PRINTM(MERROR, "Invalid band selection\n");
968 				ret = -EINVAL;
969 				goto done;
970 			}
971 			cfg_11n->param.htcap_cfg.misc_cfg = data[1];
972 			PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
973 		}
974 		/* Update 11n tx parameters in MLAN */
975 		req->action = MLAN_ACT_SET;
976 	}
977 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
978 	if (status != MLAN_STATUS_SUCCESS) {
979 		ret = -EFAULT;
980 		goto done;
981 	}
982 	data[0] = cfg_11n->param.htcap_cfg.htcap;
983 	PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]);
984 
985 	if (req->action == MLAN_ACT_GET) {
986 		cfg_11n->param.htcap_cfg.htcap = 0;
987 		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
988 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
989 		if (status != MLAN_STATUS_SUCCESS) {
990 			ret = -EFAULT;
991 			goto done;
992 		}
993 		data[1] = cfg_11n->param.htcap_cfg.htcap;
994 		PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]);
995 	}
996 
997 	ht_cap = (woal_ht_cap_info *)respbuf;
998 	ht_cap->ht_cap_info_bg = data[0];
999 	ht_cap->ht_cap_info_a = data[1];
1000 	ret = sizeof(woal_ht_cap_info);
1001 
1002 done:
1003 	if (status != MLAN_STATUS_PENDING)
1004 		kfree(req);
1005 	LEAVE();
1006 	return ret;
1007 }
1008 
1009 /**
1010  *  @brief Set/Get add BA parameters
1011  *
1012  *  @param priv         A pointer to moal_private structure
1013  *  @param respbuf      A pointer to response buffer
1014  *  @param respbuflen   Available length of response buffer
1015  *
1016  *  @return             Number of bytes written, negative for failure.
1017  */
woal_setget_priv_addbapara(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1018 static int woal_setget_priv_addbapara(moal_private *priv, t_u8 *respbuf,
1019 				      t_u32 respbuflen)
1020 {
1021 	int data[5];
1022 	mlan_ioctl_req *req = NULL;
1023 	mlan_ds_11n_cfg *cfg_11n = NULL;
1024 	woal_addba *addba = NULL;
1025 	int ret = 0;
1026 	int user_data_len = 0;
1027 	mlan_status status = MLAN_STATUS_SUCCESS;
1028 
1029 	ENTER();
1030 
1031 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAPARA))) {
1032 		/* GET operation */
1033 		user_data_len = 0;
1034 	} else {
1035 		/* SET operation */
1036 		memset((char *)data, 0, sizeof(data));
1037 		parse_arguments(respbuf + strlen(CMD_NXP) +
1038 					strlen(PRIV_CMD_ADDBAPARA),
1039 				data, ARRAY_SIZE(data), &user_data_len);
1040 
1041 		if (user_data_len != ARRAY_SIZE(data)) {
1042 			PRINTM(MERROR, "Invalid number of arguments\n");
1043 			ret = -EINVAL;
1044 			goto done;
1045 		}
1046 		if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
1047 			PRINTM(MERROR, "Incorrect addba timeout value.\n");
1048 			ret = -EFAULT;
1049 			goto done;
1050 		}
1051 		if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE ||
1052 		    data[2] <= 0 || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
1053 			PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
1054 			ret = -EFAULT;
1055 			goto done;
1056 		}
1057 		if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
1058 			PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
1059 			ret = -EFAULT;
1060 			goto done;
1061 		}
1062 	}
1063 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1064 	if (req == NULL) {
1065 		ret = -ENOMEM;
1066 		goto done;
1067 	}
1068 
1069 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1070 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
1071 	req->req_id = MLAN_IOCTL_11N_CFG;
1072 
1073 	if (user_data_len == 0) {
1074 		/* Get add BA parameters from MLAN */
1075 		req->action = MLAN_ACT_GET;
1076 	} else {
1077 		cfg_11n->param.addba_param.timeout = data[0];
1078 		cfg_11n->param.addba_param.txwinsize = data[1];
1079 		cfg_11n->param.addba_param.rxwinsize = data[2];
1080 		cfg_11n->param.addba_param.txamsdu = data[3];
1081 		cfg_11n->param.addba_param.rxamsdu = data[4];
1082 		PRINTM(MINFO,
1083 		       "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
1084 		       data[0], data[1], data[2], data[3], data[4]);
1085 		/* Update add BA parameters in MLAN */
1086 		req->action = MLAN_ACT_SET;
1087 	}
1088 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1089 	if (status != MLAN_STATUS_SUCCESS) {
1090 		ret = -EFAULT;
1091 		goto done;
1092 	}
1093 
1094 	addba = (woal_addba *)respbuf;
1095 
1096 	addba->time_out = cfg_11n->param.addba_param.timeout;
1097 	addba->tx_win_size = cfg_11n->param.addba_param.txwinsize;
1098 	addba->rx_win_size = cfg_11n->param.addba_param.rxwinsize;
1099 	addba->tx_amsdu = cfg_11n->param.addba_param.txamsdu;
1100 	addba->rx_amsdu = cfg_11n->param.addba_param.rxamsdu;
1101 	PRINTM(MINFO,
1102 	       "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
1103 	       addba->time_out, addba->tx_win_size, addba->rx_win_size,
1104 	       addba->tx_amsdu, addba->rx_amsdu);
1105 
1106 	ret = sizeof(woal_addba);
1107 
1108 done:
1109 	if (status != MLAN_STATUS_PENDING)
1110 		kfree(req);
1111 	LEAVE();
1112 	return ret;
1113 }
1114 
1115 /**
1116  *  @brief Delete selective BA based on parameters
1117  *
1118  *  @param priv         A pointer to moal_private structure
1119  *  @param respbuf      A pointer to response buffer
1120  *  @param respbuflen   Available length of response buffer
1121  *
1122  *  @return             Number of bytes written, negative for failure.
1123  */
woal_priv_delba(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1124 static int woal_priv_delba(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
1125 {
1126 	t_u32 data[2] = {0xFF, 0xFF};
1127 	mlan_ioctl_req *req = NULL;
1128 	mlan_ds_11n_cfg *cfg_11n = NULL;
1129 	mlan_ds_11n_delba *del_ba = NULL;
1130 	int ret = 0;
1131 	int user_data_len = 0;
1132 	int header_len = 0;
1133 	t_u8 *mac_pos = NULL;
1134 	t_u8 peer_mac[ETH_ALEN] = {0};
1135 	mlan_status status = MLAN_STATUS_SUCCESS;
1136 
1137 	ENTER();
1138 
1139 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELBA);
1140 
1141 	if ((int)strlen(respbuf) == header_len) {
1142 		/* Incorrect number of arguments */
1143 		PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
1144 		ret = -EINVAL;
1145 		goto done;
1146 	}
1147 
1148 	mac_pos = strstr(respbuf + header_len, " ");
1149 	if (mac_pos)
1150 		mac_pos = strstr(mac_pos + 1, " ");
1151 	if (mac_pos) {
1152 #define MAC_STRING_LENGTH 17
1153 		if (strlen(mac_pos + 1) != MAC_STRING_LENGTH) {
1154 			PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
1155 			ret = -EINVAL;
1156 			goto done;
1157 		}
1158 		woal_mac2u8(peer_mac, mac_pos + 1);
1159 		*mac_pos = '\0';
1160 	}
1161 
1162 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
1163 			&user_data_len);
1164 
1165 	if (mac_pos)
1166 		user_data_len++;
1167 
1168 	if (user_data_len > 3 || (!(data[0] & (DELBA_TX | DELBA_RX))) ||
1169 	    (data[1] != DELBA_ALL_TIDS && !(data[1] <= 7))) {
1170 		/* Incorrect number of arguments */
1171 		PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
1172 		ret = -EINVAL;
1173 		goto done;
1174 	}
1175 
1176 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1177 	if (req == NULL) {
1178 		ret = -ENOMEM;
1179 		goto done;
1180 	}
1181 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1182 	req->req_id = MLAN_IOCTL_11N_CFG;
1183 	cfg_11n->sub_command = MLAN_OID_11N_CFG_DELBA;
1184 
1185 	del_ba = &cfg_11n->param.del_ba;
1186 	memset(del_ba, 0, sizeof(mlan_ds_11n_delba));
1187 	del_ba->direction = (t_u8)data[0];
1188 	del_ba->tid = DELBA_ALL_TIDS;
1189 	if (user_data_len > 1)
1190 		del_ba->tid = (t_u8)data[1];
1191 	if (user_data_len > 2)
1192 		moal_memcpy_ext(priv->phandle, del_ba->peer_mac_addr, peer_mac,
1193 				ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
1194 
1195 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1196 
1197 	if (status != MLAN_STATUS_SUCCESS) {
1198 		ret = -EFAULT;
1199 		goto done;
1200 	}
1201 
1202 	ret = sprintf(respbuf, "OK. BA deleted successfully.\n") + 1;
1203 
1204 done:
1205 	if (status != MLAN_STATUS_PENDING)
1206 		kfree(req);
1207 	LEAVE();
1208 	return ret;
1209 }
1210 
1211 /**
1212  *  @brief Set/Get the reject addba requst conditions
1213  *
1214  *  @param priv         A pointer to moal_private structure
1215  *  @param respbuf      A pointer to response buffer
1216  *  @param respbuflen   Available length of response buffer
1217  *
1218  *  @return             Number of bytes written, negative for failure.
1219  */
woal_priv_rejectaddbareq(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1220 static int woal_priv_rejectaddbareq(moal_private *priv, t_u8 *respbuf,
1221 				    t_u32 respbuflen)
1222 {
1223 	t_u32 data[1];
1224 	mlan_ioctl_req *req = NULL;
1225 	mlan_ds_11n_cfg *cfg_11n = NULL;
1226 	int ret = 0;
1227 	int user_data_len = 0;
1228 	mlan_status status = MLAN_STATUS_SUCCESS;
1229 
1230 	ENTER();
1231 
1232 	if (strlen(respbuf) ==
1233 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_REJECTADDBAREQ))) {
1234 		/* GET operation */
1235 		user_data_len = 0;
1236 	} else {
1237 		/* SET operation */
1238 		memset((char *)data, 0, sizeof(data));
1239 		parse_arguments(respbuf + strlen(CMD_NXP) +
1240 					strlen(PRIV_CMD_REJECTADDBAREQ),
1241 				data, ARRAY_SIZE(data), &user_data_len);
1242 	}
1243 
1244 	if (user_data_len > 1) {
1245 		PRINTM(MERROR, "Too many arguments\n");
1246 		ret = -EINVAL;
1247 		goto done;
1248 	}
1249 
1250 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1251 	if (req == NULL) {
1252 		ret = -ENOMEM;
1253 		goto done;
1254 	}
1255 
1256 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1257 	cfg_11n->sub_command = MLAN_OID_11N_CFG_REJECT_ADDBA_REQ;
1258 	req->req_id = MLAN_IOCTL_11N_CFG;
1259 
1260 	if (user_data_len == 0) {
1261 		/* Get the reject addba req conditions*/
1262 		req->action = MLAN_ACT_GET;
1263 	} else {
1264 		/* Set the reject addba req conditions */
1265 		cfg_11n->param.reject_addba_req.conditions = data[0];
1266 		req->action = MLAN_ACT_SET;
1267 	}
1268 
1269 	/* Send IOCTL request to MLAN */
1270 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1271 	if (status != MLAN_STATUS_SUCCESS) {
1272 		ret = -EFAULT;
1273 		goto done;
1274 	}
1275 	if (req->action == MLAN_ACT_GET) {
1276 		sprintf(respbuf, "0x%x",
1277 			cfg_11n->param.reject_addba_req.conditions);
1278 		ret = strlen(respbuf) + 1;
1279 	} else {
1280 		ret = sprintf(respbuf, "OK\n") + 1;
1281 	}
1282 
1283 done:
1284 	if (status != MLAN_STATUS_PENDING)
1285 		kfree(req);
1286 	LEAVE();
1287 	return ret;
1288 }
1289 
1290 /**
1291  *  @brief Set/Get the addba reject setting
1292  *
1293  *  @param priv         A pointer to moal_private structure
1294  *  @param action       Action set or get
1295  *  @param addba_reject A pointer to addba_reject array.
1296  *
1297  *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
1298  * otherwise fail
1299  */
woal_ioctl_addba_reject(moal_private * priv,t_u32 action,t_u8 * addba_reject)1300 static mlan_status woal_ioctl_addba_reject(moal_private *priv, t_u32 action,
1301 					   t_u8 *addba_reject)
1302 {
1303 	mlan_ioctl_req *req = NULL;
1304 	mlan_ds_11n_cfg *cfg_11n = NULL;
1305 	mlan_status ret = MLAN_STATUS_SUCCESS;
1306 
1307 	ENTER();
1308 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1309 	if (req == NULL) {
1310 		ret = -ENOMEM;
1311 		goto done;
1312 	}
1313 
1314 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1315 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
1316 	req->req_id = MLAN_IOCTL_11N_CFG;
1317 
1318 	req->action = action;
1319 	if (action == MLAN_ACT_SET)
1320 		moal_memcpy_ext(priv->phandle, cfg_11n->param.addba_reject,
1321 				addba_reject,
1322 				sizeof(cfg_11n->param.addba_reject),
1323 				sizeof(cfg_11n->param.addba_reject));
1324 	/* Send IOCTL request to MLAN */
1325 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1326 	if (ret != MLAN_STATUS_SUCCESS)
1327 		goto done;
1328 	if (action == MLAN_ACT_GET)
1329 		moal_memcpy_ext(priv->phandle, addba_reject,
1330 				cfg_11n->param.addba_reject,
1331 				sizeof(cfg_11n->param.addba_reject),
1332 				MAX_NUM_TID);
1333 done:
1334 	if (ret != MLAN_STATUS_PENDING)
1335 		kfree(req);
1336 	LEAVE();
1337 	return ret;
1338 }
1339 
1340 /**
1341  *  @brief Set/Get addba prio_tbl
1342  *
1343  *  @param priv         A pointer to moal_private structure
1344  *  @param action       Action set or get
1345  *  @param aggr_prio_tbl  A pointer to mlan_ds_11n_aggr_prio_tbl.
1346  *
1347  *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
1348  * otherwise fail
1349  */
woal_ioctl_aggr_prio_tbl(moal_private * priv,t_u32 action,mlan_ds_11n_aggr_prio_tbl * aggr_prio_tbl)1350 mlan_status woal_ioctl_aggr_prio_tbl(moal_private *priv, t_u32 action,
1351 				     mlan_ds_11n_aggr_prio_tbl *aggr_prio_tbl)
1352 {
1353 	mlan_ioctl_req *req = NULL;
1354 	mlan_ds_11n_cfg *cfg_11n = NULL;
1355 	mlan_status ret = MLAN_STATUS_SUCCESS;
1356 
1357 	ENTER();
1358 
1359 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1360 	if (req == NULL) {
1361 		ret = -ENOMEM;
1362 		goto done;
1363 	}
1364 
1365 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1366 	cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
1367 	req->req_id = MLAN_IOCTL_11N_CFG;
1368 
1369 	req->action = action;
1370 	if (action == MLAN_ACT_SET)
1371 		moal_memcpy_ext(priv->phandle, &cfg_11n->param.aggr_prio_tbl,
1372 				aggr_prio_tbl,
1373 				sizeof(mlan_ds_11n_aggr_prio_tbl),
1374 				sizeof(mlan_ds_11n_aggr_prio_tbl));
1375 	/* Send IOCTL request to MLAN */
1376 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1377 	if (ret != MLAN_STATUS_SUCCESS)
1378 		goto done;
1379 	if (action == MLAN_ACT_GET)
1380 		moal_memcpy_ext(priv->phandle, aggr_prio_tbl,
1381 				&cfg_11n->param.aggr_prio_tbl,
1382 				sizeof(mlan_ds_11n_aggr_prio_tbl),
1383 				sizeof(mlan_ds_11n_aggr_prio_tbl));
1384 done:
1385 	if (ret != MLAN_STATUS_PENDING)
1386 		kfree(req);
1387 	LEAVE();
1388 	return ret;
1389 }
1390 
1391 /**
1392  *  @brief Set/Get addba_param
1393  *
1394  *  @param priv         A pointer to moal_private structure
1395  *  @param action       Action set or get
1396  *  @param addba_param  A pointer to mlan_ds_11n_addba_param.
1397  *
1398  *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
1399  * otherwise fail
1400  */
woal_ioctl_addba_param(moal_private * priv,t_u32 action,mlan_ds_11n_addba_param * addba_param)1401 static mlan_status woal_ioctl_addba_param(moal_private *priv, t_u32 action,
1402 					  mlan_ds_11n_addba_param *addba_param)
1403 {
1404 	mlan_ioctl_req *req = NULL;
1405 	mlan_ds_11n_cfg *cfg_11n = NULL;
1406 	mlan_status ret = MLAN_STATUS_SUCCESS;
1407 
1408 	ENTER();
1409 
1410 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1411 	if (req == NULL) {
1412 		ret = -ENOMEM;
1413 		goto done;
1414 	}
1415 
1416 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1417 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
1418 	req->req_id = MLAN_IOCTL_11N_CFG;
1419 
1420 	req->action = action;
1421 	if (action == MLAN_ACT_SET)
1422 		moal_memcpy_ext(priv->phandle, &cfg_11n->param.addba_param,
1423 				addba_param, sizeof(mlan_ds_11n_addba_param),
1424 				sizeof(mlan_ds_11n_addba_param));
1425 	/* Send IOCTL request to MLAN */
1426 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1427 	if (ret != MLAN_STATUS_SUCCESS)
1428 		goto done;
1429 	if (action == MLAN_ACT_GET)
1430 		moal_memcpy_ext(priv->phandle, addba_param,
1431 				&cfg_11n->param.addba_param,
1432 				sizeof(mlan_ds_11n_addba_param),
1433 				sizeof(mlan_ds_11n_addba_param));
1434 done:
1435 	if (ret != MLAN_STATUS_PENDING)
1436 		kfree(req);
1437 	LEAVE();
1438 	return ret;
1439 }
1440 
1441 /**
1442  *   @brief Configuring rx block-ack window size
1443  *
1444  *  @param priv         A pointer to moal_private structure
1445  *  @param respbuf      A pointer to response buffer
1446  *  @param respbuflen   Available length of response buffer
1447  *
1448  *  @return             0 --success, otherwise failure
1449  */
woal_set_rx_ba_winsize(moal_private * priv,t_u8 * respbuf,int respbuflen)1450 static int woal_set_rx_ba_winsize(moal_private *priv, t_u8 *respbuf,
1451 				  int respbuflen)
1452 {
1453 	int data[2];
1454 	t_u8 addba_reject[MAX_NUM_TID];
1455 	mlan_ds_11n_addba_param addba_param;
1456 	int ret = 0;
1457 	int user_data_len = 0;
1458 
1459 	ENTER();
1460 
1461 	memset((char *)data, 0, sizeof(data));
1462 	if (respbuf && strlen(respbuf) > 0)
1463 		parse_arguments(respbuf, data, ARRAY_SIZE(data),
1464 				&user_data_len);
1465 
1466 	if (user_data_len != 2) {
1467 		PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
1468 		ret = -EINVAL;
1469 		goto done;
1470 	}
1471 	if (data[0] > 7 || data[0] < 0) {
1472 		PRINTM(MERROR, "Invalid tid %d\n", data[0]);
1473 		ret = -EINVAL;
1474 		goto done;
1475 	}
1476 	if (data[1] < 0) {
1477 		PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
1478 		ret = -EINVAL;
1479 		goto done;
1480 	}
1481 	memset(addba_reject, 0, sizeof(addba_reject));
1482 	if (MLAN_STATUS_SUCCESS !=
1483 	    woal_ioctl_addba_reject(priv, MLAN_ACT_GET, addba_reject)) {
1484 		ret = -EFAULT;
1485 		goto done;
1486 	}
1487 	/* disable tx ba */
1488 	if (data[1] == 0) {
1489 		addba_reject[data[0]] = MTRUE;
1490 		if (MLAN_STATUS_SUCCESS !=
1491 		    woal_ioctl_addba_reject(priv, MLAN_ACT_SET, addba_reject))
1492 			ret = -EFAULT;
1493 	} else {
1494 		if (addba_reject[data[0]] == MTRUE) {
1495 			addba_reject[data[0]] = MFALSE;
1496 			if (MLAN_STATUS_SUCCESS !=
1497 			    woal_ioctl_addba_reject(priv, MLAN_ACT_SET,
1498 						    addba_reject)) {
1499 				ret = -EFAULT;
1500 				goto done;
1501 			}
1502 		}
1503 		memset(&addba_param, 0, sizeof(addba_param));
1504 		if (MLAN_STATUS_SUCCESS !=
1505 		    woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
1506 			ret = -EFAULT;
1507 			goto done;
1508 		}
1509 		if (data[1] != (int)addba_param.rxwinsize) {
1510 			addba_param.rxwinsize = data[1];
1511 			if (MLAN_STATUS_SUCCESS !=
1512 			    woal_ioctl_addba_param(priv, MLAN_ACT_SET,
1513 						   &addba_param))
1514 				ret = -EFAULT;
1515 		}
1516 	}
1517 done:
1518 	LEAVE();
1519 	return ret;
1520 }
1521 /**
1522  *   @brief Configuring trx block-ack window size
1523  *
1524  *  @param priv         A pointer to moal_private structure
1525  *  @param respbuf      A pointer to response buffer
1526  *  @param respbuflen   Available length of response buffer
1527  *
1528  *  @return             0 --success, otherwise failure
1529  */
woal_set_tx_ba_winsize(moal_private * priv,t_u8 * respbuf,int respbuflen)1530 static int woal_set_tx_ba_winsize(moal_private *priv, t_u8 *respbuf,
1531 				  int respbuflen)
1532 {
1533 	int data[2];
1534 	mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
1535 	mlan_ds_11n_addba_param addba_param;
1536 	t_u8 tos_to_tid_inv[] = {0x02, 0x00, 0x01, 0x03,
1537 				 0x04, 0x05, 0x06, 0x07};
1538 	int ret = 0;
1539 	int user_data_len = 0;
1540 
1541 	ENTER();
1542 
1543 	memset((char *)data, 0, sizeof(data));
1544 	if (respbuf && strlen(respbuf) > 0)
1545 		parse_arguments(respbuf, data, ARRAY_SIZE(data),
1546 				&user_data_len);
1547 
1548 	if (user_data_len != 2) {
1549 		PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
1550 		ret = -EINVAL;
1551 		goto done;
1552 	}
1553 	if (data[0] > 7 || data[0] < 0) {
1554 		PRINTM(MERROR, "Invalid tid %d\n", data[0]);
1555 		ret = -EINVAL;
1556 		goto done;
1557 	}
1558 	if (data[1] < 0) {
1559 		PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
1560 		ret = -EINVAL;
1561 		goto done;
1562 	}
1563 	memset(&aggr_prio_tbl, 0, sizeof(aggr_prio_tbl));
1564 	if (MLAN_STATUS_SUCCESS !=
1565 	    woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_GET, &aggr_prio_tbl)) {
1566 		ret = -EFAULT;
1567 		goto done;
1568 	}
1569 	/* disable tx ba */
1570 	if (data[1] == 0) {
1571 		if (aggr_prio_tbl.ampdu[data[0]] != 0xff) {
1572 			aggr_prio_tbl.ampdu[data[0]] = 0xff;
1573 			if (MLAN_STATUS_SUCCESS !=
1574 			    woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
1575 						     &aggr_prio_tbl))
1576 				ret = -EFAULT;
1577 		}
1578 	} else {
1579 		if (aggr_prio_tbl.ampdu[data[0]] == 0xff) {
1580 			aggr_prio_tbl.ampdu[data[0]] = tos_to_tid_inv[data[0]];
1581 			if (MLAN_STATUS_SUCCESS !=
1582 			    woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
1583 						     &aggr_prio_tbl)) {
1584 				ret = -EFAULT;
1585 				goto done;
1586 			}
1587 		}
1588 		memset(&addba_param, 0, sizeof(addba_param));
1589 		if (MLAN_STATUS_SUCCESS !=
1590 		    woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
1591 			ret = -EFAULT;
1592 			goto done;
1593 		}
1594 		if (data[1] != (int)addba_param.txwinsize) {
1595 			addba_param.txwinsize = data[1];
1596 			if (MLAN_STATUS_SUCCESS !=
1597 			    woal_ioctl_addba_param(priv, MLAN_ACT_SET,
1598 						   &addba_param))
1599 				ret = -EFAULT;
1600 		}
1601 	}
1602 done:
1603 	LEAVE();
1604 	return ret;
1605 }
1606 
1607 /**
1608  *  @brief Set/Get aggregation priority table configurations
1609  *
1610  *  @param priv         A pointer to moal_private structure
1611  *  @param respbuf      A pointer to response buffer
1612  *  @param respbuflen   Available length of response buffer
1613  *
1614  *  @return             Number of bytes written, negative for failure.
1615  */
woal_setget_priv_aggrpriotbl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1616 static int woal_setget_priv_aggrpriotbl(moal_private *priv, t_u8 *respbuf,
1617 					t_u32 respbuflen)
1618 {
1619 	int data[MAX_NUM_TID * 2], i, j;
1620 	mlan_ioctl_req *req = NULL;
1621 	mlan_ds_11n_cfg *cfg_11n = NULL;
1622 	int ret = 0;
1623 	int user_data_len = 0;
1624 	mlan_status status = MLAN_STATUS_SUCCESS;
1625 
1626 	ENTER();
1627 
1628 	if (strlen(respbuf) ==
1629 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRPRIOTBL))) {
1630 		/* GET operation */
1631 		user_data_len = 0;
1632 	} else {
1633 		/* SET operation */
1634 		memset((char *)data, 0, sizeof(data));
1635 		parse_arguments(respbuf + strlen(CMD_NXP) +
1636 					strlen(PRIV_CMD_AGGRPRIOTBL),
1637 				data, ARRAY_SIZE(data), &user_data_len);
1638 
1639 		if (user_data_len != ARRAY_SIZE(data)) {
1640 			PRINTM(MERROR, "Invalid number of arguments\n");
1641 			ret = -EINVAL;
1642 			goto done;
1643 		}
1644 		for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
1645 			if ((data[i] > 7 && data[i] != 0xff) ||
1646 			    (data[i + 1] > 7 && data[i + 1] != 0xff)) {
1647 				PRINTM(MERROR,
1648 				       "Invalid priority, valid value 0-7 or 0xff.\n");
1649 				ret = -EFAULT;
1650 				goto done;
1651 			}
1652 		}
1653 	}
1654 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1655 	if (req == NULL) {
1656 		ret = -ENOMEM;
1657 		goto done;
1658 	}
1659 
1660 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1661 	cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
1662 	req->req_id = MLAN_IOCTL_11N_CFG;
1663 
1664 	if (user_data_len == 0) {
1665 		/* Get aggr priority table from MLAN */
1666 		req->action = MLAN_ACT_GET;
1667 	} else {
1668 		for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
1669 			cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
1670 			cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
1671 		}
1672 		/* Update aggr priority table in MLAN */
1673 		req->action = MLAN_ACT_SET;
1674 	}
1675 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1676 	if (status != MLAN_STATUS_SUCCESS) {
1677 		ret = -EFAULT;
1678 		goto done;
1679 	}
1680 
1681 	for (i = 0, j = 0; i < (MAX_NUM_TID * 2); i = i + 2, ++j) {
1682 		respbuf[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
1683 		respbuf[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
1684 	}
1685 
1686 	ret = sizeof(data);
1687 
1688 done:
1689 	if (status != MLAN_STATUS_PENDING)
1690 		kfree(req);
1691 	LEAVE();
1692 	return ret;
1693 }
1694 
1695 /**
1696  *  @brief Set/Get Add BA reject configurations
1697  *
1698  *  @param priv         A pointer to moal_private structure
1699  *  @param respbuf      A pointer to response buffer
1700  *  @param respbuflen   Available length of response buffer
1701  *
1702  *  @return             Number of bytes written, negative for failure.
1703  */
woal_setget_priv_addbareject(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1704 static int woal_setget_priv_addbareject(moal_private *priv, t_u8 *respbuf,
1705 					t_u32 respbuflen)
1706 {
1707 	int data[MAX_NUM_TID], i;
1708 	mlan_ioctl_req *req = NULL;
1709 	mlan_ds_11n_cfg *cfg_11n = NULL;
1710 	int ret = 0;
1711 	int user_data_len = 0;
1712 	mlan_status status = MLAN_STATUS_SUCCESS;
1713 
1714 	ENTER();
1715 
1716 	if (strlen(respbuf) ==
1717 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAREJECT))) {
1718 		/* GET operation */
1719 		user_data_len = 0;
1720 	} else {
1721 		/* SET operation */
1722 		memset((char *)data, 0, sizeof(data));
1723 		parse_arguments(respbuf + strlen(CMD_NXP) +
1724 					strlen(PRIV_CMD_ADDBAREJECT),
1725 				data, ARRAY_SIZE(data), &user_data_len);
1726 
1727 		if (user_data_len != ARRAY_SIZE(data)) {
1728 			PRINTM(MERROR, "Invalid number of arguments\n");
1729 			ret = -EINVAL;
1730 			goto done;
1731 		}
1732 		for (i = 0; i < user_data_len; i++) {
1733 			if (data[i] != 0 && data[i] != 1) {
1734 				PRINTM(MERROR,
1735 				       "addba reject only takes argument as 0 or 1\n");
1736 				ret = -EFAULT;
1737 				goto done;
1738 			}
1739 		}
1740 	}
1741 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1742 	if (req == NULL) {
1743 		ret = -ENOMEM;
1744 		goto done;
1745 	}
1746 
1747 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1748 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
1749 	req->req_id = MLAN_IOCTL_11N_CFG;
1750 
1751 	if (user_data_len == 0) {
1752 		/* Get add BA reject configuration from MLAN */
1753 		req->action = MLAN_ACT_GET;
1754 	} else {
1755 		for (i = 0; i < user_data_len; i++)
1756 			cfg_11n->param.addba_reject[i] = data[i];
1757 		/* Update add BA reject configuration in MLAN */
1758 		req->action = MLAN_ACT_SET;
1759 	}
1760 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1761 	if (status != MLAN_STATUS_SUCCESS) {
1762 		ret = -EFAULT;
1763 		goto done;
1764 	}
1765 
1766 	for (i = 0; i < MAX_NUM_TID; i++)
1767 		respbuf[i] = cfg_11n->param.addba_reject[i];
1768 
1769 	ret = sizeof(data);
1770 
1771 done:
1772 	if (status != MLAN_STATUS_PENDING)
1773 		kfree(req);
1774 	LEAVE();
1775 	return ret;
1776 }
1777 
1778 /**
1779  *  @brief Set/Get 11AC configurations
1780  *
1781  *  @param priv         A pointer to moal_private structure
1782  *  @param respbuf      A pointer to response buffer
1783  *  @param respbuflen   Available length of response buffer
1784  *
1785  *  @return             Number of bytes written, negative for failure.
1786  */
woal_setget_priv_vhtcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1787 static int woal_setget_priv_vhtcfg(moal_private *priv, t_u8 *respbuf,
1788 				   t_u32 respbuflen)
1789 {
1790 	int data[6];
1791 	mlan_ioctl_req *req = NULL;
1792 	mlan_ds_11ac_cfg *cfg_11ac = NULL;
1793 	mlan_ds_11ac_vht_cfg *vhtcfg = NULL;
1794 	int ret = 0;
1795 	int user_data_len = 0;
1796 	mlan_status status = MLAN_STATUS_SUCCESS;
1797 
1798 	ENTER();
1799 
1800 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG))) {
1801 		PRINTM(MERROR, "Invalid number of arguments\n");
1802 		ret = -EINVAL;
1803 		goto done;
1804 	}
1805 	memset((char *)data, 0, sizeof(data));
1806 	parse_arguments(respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG),
1807 			data, ARRAY_SIZE(data), &user_data_len);
1808 
1809 	if ((user_data_len > 6) || (user_data_len < 2)) {
1810 		PRINTM(MERROR, "Invalid number of arguments\n");
1811 		ret = -EINVAL;
1812 		goto done;
1813 	}
1814 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
1815 	if (req == NULL) {
1816 		ret = -ENOMEM;
1817 		goto done;
1818 	}
1819 
1820 	cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
1821 	cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
1822 	req->req_id = MLAN_IOCTL_11AC_CFG;
1823 
1824 	/* Band */
1825 	if ((data[0] < 0) || (data[0] > 2)) {
1826 		PRINTM(MERROR, "Invalid band selection\n");
1827 		ret = -EINVAL;
1828 		goto done;
1829 	} else {
1830 		if (data[0] == BAND_SELECT_BOTH) {
1831 			cfg_11ac->param.vht_cfg.band =
1832 				(BAND_SELECT_BG | BAND_SELECT_A);
1833 		} else {
1834 			cfg_11ac->param.vht_cfg.band = data[0];
1835 		}
1836 		PRINTM(MINFO, "GET/SET: vhtcfg band: 0x%x\n", data[0]);
1837 	}
1838 
1839 	/* Tx/Rx */
1840 	if ((data[1] <= 0) || (data[1] > 3)) {
1841 		PRINTM(MERROR, "Invalid Tx/Rx selection\n");
1842 		ret = -EINVAL;
1843 		goto done;
1844 	} else {
1845 		cfg_11ac->param.vht_cfg.txrx = data[1];
1846 		PRINTM(MINFO, "GET/SET: vhtcfg txrx: 0x%x\n", data[1]);
1847 	}
1848 
1849 	if (user_data_len == 2) {
1850 		/* GET operation */
1851 		if (data[0] == BAND_SELECT_BOTH) {
1852 			/* if get both bands, get BG first */
1853 			cfg_11ac->param.vht_cfg.band = BAND_SELECT_BG;
1854 		}
1855 		if (priv->bss_role == MLAN_BSS_ROLE_UAP)
1856 			cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;
1857 
1858 		req->action = MLAN_ACT_GET;
1859 	} else {
1860 		if (user_data_len == 3) {
1861 			PRINTM(MERROR, "Invalid number of arguments\n");
1862 			ret = -EINVAL;
1863 			goto done;
1864 		}
1865 		if (user_data_len >= 4) {
1866 			/* BW cfg */
1867 			if ((data[2] < 0) || (data[2] > 1) ||
1868 			    ((data[2] == 1) && (data[0] & BAND_SELECT_BG))) {
1869 				PRINTM(MERROR, "Invalid BW cfg selection\n");
1870 				ret = -EINVAL;
1871 				goto done;
1872 			} else {
1873 				cfg_11ac->param.vht_cfg.bwcfg = data[2];
1874 				PRINTM(MINFO, "SET: vhtcfg bw cfg:0x%x\n",
1875 				       data[2]);
1876 			}
1877 
1878 			cfg_11ac->param.vht_cfg.vht_cap_info = data[3];
1879 			PRINTM(MINFO, "SET: vhtcfg vht_cap_info:0x%x\n",
1880 			       data[3]);
1881 		}
1882 		if (user_data_len == 4) {
1883 			data[4] = 0xffffffff;
1884 			data[5] = 0xffffffff;
1885 		}
1886 		if (user_data_len == 5) {
1887 			PRINTM(MERROR, "Invalid number of arguments\n");
1888 			ret = -EINVAL;
1889 			goto done;
1890 		}
1891 		if (user_data_len >= 4) {
1892 			cfg_11ac->param.vht_cfg.vht_tx_mcs = data[4];
1893 			cfg_11ac->param.vht_cfg.vht_rx_mcs = data[5];
1894 		}
1895 		/* Update 11AC parameters in MLAN */
1896 		req->action = MLAN_ACT_SET;
1897 	}
1898 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1899 	if (status != MLAN_STATUS_SUCCESS) {
1900 		ret = -EFAULT;
1901 		goto done;
1902 	}
1903 
1904 	/* number of vhtcfg entries */
1905 	*respbuf = 1;
1906 	vhtcfg = (mlan_ds_11ac_vht_cfg *)(respbuf + 1);
1907 	moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
1908 			sizeof(mlan_ds_11ac_vht_cfg), respbuflen - 1);
1909 	ret = 1 + sizeof(mlan_ds_11ac_vht_cfg);
1910 
1911 	if ((req->action == MLAN_ACT_GET) && (data[0] == BAND_SELECT_BOTH)) {
1912 		cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
1913 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1914 		if (status != MLAN_STATUS_SUCCESS) {
1915 			ret = -EFAULT;
1916 			goto done;
1917 		}
1918 		/* number of vhtcfg entries */
1919 		*respbuf = 2;
1920 		vhtcfg++;
1921 		moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
1922 				sizeof(mlan_ds_11ac_vht_cfg),
1923 				respbuflen - 1 - sizeof(mlan_ds_11ac_vht_cfg));
1924 		ret += sizeof(mlan_ds_11ac_vht_cfg);
1925 	}
1926 
1927 done:
1928 	if (status != MLAN_STATUS_PENDING)
1929 		kfree(req);
1930 	LEAVE();
1931 	return ret;
1932 }
1933 
1934 /**
1935  *  @brief Set/Get 11AC Operating Mode Notification configurations
1936  *
1937  *  @param priv         A pointer to moal_private structure
1938  *  @param respbuf      A pointer to response buffer
1939  *  @param respbuflen   Available length of response buffer
1940  *
1941  *  @return             Number of bytes written, negative for failure.
1942  */
woal_setget_priv_opermodecfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1943 static int woal_setget_priv_opermodecfg(moal_private *priv, t_u8 *respbuf,
1944 					t_u32 respbuflen)
1945 {
1946 	int data[2];
1947 	mlan_ioctl_req *req = NULL;
1948 	mlan_ds_11ac_cfg *cfg_11ac = NULL;
1949 	mlan_ds_11ac_opermode_cfg *opermodecfg = NULL;
1950 	int ret = 0;
1951 	int user_data_len = 0;
1952 	mlan_status status = MLAN_STATUS_SUCCESS;
1953 
1954 	ENTER();
1955 
1956 	memset((char *)data, 0, sizeof(data));
1957 	parse_arguments(respbuf + strlen(CMD_NXP) +
1958 				strlen(PRIV_CMD_OPERMODECFG),
1959 			data, ARRAY_SIZE(data), &user_data_len);
1960 
1961 	if ((user_data_len != 0) && (user_data_len != 2)) {
1962 		PRINTM(MERROR, "Invalid number of arguments\n");
1963 		ret = -EINVAL;
1964 		goto done;
1965 	}
1966 	if (user_data_len == 2) {
1967 		/* Channel width */
1968 		if ((data[0] < 1) || (data[0] > 4)) {
1969 			PRINTM(MERROR, "Invalid channel width: 0x%x\n",
1970 			       data[0]);
1971 			ret = -EINVAL;
1972 			goto done;
1973 		}
1974 		/* nss */
1975 		if ((data[1] < 1) || (data[1] > 8)) {
1976 			PRINTM(MERROR, "Invalid nss: 0x%x\n", data[1]);
1977 			ret = -EINVAL;
1978 			goto done;
1979 		}
1980 	}
1981 
1982 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
1983 	if (req == NULL) {
1984 		ret = -ENOMEM;
1985 		goto done;
1986 	}
1987 
1988 	cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
1989 	cfg_11ac->sub_command = MLAN_OID_11AC_OPERMODE_CFG;
1990 	req->req_id = MLAN_IOCTL_11AC_CFG;
1991 
1992 	if (user_data_len == 0) {
1993 		req->action = MLAN_ACT_GET;
1994 	} else {
1995 		req->action = MLAN_ACT_SET;
1996 		cfg_11ac->param.opermode_cfg.bw = data[0];
1997 		cfg_11ac->param.opermode_cfg.nss = data[1];
1998 	}
1999 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2000 	if (status != MLAN_STATUS_SUCCESS) {
2001 		ret = -EFAULT;
2002 		goto done;
2003 	}
2004 	opermodecfg = (mlan_ds_11ac_opermode_cfg *)respbuf;
2005 	moal_memcpy_ext(priv->phandle, opermodecfg,
2006 			&(cfg_11ac->param.opermode_cfg), sizeof(*opermodecfg),
2007 			respbuflen);
2008 	ret = sizeof(*opermodecfg);
2009 
2010 done:
2011 	if (status != MLAN_STATUS_PENDING)
2012 		kfree(req);
2013 	LEAVE();
2014 	return ret;
2015 }
2016 
2017 /**
2018  *  @brief Set/Get 11AC configurations
2019  *
2020  *  @param priv         A pointer to moal_private structure
2021  *  @param respbuf      A pointer to response buffer
2022  *  @param respbuflen   Available length of response buffer
2023  *
2024  *  @return             Number of bytes written, negative for failure.
2025  */
woal_get_priv_datarate(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2026 static int woal_get_priv_datarate(moal_private *priv, t_u8 *respbuf,
2027 				  t_u32 respbuflen)
2028 {
2029 	mlan_ioctl_req *req = NULL;
2030 	mlan_ds_rate *rate = NULL;
2031 	mlan_data_rate *data_rate = NULL;
2032 	int ret = 0;
2033 	mlan_status status = MLAN_STATUS_SUCCESS;
2034 
2035 	ENTER();
2036 
2037 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2038 	if (req == NULL) {
2039 		ret = -ENOMEM;
2040 		goto done;
2041 	}
2042 
2043 	rate = (mlan_ds_rate *)req->pbuf;
2044 	rate->sub_command = MLAN_OID_GET_DATA_RATE;
2045 	req->req_id = MLAN_IOCTL_RATE;
2046 	req->action = MLAN_ACT_GET;
2047 
2048 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2049 	if (status != MLAN_STATUS_SUCCESS) {
2050 		ret = -EFAULT;
2051 		goto done;
2052 	}
2053 
2054 	data_rate = (mlan_data_rate *)respbuf;
2055 
2056 	moal_memcpy_ext(priv->phandle, data_rate, &rate->param.data_rate,
2057 			sizeof(mlan_data_rate), respbuflen);
2058 
2059 	ret = sizeof(mlan_data_rate);
2060 
2061 done:
2062 	if (status != MLAN_STATUS_PENDING)
2063 		kfree(req);
2064 	LEAVE();
2065 	return ret;
2066 }
2067 
2068 /**
2069  *  @brief Set/Get tx rate configurations
2070  *
2071  *  @param priv         A pointer to moal_private structure
2072  *  @param respbuf      A pointer to response buffer
2073  *  @param respbuflen   Available length of response buffer
2074  *
2075  *  @return             Number of bytes written, negative for failure.
2076  */
woal_setget_priv_txratecfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2077 static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf,
2078 				      t_u32 respbuflen)
2079 {
2080 	t_u32 data[4];
2081 	mlan_ioctl_req *req = NULL;
2082 	mlan_ds_rate *rate = NULL;
2083 	woal_tx_rate_cfg *ratecfg = NULL;
2084 	int ret = 0;
2085 	int user_data_len = 0;
2086 	mlan_status status = MLAN_STATUS_SUCCESS;
2087 	txrate_setting *rate_setting = NULL;
2088 
2089 	ENTER();
2090 
2091 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TXRATECFG))) {
2092 		/* GET operation */
2093 		user_data_len = 0;
2094 	} else {
2095 		/* SET operation */
2096 		memset((char *)data, 0, sizeof(data));
2097 		parse_arguments(respbuf + strlen(CMD_NXP) +
2098 					strlen(PRIV_CMD_TXRATECFG),
2099 				data, ARRAY_SIZE(data), &user_data_len);
2100 	}
2101 
2102 	if (user_data_len > 4) {
2103 		PRINTM(MERROR, "Too many arguments\n");
2104 		ret = -EINVAL;
2105 		goto done;
2106 	}
2107 
2108 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2109 	if (req == NULL) {
2110 		ret = -ENOMEM;
2111 		goto done;
2112 	}
2113 
2114 	req->req_id = MLAN_IOCTL_RATE;
2115 	rate = (mlan_ds_rate *)req->pbuf;
2116 	rate->sub_command = MLAN_OID_RATE_CFG;
2117 	rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
2118 
2119 	if (user_data_len == 0) {
2120 		/* Get operation */
2121 		req->action = MLAN_ACT_GET;
2122 	} else {
2123 		/* Set operation */
2124 		req->action = MLAN_ACT_SET;
2125 		/* format */
2126 		if ((data[0] != AUTO_RATE) && (data[0] >= 4)) {
2127 			PRINTM(MERROR, "Invalid format selection\n");
2128 			ret = -EINVAL;
2129 			goto done;
2130 		}
2131 		if (data[0] == AUTO_RATE) {
2132 			/* auto */
2133 			rate->param.rate_cfg.is_rate_auto = 1;
2134 		} else {
2135 			/* fixed rate */
2136 			PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]);
2137 			if ((data[0] != AUTO_RATE) &&
2138 			    (data[0] > MLAN_RATE_FORMAT_HE)) {
2139 				PRINTM(MERROR, "Invalid format selection\n");
2140 				ret = -EINVAL;
2141 				goto done;
2142 			}
2143 			rate->param.rate_cfg.rate_format = data[0];
2144 
2145 			if (user_data_len >= 2) {
2146 				PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
2147 				       data[1]);
2148 				/* sanity check */
2149 				if (((data[0] == MLAN_RATE_FORMAT_LG) &&
2150 				     (data[1] > MLAN_RATE_INDEX_OFDM7)) ||
2151 				    ((data[0] == MLAN_RATE_FORMAT_HT) &&
2152 				     (data[1] != 32) && (data[1] > 15)) ||
2153 				    ((data[0] == MLAN_RATE_FORMAT_VHT) &&
2154 				     (data[1] > MLAN_RATE_INDEX_MCS9)) ||
2155 				    ((data[0] == MLAN_RATE_FORMAT_HE) &&
2156 				     (data[1] > MLAN_RATE_INDEX_MCS11))) {
2157 					PRINTM(MERROR,
2158 					       "Invalid index selection\n");
2159 					ret = -EINVAL;
2160 					goto done;
2161 				}
2162 
2163 				PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
2164 				       data[1]);
2165 				rate->param.rate_cfg.rate = data[1];
2166 			}
2167 
2168 			if (data[0] == 2 || data[0] == 3) {
2169 				PRINTM(MINFO, "SET: txratefg nss: 0x%x\n",
2170 				       data[2]);
2171 				/* NSS is supported up to 2 */
2172 				if ((data[2] <= 0) || (data[2] >= 3)) {
2173 					PRINTM(MERROR,
2174 					       "Invalid nss selection\n");
2175 					ret = -EINVAL;
2176 					goto done;
2177 				}
2178 				rate->param.rate_cfg.nss = data[2];
2179 			}
2180 			if (user_data_len == 4) {
2181 				rate->param.rate_cfg.rate_setting =
2182 					data[3] & ~0x0C00;
2183 				PRINTM(MIOCTL,
2184 				       "SET: txratefg HE Rate Setting: 0x%x\n",
2185 				       data[3]);
2186 
2187 /* HE Preamble type */
2188 //#define HE_SU_PREAMBLE 0
2189 #define HE_ER_PREAMBLE 1
2190 
2191 /* HE ER SU Type */
2192 #define HE_ER_SU_BANDWIDTH_TONE242 0
2193 #define HE_ER_SU_BANDWIDTH_TONE106 1
2194 
2195 				rate_setting = (txrate_setting *)&data[3];
2196 
2197 				if (data[0] == MLAN_RATE_FORMAT_HE) {
2198 					if (rate_setting->preamble ==
2199 					    HE_ER_PREAMBLE) {
2200 						if (rate_setting->bandwidth ==
2201 						    HE_ER_SU_BANDWIDTH_TONE242) {
2202 							if ((data[1] >
2203 							     MLAN_RATE_INDEX_MCS2) ||
2204 							    data[2] >
2205 								    MLAN_RATE_NSS1) {
2206 								PRINTM(MERROR,
2207 								       "Invalid rate and MCS or NSS configuration for 242 tone\n");
2208 								ret = -EINVAL;
2209 								goto done;
2210 							}
2211 						} else if (rate_setting
2212 								   ->bandwidth ==
2213 							   HE_ER_SU_BANDWIDTH_TONE106) {
2214 							if ((data[1] !=
2215 							     MLAN_RATE_INDEX_MCS0) ||
2216 							    data[2] !=
2217 								    MLAN_RATE_NSS1) {
2218 								PRINTM(MERROR,
2219 								       "Invalid rate and MCS or NSS configuration\n for 106 tone");
2220 								ret = -EINVAL;
2221 								goto done;
2222 							}
2223 						} else {
2224 							PRINTM(MERROR,
2225 							       "Invalid Bandwidth for HE ER Preamble\n");
2226 							ret = -EINVAL;
2227 							goto done;
2228 						}
2229 					}
2230 					if ((rate_setting->dcm) &&
2231 					    (rate_setting->stbc == 0)) {
2232 						if ((data[1] ==
2233 						     MLAN_RATE_INDEX_MCS2) ||
2234 						    (data[1] >
2235 						     MLAN_RATE_INDEX_MCS4)) {
2236 							PRINTM(MERROR,
2237 							       "Invalid MCS configuration if DCM is supported\n");
2238 							ret = -EINVAL;
2239 							goto done;
2240 						}
2241 					}
2242 				}
2243 			} else {
2244 				rate->param.rate_cfg.rate_setting = 0xffff;
2245 			}
2246 		}
2247 	}
2248 
2249 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2250 	if (status != MLAN_STATUS_SUCCESS) {
2251 		ret = -EFAULT;
2252 		goto done;
2253 	}
2254 
2255 	ratecfg = (woal_tx_rate_cfg *)respbuf;
2256 	if (rate->param.rate_cfg.is_rate_auto == MTRUE) {
2257 		ratecfg->rate_format = 0xFF;
2258 	} else {
2259 		/* fixed rate */
2260 		ratecfg->rate_format = rate->param.rate_cfg.rate_format;
2261 		ratecfg->rate_index = rate->param.rate_cfg.rate;
2262 		if (rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_VHT ||
2263 		    rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_HE)
2264 			ratecfg->nss = rate->param.rate_cfg.nss;
2265 		ratecfg->rate_setting = rate->param.rate_cfg.rate_setting;
2266 	}
2267 
2268 	ret = sizeof(woal_tx_rate_cfg);
2269 
2270 done:
2271 	if (status != MLAN_STATUS_PENDING)
2272 		kfree(req);
2273 	LEAVE();
2274 	return ret;
2275 }
2276 
2277 #if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
2278 /**
2279  *  @brief Get statistics information
2280  *
2281  *  @param priv         A pointer to moal_private structure
2282  *  @param wait_option  Wait option
2283  *  @param stats        A pointer to mlan_ds_get_stats structure
2284  *
2285  *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
2286  * otherwise fail
2287  */
woal_get_stats_info(moal_private * priv,t_u8 wait_option,mlan_ds_get_stats * stats)2288 mlan_status woal_get_stats_info(moal_private *priv, t_u8 wait_option,
2289 				mlan_ds_get_stats *stats)
2290 {
2291 	mlan_ds_get_info *info = NULL;
2292 	mlan_ioctl_req *req = NULL;
2293 	mlan_status status = MLAN_STATUS_SUCCESS;
2294 	ENTER();
2295 
2296 	/* Allocate an IOCTL request buffer */
2297 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
2298 	if (req == NULL) {
2299 		status = MLAN_STATUS_FAILURE;
2300 		goto done;
2301 	}
2302 
2303 	/* Fill request buffer */
2304 	info = (mlan_ds_get_info *)req->pbuf;
2305 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
2306 		info->sub_command = MLAN_OID_GET_STATS;
2307 	else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
2308 		info->sub_command = MLAN_OID_GET_UAP_STATS_LOG;
2309 	req->req_id = MLAN_IOCTL_GET_INFO;
2310 	req->action = MLAN_ACT_GET;
2311 
2312 	/* Send IOCTL request to MLAN */
2313 	status = woal_request_ioctl(priv, req, wait_option);
2314 	if (status == MLAN_STATUS_SUCCESS) {
2315 		if (stats)
2316 			moal_memcpy_ext(priv->phandle, stats,
2317 					&info->param.stats,
2318 					sizeof(mlan_ds_get_stats),
2319 					sizeof(mlan_ds_get_stats));
2320 #if defined(STA_WEXT) || defined(UAP_WEXT)
2321 		priv->w_stats.discard.fragment = info->param.stats.fcs_error;
2322 		priv->w_stats.discard.retries = info->param.stats.retry;
2323 		priv->w_stats.discard.misc = info->param.stats.ack_failure;
2324 #endif
2325 	}
2326 done:
2327 	if (status != MLAN_STATUS_PENDING)
2328 		kfree(req);
2329 	LEAVE();
2330 	return status;
2331 }
2332 
2333 /**
2334  *  @brief Get wireless stats information
2335  *
2336  *  @param priv         A pointer to moal_private structure
2337  *  @param respbuf      A pointer to response buffer
2338  *  @param respbuflen   Available length of response buffer
2339  *
2340  *  @return             Number of bytes written, negative for failure.
2341  */
woal_get_priv_getlog(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2342 static int woal_get_priv_getlog(moal_private *priv, t_u8 *respbuf,
2343 				t_u32 respbuflen)
2344 {
2345 	int ret = 0;
2346 	mlan_ds_get_stats *stats;
2347 	ENTER();
2348 
2349 	if (respbuflen < sizeof(*stats)) {
2350 		PRINTM(MERROR, "Get log: respbuflen (%d) too small!",
2351 		       (int)respbuflen);
2352 		ret = -EFAULT;
2353 		goto done;
2354 	}
2355 	stats = (mlan_ds_get_stats *)respbuf;
2356 	if (MLAN_STATUS_SUCCESS !=
2357 	    woal_get_stats_info(priv, MOAL_IOCTL_WAIT, stats)) {
2358 		PRINTM(MERROR, "Get log: Failed to get stats info!");
2359 		ret = -EFAULT;
2360 		goto done;
2361 	}
2362 
2363 	if (priv->phandle->fw_getlog_enable)
2364 		ret = sizeof(mlan_ds_get_stats);
2365 	else
2366 		ret = sizeof(mlan_ds_get_stats_org);
2367 
2368 done:
2369 	LEAVE();
2370 	return ret;
2371 }
2372 #endif
2373 
2374 /**
2375  *  @brief Set/Get esupplicant mode configurations
2376  *
2377  *  @param priv         A pointer to moal_private structure
2378  *  @param respbuf      A pointer to response buffer
2379  *  @param respbuflen   Available length of response buffer
2380  *
2381  *  @return             Number of bytes written, negative for failure.
2382  */
woal_setget_priv_esuppmode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2383 static int woal_setget_priv_esuppmode(moal_private *priv, t_u8 *respbuf,
2384 				      t_u32 respbuflen)
2385 {
2386 	t_u32 data[3];
2387 	mlan_ioctl_req *req = NULL;
2388 	mlan_ds_sec_cfg *sec = NULL;
2389 	woal_esuppmode_cfg *esupp_mode = NULL;
2390 	int ret = 0;
2391 	int user_data_len = 0;
2392 	mlan_status status = MLAN_STATUS_SUCCESS;
2393 
2394 	ENTER();
2395 
2396 	if (!priv->phandle->card_info->embedded_supp) {
2397 		PRINTM(MERROR, "Not supported cmd on this card\n");
2398 		ret = -EOPNOTSUPP;
2399 		goto done;
2400 	}
2401 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ESUPPMODE))) {
2402 		/* GET operation */
2403 		user_data_len = 0;
2404 	} else {
2405 		/* SET operation */
2406 		memset((char *)data, 0, sizeof(data));
2407 		parse_arguments(respbuf + strlen(CMD_NXP) +
2408 					strlen(PRIV_CMD_ESUPPMODE),
2409 				data, ARRAY_SIZE(data), &user_data_len);
2410 	}
2411 
2412 	if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) {
2413 		PRINTM(MERROR, "Invalid number of arguments\n");
2414 		ret = -EINVAL;
2415 		goto done;
2416 	}
2417 
2418 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
2419 	if (req == NULL) {
2420 		ret = -ENOMEM;
2421 		goto done;
2422 	}
2423 
2424 	req->req_id = MLAN_IOCTL_SEC_CFG;
2425 	sec = (mlan_ds_sec_cfg *)req->pbuf;
2426 	sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
2427 
2428 	if (user_data_len == 0) {
2429 		/* Get operation */
2430 		req->action = MLAN_ACT_GET;
2431 	} else {
2432 		/* Set operation */
2433 		req->action = MLAN_ACT_SET;
2434 		/* RSN mode */
2435 		sec->param.esupp_mode.rsn_mode = data[0];
2436 		/* Pairwise cipher */
2437 		sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF);
2438 		/* Group cipher */
2439 		sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF);
2440 	}
2441 
2442 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2443 	if (status != MLAN_STATUS_SUCCESS) {
2444 		ret = -EFAULT;
2445 		goto done;
2446 	}
2447 
2448 	esupp_mode = (woal_esuppmode_cfg *)respbuf;
2449 	esupp_mode->rsn_mode =
2450 		(t_u16)((sec->param.esupp_mode.rsn_mode) & 0xFFFF);
2451 	esupp_mode->pairwise_cipher =
2452 		(t_u8)((sec->param.esupp_mode.act_paircipher) & 0xFF);
2453 	esupp_mode->group_cipher =
2454 		(t_u8)((sec->param.esupp_mode.act_groupcipher) & 0xFF);
2455 
2456 	ret = sizeof(woal_esuppmode_cfg);
2457 done:
2458 	if (status != MLAN_STATUS_PENDING)
2459 		kfree(req);
2460 	LEAVE();
2461 	return ret;
2462 }
2463 
2464 /**
2465  *  @brief Set/Get esupplicant passphrase configurations
2466  *
2467  *  @param priv         A pointer to moal_private structure
2468  *  @param respbuf      A pointer to response buffer
2469  *  @param respbuflen   Available length of response buffer
2470  *
2471  *  @return             Number of bytes written, negative for failure.
2472  */
woal_setget_priv_passphrase(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2473 static int woal_setget_priv_passphrase(moal_private *priv, t_u8 *respbuf,
2474 				       t_u32 respbuflen)
2475 {
2476 	mlan_ioctl_req *req = NULL;
2477 	mlan_ds_sec_cfg *sec = NULL;
2478 	int ret = 0, action = -1, i = 0;
2479 	char *begin, *end, *opt;
2480 	t_u16 len = 0;
2481 	t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
2482 	t_u8 *mac = NULL;
2483 	mlan_status status = MLAN_STATUS_SUCCESS;
2484 
2485 	ENTER();
2486 
2487 	if (!priv->phandle->card_info->embedded_supp) {
2488 		PRINTM(MERROR, "Not supported cmd on this card\n");
2489 		ret = -EOPNOTSUPP;
2490 		goto done;
2491 	}
2492 
2493 	if (strlen(respbuf) ==
2494 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE))) {
2495 		PRINTM(MERROR, "No arguments provided\n");
2496 		ret = -EINVAL;
2497 		goto done;
2498 	}
2499 
2500 	/* Parse the buf to get the cmd_action */
2501 	begin = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE);
2502 	end = woal_strsep(&begin, ';', '/');
2503 	if (end)
2504 		action = woal_atox(end);
2505 	if (action < 0 || action > 2 || end[1] != '\0') {
2506 		PRINTM(MERROR, "Invalid action argument %s\n", end);
2507 		ret = -EINVAL;
2508 		goto done;
2509 	}
2510 
2511 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
2512 	if (req == NULL) {
2513 		ret = -ENOMEM;
2514 		goto done;
2515 	}
2516 
2517 	req->req_id = MLAN_IOCTL_SEC_CFG;
2518 	sec = (mlan_ds_sec_cfg *)req->pbuf;
2519 	sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
2520 	if (action == 0)
2521 		req->action = MLAN_ACT_GET;
2522 	else
2523 		req->action = MLAN_ACT_SET;
2524 
2525 	while (begin) {
2526 		end = woal_strsep(&begin, ';', '/');
2527 		opt = woal_strsep(&end, '=', '/');
2528 		if (!opt || !end || !end[0]) {
2529 			PRINTM(MERROR, "Invalid option\n");
2530 			ret = -EINVAL;
2531 			break;
2532 		} else if (!strnicmp(opt, "ssid", strlen(opt))) {
2533 			if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
2534 				PRINTM(MERROR,
2535 				       "SSID length exceeds max length\n");
2536 				ret = -EFAULT;
2537 				break;
2538 			}
2539 			sec->param.passphrase.ssid.ssid_len = strlen(end);
2540 			moal_memcpy_ext(priv->phandle,
2541 					sec->param.passphrase.ssid.ssid, end,
2542 					strlen(end), MLAN_MAX_SSID_LENGTH);
2543 			PRINTM(MINFO, "ssid=%s, len=%d\n",
2544 			       sec->param.passphrase.ssid.ssid,
2545 			       (int)sec->param.passphrase.ssid.ssid_len);
2546 		} else if (!strnicmp(opt, "bssid", strlen(opt))) {
2547 			woal_mac2u8((t_u8 *)&sec->param.passphrase.bssid, end);
2548 		} else if (!strnicmp(opt, "psk", strlen(opt)) &&
2549 			   req->action == MLAN_ACT_SET) {
2550 			if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
2551 				PRINTM(MERROR, "Invalid PMK length\n");
2552 				ret = -EINVAL;
2553 				break;
2554 			}
2555 			woal_ascii2hex(
2556 				(t_u8 *)(sec->param.passphrase.psk.pmk.pmk),
2557 				end, MLAN_PMK_HEXSTR_LENGTH / 2);
2558 			sec->param.passphrase.psk_type = MLAN_PSK_PMK;
2559 		} else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
2560 			   req->action == MLAN_ACT_SET) {
2561 			if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
2562 			    strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
2563 				PRINTM(MERROR,
2564 				       "Invalid length for passphrase\n");
2565 				ret = -EINVAL;
2566 				break;
2567 			}
2568 			sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
2569 			moal_memcpy_ext(
2570 				priv->phandle,
2571 				sec->param.passphrase.psk.passphrase.passphrase,
2572 				end,
2573 				sizeof(sec->param.passphrase.psk.passphrase
2574 					       .passphrase),
2575 				sizeof(sec->param.passphrase.psk.passphrase
2576 					       .passphrase));
2577 			sec->param.passphrase.psk.passphrase.passphrase_len =
2578 				strlen(end);
2579 			PRINTM(MINFO, "passphrase=%s, len=%d\n",
2580 			       sec->param.passphrase.psk.passphrase.passphrase,
2581 			       (int)sec->param.passphrase.psk.passphrase
2582 				       .passphrase_len);
2583 		} else if (!strnicmp(opt, "sae_password", strlen(opt)) &&
2584 			   req->action == MLAN_ACT_SET) {
2585 			if (strlen(end) < MLAN_MIN_SAE_PASSWORD_LENGTH ||
2586 			    strlen(end) > MLAN_MAX_SAE_PASSWORD_LENGTH) {
2587 				PRINTM(MERROR,
2588 				       "Invalid length for sae password\n");
2589 				ret = -EINVAL;
2590 				break;
2591 			}
2592 			sec->param.passphrase.psk_type = MLAN_PSK_SAE_PASSWORD;
2593 			moal_memcpy_ext(
2594 				priv->phandle,
2595 				sec->param.passphrase.psk.sae_password
2596 					.sae_password,
2597 				end,
2598 				sizeof(sec->param.passphrase.psk.sae_password
2599 					       .sae_password),
2600 				sizeof(sec->param.passphrase.psk.sae_password
2601 					       .sae_password));
2602 			sec->param.passphrase.psk.sae_password.sae_password_len =
2603 				strlen(end);
2604 			PRINTM(MINFO, "sae_password=%s, len=%d\n",
2605 			       sec->param.passphrase.psk.sae_password
2606 				       .sae_password,
2607 			       (int)sec->param.passphrase.psk.sae_password
2608 				       .sae_password_len);
2609 		} else {
2610 			PRINTM(MERROR, "Invalid option %s\n", opt);
2611 			ret = -EINVAL;
2612 			break;
2613 		}
2614 	}
2615 	if (ret)
2616 		goto done;
2617 
2618 	if (action == 2)
2619 		sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
2620 	else if (action == 0)
2621 		sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
2622 
2623 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2624 	if (status != MLAN_STATUS_SUCCESS) {
2625 		ret = -EFAULT;
2626 		goto done;
2627 	}
2628 
2629 	memset(respbuf, 0, respbuflen);
2630 	if (sec->param.passphrase.ssid.ssid_len) {
2631 		len += sprintf(respbuf + len, "ssid:");
2632 		moal_memcpy_ext(priv->phandle, respbuf + len,
2633 				sec->param.passphrase.ssid.ssid,
2634 				sec->param.passphrase.ssid.ssid_len,
2635 				respbuflen - len);
2636 		len += sec->param.passphrase.ssid.ssid_len;
2637 		len += sprintf(respbuf + len, " ");
2638 	}
2639 	if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
2640 		mac = (t_u8 *)&sec->param.passphrase.bssid;
2641 		len += sprintf(respbuf + len, "bssid:");
2642 		for (i = 0; i < ETH_ALEN - 1; ++i)
2643 			len += sprintf(respbuf + len, "%02x:", mac[i]);
2644 		len += sprintf(respbuf + len, "%02x ", mac[i]);
2645 	}
2646 	if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
2647 		len += sprintf(respbuf + len, "psk:");
2648 		for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
2649 			len += sprintf(respbuf + len, "%02x",
2650 				       sec->param.passphrase.psk.pmk.pmk[i]);
2651 		len += sprintf(respbuf + len, "\n");
2652 	}
2653 	if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE)
2654 		len += sprintf(respbuf + len, "passphrase:%s\n",
2655 			       sec->param.passphrase.psk.passphrase.passphrase);
2656 	if (sec->param.passphrase.psk_type == MLAN_PSK_SAE_PASSWORD)
2657 		len += sprintf(
2658 			respbuf + len, "sae_password:%s\n",
2659 			sec->param.passphrase.psk.sae_password.sae_password);
2660 
2661 	ret = len;
2662 done:
2663 	if (status != MLAN_STATUS_PENDING)
2664 		kfree(req);
2665 	LEAVE();
2666 	return ret;
2667 }
2668 
2669 /**
2670  *  @brief Deauthenticate
2671  *
2672  *  @param priv         A pointer to moal_private structure
2673  *  @param respbuf      A pointer to response buffer
2674  *  @param respbuflen   Available length of response buffer
2675  *
2676  *  @return             Number of bytes written, negative for failure.
2677  */
woal_priv_deauth(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2678 static int woal_priv_deauth(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
2679 {
2680 	int ret = 0;
2681 	t_u8 mac[ETH_ALEN];
2682 
2683 	ENTER();
2684 
2685 	if (strlen(respbuf) > (strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH))) {
2686 		/* Deauth mentioned BSSID */
2687 		woal_mac2u8(mac, respbuf + strlen(CMD_NXP) +
2688 					 strlen(PRIV_CMD_DEAUTH));
2689 		if (MLAN_STATUS_SUCCESS !=
2690 		    woal_disconnect(priv, MOAL_IOCTL_WAIT, mac,
2691 				    DEF_DEAUTH_REASON_CODE)) {
2692 			ret = -EFAULT;
2693 			goto done;
2694 		}
2695 	} else {
2696 		if (MLAN_STATUS_SUCCESS !=
2697 		    woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
2698 				    DEF_DEAUTH_REASON_CODE))
2699 			ret = -EFAULT;
2700 	}
2701 
2702 done:
2703 	LEAVE();
2704 	return ret;
2705 }
2706 
2707 #ifdef UAP_SUPPORT
2708 /**
2709  *  @brief uap station deauth ioctl handler
2710  *
2711  *  @param priv         A pointer to moal_private structure
2712  *  @param respbuf      A pointer to response buffer
2713  *  @param respbuflen   Available length of response buffer
2714  *
2715  *  @return             Number of bytes written, negative for failure.
2716  */
woal_priv_ap_deauth(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2717 static int woal_priv_ap_deauth(moal_private *priv, t_u8 *respbuf,
2718 			       t_u32 respbuflen)
2719 {
2720 	t_u8 *data_ptr;
2721 	mlan_ioctl_req *ioctl_req = NULL;
2722 	mlan_ds_bss *bss = NULL;
2723 	mlan_deauth_param deauth_param;
2724 	int ret = 0;
2725 	mlan_status status = MLAN_STATUS_SUCCESS;
2726 
2727 	ENTER();
2728 
2729 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH));
2730 	memset(&deauth_param, 0, sizeof(mlan_deauth_param));
2731 	moal_memcpy_ext(priv->phandle, &deauth_param, data_ptr,
2732 			sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));
2733 
2734 	PRINTM(MIOCTL, "ioctl deauth station: " MACSTR ", reason=%d\n",
2735 	       MAC2STR(deauth_param.mac_addr), deauth_param.reason_code);
2736 
2737 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2738 	if (ioctl_req == NULL) {
2739 		ret = -ENOMEM;
2740 		goto done;
2741 	}
2742 	bss = (mlan_ds_bss *)ioctl_req->pbuf;
2743 
2744 	bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
2745 	ioctl_req->req_id = MLAN_IOCTL_BSS;
2746 	ioctl_req->action = MLAN_ACT_SET;
2747 
2748 	moal_memcpy_ext(priv->phandle, &bss->param.deauth_param, &deauth_param,
2749 			sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));
2750 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2751 	if (status != MLAN_STATUS_SUCCESS) {
2752 		ret = -EFAULT;
2753 		goto done;
2754 	}
2755 
2756 	moal_memcpy_ext(
2757 		priv->phandle, data_ptr, &ioctl_req->status_code, sizeof(t_u32),
2758 		respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH)));
2759 	ret = sizeof(t_u32);
2760 done:
2761 	if (status != MLAN_STATUS_PENDING)
2762 		kfree(ioctl_req);
2763 	LEAVE();
2764 	return ret;
2765 }
2766 
2767 /**
2768  *  @brief uap get station list handler
2769  *
2770  *  @param dev      A pointer to net_device structure
2771  *  @param req      A pointer to ifreq structure
2772  *  @return         0 --success, otherwise fail
2773  */
woal_priv_get_sta_list(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2774 static int woal_priv_get_sta_list(moal_private *priv, t_u8 *respbuf,
2775 				  t_u32 respbuflen)
2776 {
2777 	int ret = 0;
2778 	mlan_ds_get_info *info = NULL;
2779 	mlan_ds_sta_list *sta_list = NULL;
2780 	mlan_ioctl_req *ioctl_req = NULL;
2781 	mlan_status status = MLAN_STATUS_SUCCESS;
2782 
2783 	ENTER();
2784 
2785 	/* Allocate an IOCTL request buffer */
2786 	ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
2787 		sizeof(mlan_ds_get_info));
2788 	if (ioctl_req == NULL) {
2789 		ret = -ENOMEM;
2790 		goto done;
2791 	}
2792 
2793 	info = (mlan_ds_get_info *)ioctl_req->pbuf;
2794 	info->sub_command = MLAN_OID_UAP_STA_LIST;
2795 	ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
2796 	ioctl_req->action = MLAN_ACT_GET;
2797 
2798 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2799 	if (status != MLAN_STATUS_SUCCESS) {
2800 		ret = -EFAULT;
2801 		goto done;
2802 	}
2803 
2804 	sta_list = (mlan_ds_sta_list *)(respbuf + strlen(CMD_NXP) +
2805 					strlen(PRIV_CMD_GET_STA_LIST));
2806 	moal_memcpy_ext(
2807 		priv->phandle, sta_list, &info->param.sta_list,
2808 		ioctl_req->data_read_written,
2809 		respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_STA_LIST)));
2810 	ret = ioctl_req->data_read_written + strlen(CMD_NXP) +
2811 	      strlen(PRIV_CMD_GET_STA_LIST);
2812 done:
2813 	if (status != MLAN_STATUS_PENDING)
2814 		kfree(ioctl_req);
2815 	LEAVE();
2816 	return ret;
2817 }
2818 
2819 /**
2820  *  @brief uap bss_config handler
2821  *
2822  *  @param dev      A pointer to net_device structure
2823  *  @param req      A pointer to ifreq structure
2824  *  @return         0 --success, otherwise fail
2825  */
woal_priv_bss_config(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2826 static int woal_priv_bss_config(moal_private *priv, t_u8 *respbuf,
2827 				t_u32 respbuflen)
2828 {
2829 	int ret = 0;
2830 	mlan_ds_bss *bss = NULL;
2831 	mlan_ioctl_req *ioctl_req = NULL;
2832 	t_u32 action = 0;
2833 	int offset = 0;
2834 	mlan_status status = MLAN_STATUS_SUCCESS;
2835 
2836 	ENTER();
2837 
2838 	offset = strlen(CMD_NXP) + strlen(PRIV_CMD_BSS_CONFIG);
2839 	moal_memcpy_ext(priv->phandle, (u8 *)&action, respbuf + offset,
2840 			sizeof(action), sizeof(action));
2841 	offset += sizeof(action);
2842 
2843 	/* Allocate an IOCTL request buffer */
2844 	ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
2845 		sizeof(mlan_ds_bss));
2846 	if (ioctl_req == NULL) {
2847 		ret = -ENOMEM;
2848 		goto done;
2849 	}
2850 
2851 	bss = (mlan_ds_bss *)ioctl_req->pbuf;
2852 	bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
2853 	ioctl_req->req_id = MLAN_IOCTL_BSS;
2854 	if (action == 1) {
2855 		ioctl_req->action = MLAN_ACT_SET;
2856 		/* Get the BSS config from user */
2857 		moal_memcpy_ext(priv->phandle, &bss->param.bss_config,
2858 				respbuf + offset, sizeof(mlan_uap_bss_param),
2859 				sizeof(mlan_uap_bss_param));
2860 	} else {
2861 		ioctl_req->action = MLAN_ACT_GET;
2862 	}
2863 
2864 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2865 	if (status != MLAN_STATUS_SUCCESS) {
2866 		ret = -EFAULT;
2867 		goto done;
2868 	}
2869 
2870 	if (ioctl_req->action == MLAN_ACT_GET) {
2871 		moal_memcpy_ext(priv->phandle, respbuf + offset,
2872 				&bss->param.bss_config,
2873 				sizeof(mlan_uap_bss_param),
2874 				respbuflen - (t_u32)offset);
2875 	}
2876 	ret = sizeof(mlan_uap_bss_param);
2877 done:
2878 	if (status != MLAN_STATUS_PENDING)
2879 		kfree(ioctl_req);
2880 	LEAVE();
2881 	return ret;
2882 }
2883 #endif
2884 
2885 #ifdef WIFI_DIRECT_SUPPORT
2886 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
2887 /**
2888  *  @brief Set/Get BSS role
2889  *
2890  *  @param priv         A pointer to moal_private structure
2891  *  @param respbuf      A pointer to response buffer
2892  *  @param respbuflen   Available length of response buffer
2893  *
2894  *  @return             Number of bytes written, negative for failure.
2895  */
woal_priv_bssrole(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2896 static int woal_priv_bssrole(moal_private *priv, t_u8 *respbuf,
2897 			     t_u32 respbuflen)
2898 {
2899 	t_u32 data[1];
2900 	int ret = 0;
2901 	int user_data_len = 0;
2902 	t_u8 action = MLAN_ACT_GET;
2903 
2904 	ENTER();
2905 
2906 	memset((char *)data, 0, sizeof(data));
2907 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BSSROLE))) {
2908 		/* GET operation */
2909 		user_data_len = 0;
2910 	} else {
2911 		/* SET operation */
2912 		parse_arguments(respbuf + strlen(CMD_NXP) +
2913 					strlen(PRIV_CMD_BSSROLE),
2914 				data, ARRAY_SIZE(data), &user_data_len);
2915 	}
2916 
2917 	if (user_data_len >= 2) {
2918 		PRINTM(MERROR, "Too many arguments\n");
2919 		ret = -EINVAL;
2920 		goto error;
2921 	}
2922 
2923 	if (user_data_len == 0) {
2924 		action = MLAN_ACT_GET;
2925 	} else {
2926 		if ((data[0] != MLAN_BSS_ROLE_STA &&
2927 		     data[0] != MLAN_BSS_ROLE_UAP) ||
2928 		    priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
2929 			PRINTM(MWARN, "Invalid BSS role\n");
2930 			ret = -EINVAL;
2931 			goto error;
2932 		}
2933 		if (data[0] == GET_BSS_ROLE(priv)) {
2934 			PRINTM(MWARN, "Already BSS is in desired role\n");
2935 			goto done;
2936 		}
2937 		action = MLAN_ACT_SET;
2938 		/* Reset interface */
2939 		if (MLAN_STATUS_SUCCESS !=
2940 		    woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE)) {
2941 			PRINTM(MERROR, "%s: woal_reset_intf failed \n",
2942 			       __func__);
2943 			ret = -EFAULT;
2944 			goto error;
2945 		}
2946 	}
2947 
2948 	if (MLAN_STATUS_SUCCESS !=
2949 	    woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, (t_u8 *)data)) {
2950 		ret = -EFAULT;
2951 		goto error;
2952 	}
2953 
2954 	if (user_data_len) {
2955 		/* Initialize private structures */
2956 		woal_init_priv(priv, MOAL_IOCTL_WAIT);
2957 		/* Enable interfaces */
2958 		netif_device_attach(priv->netdev);
2959 		woal_start_queue(priv->netdev);
2960 	}
2961 
2962 done:
2963 	memset(respbuf, 0, respbuflen);
2964 	respbuf[0] = (t_u8)data[0];
2965 	ret = 1;
2966 
2967 error:
2968 	LEAVE();
2969 	return ret;
2970 }
2971 #endif /* STA_SUPPORT && UAP_SUPPORT */
2972 #endif /* WIFI_DIRECT_SUPPORT */
2973 
2974 #ifdef STA_SUPPORT
2975 /**
2976  *  @brief Set user scan
2977  *
2978  *  @param priv         A pointer to moal_private structure
2979  *  @param respbuf      A pointer to response buffer
2980  *  @param respbuflen   Available length of response buffer
2981  *
2982  *  @return             Number of bytes written, negative for failure.
2983  */
woal_priv_setuserscan(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2984 static int woal_priv_setuserscan(moal_private *priv, t_u8 *respbuf,
2985 				 t_u32 respbuflen)
2986 {
2987 	wlan_user_scan_cfg *scan_cfg;
2988 	int ret = 0;
2989 
2990 	ENTER();
2991 
2992 	scan_cfg = (wlan_user_scan_cfg *)kmalloc(sizeof(wlan_user_scan_cfg),
2993 						 GFP_KERNEL);
2994 	if (!scan_cfg) {
2995 		PRINTM(MERROR, "Malloc buffer failed\n");
2996 		LEAVE();
2997 		return -ENOMEM;
2998 	}
2999 
3000 	/* Create the scan_cfg structure */
3001 	memset(scan_cfg, 0, sizeof(wlan_user_scan_cfg));
3002 
3003 	/* We expect the scan_cfg structure to be passed in respbuf */
3004 	moal_memcpy_ext(priv->phandle, (char *)scan_cfg,
3005 			respbuf + strlen(CMD_NXP) +
3006 				strlen(PRIV_CMD_SETUSERSCAN),
3007 			sizeof(wlan_user_scan_cfg), sizeof(wlan_user_scan_cfg));
3008 	moal_memcpy_ext(priv->phandle, scan_cfg->random_mac, priv->random_mac,
3009 			ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
3010 	/* Call for scan */
3011 	if (MLAN_STATUS_FAILURE == woal_do_scan(priv, scan_cfg))
3012 		ret = -EFAULT;
3013 	kfree(scan_cfg);
3014 	LEAVE();
3015 	return ret;
3016 }
3017 
3018 /**
3019  *  @brief Get channel statistics
3020  *
3021  *  @param priv         A pointer to moal_private structure
3022  *  @param respbuf      A pointer to response buffer
3023  *  @param respbuflen   Available length of response buffer
3024  *
3025  *  @return             Number of bytes written, negative for failure.
3026  */
woal_priv_get_chanstats(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3027 static int woal_priv_get_chanstats(moal_private *priv, t_u8 *respbuf,
3028 				   t_u32 respbuflen)
3029 {
3030 	mlan_scan_resp scan_resp;
3031 	chan_stats *stats = NULL;
3032 	int ret = 0;
3033 	ENTER();
3034 
3035 	if (!respbuf) {
3036 		PRINTM(MERROR, "response buffer is not available!\n");
3037 		ret = -EINVAL;
3038 		goto done;
3039 	}
3040 	mdelay(10);
3041 	memset(&scan_resp, 0, sizeof(scan_resp));
3042 	if (MLAN_STATUS_SUCCESS !=
3043 	    woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
3044 		ret = -EFAULT;
3045 		goto done;
3046 	}
3047 	memset(respbuf, 0, respbuflen);
3048 	stats = (chan_stats *)respbuf;
3049 	stats->num_in_chan_stats = scan_resp.num_in_chan_stats;
3050 	ret = sizeof(ChanStatistics_t) * stats->num_in_chan_stats;
3051 	moal_memcpy_ext(priv->phandle, (t_u8 *)stats->stats,
3052 			(t_u8 *)scan_resp.pchan_stats, ret, respbuflen);
3053 	ret += sizeof(stats->num_in_chan_stats);
3054 done:
3055 	LEAVE();
3056 	return ret;
3057 }
3058 
3059 /**
3060  *  @brief Retrieve the scan response/beacon table
3061  *
3062  *  @param respbuf      A pointer to response buffer
3063  *  @param respbuflen   Available length of response buffer
3064  *  @param scan_resp    A pointer to mlan_scan_resp structure
3065  *  @param scan_start   Argument
3066  *
3067  *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
3068  */
moal_ret_get_scan_table_ioctl(t_u8 * respbuf,t_u32 respbuflen,mlan_scan_resp * scan_resp,t_u32 scan_start)3069 static int moal_ret_get_scan_table_ioctl(t_u8 *respbuf, t_u32 respbuflen,
3070 					 mlan_scan_resp *scan_resp,
3071 					 t_u32 scan_start)
3072 {
3073 	pBSSDescriptor_t pbss_desc, scan_table;
3074 	wlan_ioctl_get_scan_table_info *prsp_info;
3075 	int ret_code;
3076 	int ret_len;
3077 	int space_left;
3078 	t_u8 *pcurrent;
3079 	t_u8 *pbuffer_end;
3080 	t_u32 num_scans_done;
3081 
3082 	ENTER();
3083 
3084 	num_scans_done = 0;
3085 	ret_code = MLAN_STATUS_SUCCESS;
3086 
3087 	prsp_info = (wlan_ioctl_get_scan_table_info *)respbuf;
3088 	pcurrent = (t_u8 *)prsp_info->scan_table_entry_buf;
3089 
3090 	pbuffer_end = respbuf + respbuflen - 1;
3091 	space_left = pbuffer_end - pcurrent;
3092 	scan_table = (BSSDescriptor_t *)(scan_resp->pscan_table);
3093 
3094 	PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
3095 	PRINTM(MINFO, "GetScanTable: length avail = %d\n", respbuflen);
3096 
3097 	if (!scan_start) {
3098 		PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
3099 
3100 		/* Use to get current association saved descriptor */
3101 		pbss_desc = scan_table;
3102 
3103 		ret_code = wlan_get_scan_table_ret_entry(pbss_desc, &pcurrent,
3104 							 &space_left);
3105 
3106 		if (ret_code == MLAN_STATUS_SUCCESS)
3107 			num_scans_done = 1;
3108 
3109 	} else {
3110 		scan_start--;
3111 
3112 		while (space_left &&
3113 		       (scan_start + num_scans_done <
3114 			scan_resp->num_in_scan_table) &&
3115 		       (ret_code == MLAN_STATUS_SUCCESS)) {
3116 			pbss_desc =
3117 				(scan_table + (scan_start + num_scans_done));
3118 
3119 			PRINTM(MINFO,
3120 			       "GetScanTable: get current BSS Descriptor [%d]\n",
3121 			       scan_start + num_scans_done);
3122 
3123 			ret_code = wlan_get_scan_table_ret_entry(
3124 				pbss_desc, &pcurrent, &space_left);
3125 
3126 			if (ret_code == MLAN_STATUS_SUCCESS)
3127 				num_scans_done++;
3128 		}
3129 	}
3130 
3131 	prsp_info->scan_number = num_scans_done;
3132 	ret_len = pcurrent - respbuf;
3133 
3134 	LEAVE();
3135 	return ret_len;
3136 }
3137 
3138 /**
3139  *  @brief Get scan table
3140  *
3141  *  @param priv         A pointer to moal_private structure
3142  *  @param respbuf      A pointer to response buffer
3143  *  @param respbuflen   Available length of response buffer
3144  *
3145  *  @return             Number of bytes written, negative for failure.
3146  */
woal_priv_getscantable(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3147 static int woal_priv_getscantable(moal_private *priv, t_u8 *respbuf,
3148 				  t_u32 respbuflen)
3149 {
3150 	int ret = 0;
3151 	mlan_ioctl_req *req = NULL;
3152 	mlan_ds_scan *scan = NULL;
3153 	t_u32 scan_start;
3154 	mlan_status status = MLAN_STATUS_SUCCESS;
3155 	moal_handle *handle = priv->phandle;
3156 
3157 	ENTER();
3158 
3159 	/* First make sure scanning is not in progress */
3160 	if (handle->scan_pending_on_block == MTRUE) {
3161 		ret = -EAGAIN;
3162 		goto done;
3163 	}
3164 
3165 	/* Allocate an IOCTL request buffer */
3166 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
3167 	if (req == NULL) {
3168 		ret = -ENOMEM;
3169 		goto done;
3170 	}
3171 
3172 	/* Fill request buffer */
3173 	scan = (mlan_ds_scan *)req->pbuf;
3174 	req->req_id = MLAN_IOCTL_SCAN;
3175 	req->action = MLAN_ACT_GET;
3176 
3177 	/* Get the whole command from user */
3178 	moal_memcpy_ext(handle, &scan_start,
3179 			respbuf + strlen(CMD_NXP) +
3180 				strlen(PRIV_CMD_GETSCANTABLE),
3181 			sizeof(scan_start), sizeof(scan_start));
3182 	if (scan_start)
3183 		scan->sub_command = MLAN_OID_SCAN_NORMAL;
3184 	else
3185 		scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;
3186 
3187 	/* Send IOCTL request to MLAN */
3188 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3189 	if (status == MLAN_STATUS_SUCCESS) {
3190 		ret = moal_ret_get_scan_table_ioctl(respbuf, respbuflen,
3191 						    &scan->param.scan_resp,
3192 						    scan_start);
3193 	}
3194 done:
3195 	if (status != MLAN_STATUS_PENDING)
3196 		kfree(req);
3197 	LEAVE();
3198 	return ret;
3199 }
3200 /**
3201  *  @brief Extended capabilities configuration
3202  *
3203  *  @param priv         A pointer to moal_private structure
3204  *  @param respbuf      A pointer to response buffer
3205  *  @param respbuflen   Available length of response buffer
3206  *
3207  *  @return             Number of bytes written, negative for failure.
3208  */
woal_priv_extcapcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3209 static int woal_priv_extcapcfg(moal_private *priv, t_u8 *respbuf,
3210 			       t_u32 respbuflen)
3211 {
3212 	int ret, header;
3213 	mlan_ioctl_req *req = NULL;
3214 	mlan_ds_misc_cfg *cfg = NULL;
3215 	IEEEtypes_Header_t *ie;
3216 	mlan_status status = MLAN_STATUS_SUCCESS;
3217 
3218 	ENTER();
3219 
3220 	if (!respbuf) {
3221 		LEAVE();
3222 		return 0;
3223 	}
3224 
3225 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3226 	if (req == NULL) {
3227 		ret = -ENOMEM;
3228 		goto done;
3229 	}
3230 
3231 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
3232 	cfg->sub_command = MLAN_OID_MISC_EXT_CAP_CFG;
3233 	req->req_id = MLAN_IOCTL_MISC_CFG;
3234 	header = strlen(CMD_NXP) + strlen(PRIV_CMD_EXTCAPCFG);
3235 	if ((int)strlen(respbuf) == header)
3236 		/* GET operation */
3237 		req->action = MLAN_ACT_GET;
3238 	else {
3239 		/* SET operation */
3240 		ie = (IEEEtypes_Header_t *)(respbuf + header);
3241 		if (ie->len > sizeof(ExtCap_t)) {
3242 			PRINTM(MERROR,
3243 			       "Extended Capability lenth is invalid\n");
3244 			ret = -EFAULT;
3245 			goto done;
3246 		}
3247 		req->action = MLAN_ACT_SET;
3248 		memset(&cfg->param.ext_cap, 0, sizeof(ExtCap_t));
3249 		moal_memcpy_ext(priv->phandle, &cfg->param.ext_cap, ie + 1,
3250 				ie->len, sizeof(ExtCap_t));
3251 	}
3252 
3253 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3254 	if (status != MLAN_STATUS_SUCCESS) {
3255 		ret = -EFAULT;
3256 		goto done;
3257 	}
3258 
3259 	memset(respbuf, 0, respbuflen);
3260 	ie = (IEEEtypes_Header_t *)respbuf;
3261 	ie->element_id = EXT_CAPABILITY;
3262 	ie->len = sizeof(ExtCap_t);
3263 	moal_memcpy_ext(priv->phandle, ie + 1, &cfg->param.ext_cap,
3264 			sizeof(ExtCap_t),
3265 			respbuflen - sizeof(IEEEtypes_Header_t));
3266 
3267 	ret = sizeof(IEEEtypes_Header_t) + ie->len;
3268 
3269 done:
3270 	if (status != MLAN_STATUS_PENDING)
3271 		kfree(req);
3272 	LEAVE();
3273 	return ret;
3274 }
3275 #endif
3276 
3277 /**
3278  *  @brief Set/Get deep sleep mode configurations
3279  *
3280  *  @param priv         A pointer to moal_private structure
3281  *  @param respbuf      A pointer to response buffer
3282  *  @param respbuflen   Available length of response buffer
3283  *
3284  *  @return             Number of bytes written, negative for failure.
3285  */
woal_priv_setgetdeepsleep(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3286 static int woal_priv_setgetdeepsleep(moal_private *priv, t_u8 *respbuf,
3287 				     t_u32 respbuflen)
3288 {
3289 	t_u32 data[2];
3290 	int ret = 0;
3291 	int user_data_len = 0;
3292 
3293 	ENTER();
3294 
3295 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DEEPSLEEP))) {
3296 		/* GET operation */
3297 		user_data_len = 0;
3298 	} else {
3299 		/* SET operation */
3300 		memset((char *)data, 0, sizeof(data));
3301 		parse_arguments(respbuf + strlen(CMD_NXP) +
3302 					strlen(PRIV_CMD_DEEPSLEEP),
3303 				data, ARRAY_SIZE(data), &user_data_len);
3304 	}
3305 
3306 	if (user_data_len >= 3) {
3307 		PRINTM(MERROR, "Too many arguments\n");
3308 		ret = -EINVAL;
3309 		goto done;
3310 	}
3311 
3312 	if (user_data_len == 0) {
3313 		if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
3314 			ret = -EFAULT;
3315 			goto done;
3316 		}
3317 		sprintf(respbuf, "%d %d", data[0], data[1]);
3318 		ret = strlen(respbuf) + 1;
3319 	} else {
3320 		if (data[0] == DEEP_SLEEP_OFF) {
3321 			PRINTM(MINFO, "Exit Deep Sleep Mode\n");
3322 			ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE,
3323 						  0);
3324 			if (ret != MLAN_STATUS_SUCCESS) {
3325 				ret = -EINVAL;
3326 				goto done;
3327 			}
3328 		} else if (data[0] == DEEP_SLEEP_ON) {
3329 			PRINTM(MINFO, "Enter Deep Sleep Mode\n");
3330 			if (user_data_len != 2)
3331 				data[1] = 0;
3332 			ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE,
3333 						  data[1]);
3334 			if (ret != MLAN_STATUS_SUCCESS) {
3335 				ret = -EINVAL;
3336 				goto done;
3337 			}
3338 		} else {
3339 			PRINTM(MERROR, "Unknown option = %u\n", data[0]);
3340 			ret = -EINVAL;
3341 			goto done;
3342 		}
3343 		ret = sprintf(respbuf, "OK\n") + 1;
3344 	}
3345 
3346 done:
3347 	LEAVE();
3348 	return ret;
3349 }
3350 
3351 /**
3352  *  @brief Set/Get IP address configurations
3353  *
3354  *  @param priv         A pointer to moal_private structure
3355  *  @param respbuf      A pointer to response buffer
3356  *  @param respbuflen   Available length of response buffer
3357  *
3358  *  @return             Number of bytes written, negative for failure.
3359  */
woal_priv_setgetipaddr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3360 static int woal_priv_setgetipaddr(moal_private *priv, t_u8 *respbuf,
3361 				  t_u32 respbuflen)
3362 {
3363 	mlan_ioctl_req *req = NULL;
3364 	mlan_ds_misc_cfg *misc = NULL;
3365 	int ret = 0, op_code = 0, data_length = 0, header = 0;
3366 	mlan_status status = MLAN_STATUS_SUCCESS;
3367 
3368 	ENTER();
3369 
3370 	if (priv->bss_type != MLAN_BSS_TYPE_STA) {
3371 		PRINTM(MIOCTL, "Bss type[%d]: Not STA, ignore it\n",
3372 		       priv->bss_type);
3373 		ret = sprintf(respbuf, "OK\n") + 1;
3374 		goto done;
3375 	}
3376 
3377 	header = strlen(CMD_NXP) + strlen(PRIV_CMD_IPADDR);
3378 	data_length = strlen(respbuf) - header;
3379 
3380 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3381 	if (req == NULL) {
3382 		ret = -ENOMEM;
3383 		goto done;
3384 	}
3385 	misc = (mlan_ds_misc_cfg *)req->pbuf;
3386 
3387 	if (data_length < 1) { /* GET */
3388 		req->action = MLAN_ACT_GET;
3389 	} else {
3390 		/* Make sure we have the operation argument */
3391 		if (data_length > 2 && respbuf[header + 1] != ';') {
3392 			PRINTM(MERROR,
3393 			       "No operation argument. Separate with ';'\n");
3394 			ret = -EINVAL;
3395 			goto done;
3396 		} else {
3397 			respbuf[header + 1] = '\0';
3398 		}
3399 		req->action = MLAN_ACT_SET;
3400 
3401 		/* Only one IP is supported in current firmware */
3402 		memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
3403 		if (data_length > 2)
3404 			in4_pton(&respbuf[header + 2],
3405 				 MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
3406 				 misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
3407 		misc->param.ipaddr_cfg.ip_addr_num = 1;
3408 		misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
3409 
3410 		if (woal_atoi(&op_code, &respbuf[header]) !=
3411 		    MLAN_STATUS_SUCCESS) {
3412 			ret = -EINVAL;
3413 			goto done;
3414 		}
3415 		misc->param.ipaddr_cfg.op_code = (t_u32)op_code;
3416 	}
3417 
3418 	req->req_id = MLAN_IOCTL_MISC_CFG;
3419 	misc->sub_command = MLAN_OID_MISC_IP_ADDR;
3420 
3421 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3422 	if (status != MLAN_STATUS_SUCCESS) {
3423 		ret = -EFAULT;
3424 		goto done;
3425 	}
3426 
3427 	if (req->action == MLAN_ACT_GET) {
3428 		snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
3429 			 misc->param.ipaddr_cfg.op_code,
3430 			 misc->param.ipaddr_cfg.ip_addr[0][0],
3431 			 misc->param.ipaddr_cfg.ip_addr[0][1],
3432 			 misc->param.ipaddr_cfg.ip_addr[0][2],
3433 			 misc->param.ipaddr_cfg.ip_addr[0][3]);
3434 		ret = IPADDR_MAX_BUF + 1;
3435 	} else {
3436 		ret = sprintf(respbuf, "OK\n") + 1;
3437 	}
3438 
3439 done:
3440 	if (status != MLAN_STATUS_PENDING)
3441 		kfree(req);
3442 	LEAVE();
3443 	return ret;
3444 }
3445 
3446 /**
3447  *  @brief Set/Get WPS session configurations
3448  *
3449  *  @param priv         A pointer to moal_private structure
3450  *  @param respbuf      A pointer to response buffer
3451  *  @param respbuflen   Available length of response buffer
3452  *
3453  *  @return             Number of bytes written, negative for failure.
3454  */
woal_priv_setwpssession(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3455 static int woal_priv_setwpssession(moal_private *priv, t_u8 *respbuf,
3456 				   t_u32 respbuflen)
3457 {
3458 	mlan_ioctl_req *req = NULL;
3459 	mlan_ds_wps_cfg *pwps = NULL;
3460 	t_u32 data[1];
3461 	int ret = 0;
3462 	int user_data_len = 0;
3463 	mlan_status status = MLAN_STATUS_SUCCESS;
3464 
3465 	ENTER();
3466 
3467 	memset((char *)data, 0, sizeof(data));
3468 	if (strlen(respbuf) ==
3469 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_WPSSESSION))) {
3470 		/* GET operation */
3471 		user_data_len = 0;
3472 	} else {
3473 		/* SET operation */
3474 		parse_arguments(respbuf + strlen(CMD_NXP) +
3475 					strlen(PRIV_CMD_WPSSESSION),
3476 				data, ARRAY_SIZE(data), &user_data_len);
3477 	}
3478 
3479 	if (user_data_len > 1) {
3480 		PRINTM(MERROR, "Too many arguments\n");
3481 		ret = -EINVAL;
3482 		goto done;
3483 	}
3484 
3485 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
3486 	if (req == NULL) {
3487 		ret = -ENOMEM;
3488 		goto done;
3489 	}
3490 	pwps = (mlan_ds_wps_cfg *)req->pbuf;
3491 
3492 	req->req_id = MLAN_IOCTL_WPS_CFG;
3493 	req->action = MLAN_ACT_SET;
3494 	pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
3495 
3496 	if (data[0] == 1)
3497 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
3498 	else
3499 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
3500 
3501 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3502 	if (status != MLAN_STATUS_SUCCESS) {
3503 		ret = -EFAULT;
3504 		goto done;
3505 	}
3506 
3507 	ret = sprintf(respbuf, "OK\n") + 1;
3508 done:
3509 	if (status != MLAN_STATUS_PENDING)
3510 		kfree(req);
3511 	LEAVE();
3512 	return ret;
3513 }
3514 
3515 /**
3516  *  @brief Get OTP user data
3517  *
3518  *  @param priv         A pointer to moal_private structure
3519  *  @param respbuf      A pointer to response buffer
3520  *  @param respbuflen   Available length of response buffer
3521  *
3522  *  @return             Number of bytes written, negative for failure.
3523  */
woal_priv_otpuserdata(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3524 static int woal_priv_otpuserdata(moal_private *priv, t_u8 *respbuf,
3525 				 t_u32 respbuflen)
3526 {
3527 	int data[1];
3528 	int user_data_len = 0;
3529 	mlan_ioctl_req *req = NULL;
3530 	mlan_ds_misc_cfg *misc = NULL;
3531 	mlan_ds_misc_otp_user_data *otp = NULL;
3532 	int ret = 0;
3533 	mlan_status status = MLAN_STATUS_SUCCESS;
3534 
3535 	ENTER();
3536 
3537 	if (strlen(respbuf) ==
3538 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_OTPUSERDATA))) {
3539 		PRINTM(MERROR, "Invalid number of arguments\n");
3540 		ret = -EINVAL;
3541 		goto done;
3542 	}
3543 	memset((char *)data, 0, sizeof(data));
3544 	parse_arguments(respbuf + strlen(CMD_NXP) +
3545 				strlen(PRIV_CMD_OTPUSERDATA),
3546 			data, ARRAY_SIZE(data), &user_data_len);
3547 
3548 	if (user_data_len != 1) {
3549 		PRINTM(MERROR, "Invalid number of arguments\n");
3550 		ret = -EINVAL;
3551 		goto done;
3552 	}
3553 
3554 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3555 	if (req == NULL) {
3556 		ret = -ENOMEM;
3557 		goto done;
3558 	}
3559 	req->action = MLAN_ACT_GET;
3560 	req->req_id = MLAN_IOCTL_MISC_CFG;
3561 
3562 	misc = (mlan_ds_misc_cfg *)req->pbuf;
3563 	misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA;
3564 	misc->param.otp_user_data.user_data_length = data[0];
3565 
3566 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3567 	if (status != MLAN_STATUS_SUCCESS) {
3568 		ret = -EFAULT;
3569 		goto done;
3570 	}
3571 	otp = (mlan_ds_misc_otp_user_data *)req->pbuf;
3572 
3573 	if (req->action == MLAN_ACT_GET) {
3574 		ret = MIN(otp->user_data_length, data[0]);
3575 		moal_memcpy_ext(priv->phandle, respbuf, otp->user_data, ret,
3576 				respbuflen);
3577 	}
3578 
3579 done:
3580 	if (status != MLAN_STATUS_PENDING)
3581 		kfree(req);
3582 	LEAVE();
3583 	return ret;
3584 }
3585 
3586 /**
3587  *  @brief Set / Get country code
3588  *
3589  *  @param priv         A pointer to moal_private structure
3590  *  @param respbuf      A pointer to response buffer
3591  *  @param respbuflen   Available length of response buffer
3592  *
3593  *  @return             Number of bytes written, negative for failure.
3594  */
woal_priv_set_get_countrycode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3595 static int woal_priv_set_get_countrycode(moal_private *priv, t_u8 *respbuf,
3596 					 t_u32 respbuflen)
3597 {
3598 	int ret = 0;
3599 	/* char data[COUNTRY_CODE_LEN] = {0, 0, 0}; */
3600 	int header = 0, data_length = 0; /* wrq->u.data.length; */
3601 	mlan_ioctl_req *req = NULL;
3602 	mlan_ds_misc_cfg *pcfg_misc = NULL;
3603 	mlan_ds_misc_country_code *country_code = NULL;
3604 	mlan_status status = MLAN_STATUS_SUCCESS;
3605 
3606 	ENTER();
3607 
3608 	header = strlen(CMD_NXP) + strlen(PRIV_CMD_COUNTRYCODE);
3609 	data_length = strlen(respbuf) - header;
3610 
3611 	if (data_length > COUNTRY_CODE_LEN) {
3612 		PRINTM(MERROR, "Invalid argument!\n");
3613 		ret = -EINVAL;
3614 		goto done;
3615 	}
3616 
3617 	/* Allocate an IOCTL request buffer */
3618 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3619 	if (req == NULL) {
3620 		ret = -ENOMEM;
3621 		goto done;
3622 	}
3623 
3624 	/* Fill request buffer */
3625 	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
3626 	country_code = &pcfg_misc->param.country_code;
3627 	pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
3628 	req->req_id = MLAN_IOCTL_MISC_CFG;
3629 
3630 	if (data_length <= 1) {
3631 		req->action = MLAN_ACT_GET;
3632 	} else {
3633 		memset(country_code->country_code, 0, COUNTRY_CODE_LEN);
3634 		moal_memcpy_ext(priv->phandle, country_code->country_code,
3635 				respbuf + header, COUNTRY_CODE_LEN,
3636 				COUNTRY_CODE_LEN);
3637 		req->action = MLAN_ACT_SET;
3638 	}
3639 
3640 	/* Send IOCTL request to MLAN */
3641 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3642 	if (status != MLAN_STATUS_SUCCESS) {
3643 		ret = -EFAULT;
3644 		goto done;
3645 	}
3646 
3647 	if (req->action == MLAN_ACT_GET) {
3648 		ret = data_length = COUNTRY_CODE_LEN;
3649 		memset(respbuf + header, 0, COUNTRY_CODE_LEN);
3650 		moal_memcpy_ext(priv->phandle, respbuf,
3651 				country_code->country_code, COUNTRY_CODE_LEN,
3652 				respbuflen);
3653 	}
3654 
3655 done:
3656 	if (status != MLAN_STATUS_PENDING)
3657 		kfree(req);
3658 
3659 	LEAVE();
3660 	return ret;
3661 }
3662 
3663 /**
3664  *  @brief Get cfp information
3665  *
3666  *  @param priv         A pointer to moal_private structure
3667  *  @param respbuf      A pointer to response buffer
3668  *  @param respbuflen   Available length of response buffer
3669  *
3670  *  @return             Number of bytes written, negative for failure.
3671  */
woal_priv_get_cfpinfo(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3672 static int woal_priv_get_cfpinfo(moal_private *priv, t_u8 *respbuf,
3673 				 t_u32 respbuflen)
3674 {
3675 	int ret = 0;
3676 	mlan_ioctl_req *req = NULL;
3677 	mlan_ds_misc_cfg *cfp_misc = NULL;
3678 	mlan_status status = MLAN_STATUS_SUCCESS;
3679 
3680 	ENTER();
3681 
3682 	if (!respbuf) {
3683 		PRINTM(MERROR, "response buffer is not available!\n");
3684 		ret = -EINVAL;
3685 		goto done;
3686 	}
3687 
3688 	/* Allocate an IOCTL request buffer */
3689 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3690 	if (req == NULL) {
3691 		ret = -ENOMEM;
3692 		goto done;
3693 	}
3694 
3695 	/* Fill request buffer */
3696 	cfp_misc = (mlan_ds_misc_cfg *)req->pbuf;
3697 	cfp_misc->sub_command = MLAN_OID_MISC_CFP_INFO;
3698 	req->req_id = MLAN_IOCTL_MISC_CFG;
3699 	req->action = MLAN_ACT_GET;
3700 
3701 	/* Send IOCTL request to MLAN */
3702 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3703 	if (status != MLAN_STATUS_SUCCESS) {
3704 		ret = -EFAULT;
3705 		goto done;
3706 	}
3707 	if (respbuflen < req->data_read_written) {
3708 		PRINTM(MERROR, "response buffer length is too short!\n");
3709 		ret = -EINVAL;
3710 		goto done;
3711 	}
3712 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)req->pbuf,
3713 			req->data_read_written, respbuflen);
3714 	ret = req->data_read_written;
3715 done:
3716 	if (status != MLAN_STATUS_PENDING)
3717 		kfree(req);
3718 
3719 	LEAVE();
3720 	return ret;
3721 }
3722 
3723 /**
3724  *  @brief Set/Get TCP Ack enhancement configurations
3725  *
3726  *  @param priv         A pointer to moal_private structure
3727  *  @param respbuf      A pointer to response buffer
3728  *  @param respbuflen   Available length of response buffer
3729  *
3730  *  @return             Number of bytes written, negative for failure.
3731  */
woal_priv_setgettcpackenh(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3732 static int woal_priv_setgettcpackenh(moal_private *priv, t_u8 *respbuf,
3733 				     t_u32 respbuflen)
3734 {
3735 	t_u32 data[2] = {0, 0};
3736 	int ret = 0;
3737 	int user_data_len = 0;
3738 
3739 	ENTER();
3740 	if (!priv || !priv->phandle) {
3741 		PRINTM(MERROR, "priv or handle is null\n");
3742 		ret = -EFAULT;
3743 		goto done;
3744 	}
3745 
3746 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TCPACKENH))) {
3747 		/* GET operation */
3748 		user_data_len = 0;
3749 	} else {
3750 		/* SET operation */
3751 		memset((char *)data, 0, sizeof(data));
3752 		parse_arguments(respbuf + strlen(CMD_NXP) +
3753 					strlen(PRIV_CMD_TCPACKENH),
3754 				data, ARRAY_SIZE(data), &user_data_len);
3755 	}
3756 
3757 	if (user_data_len == 0) {
3758 		/* get operation */
3759 		data[0] = priv->enable_tcp_ack_enh;
3760 		data[1] = priv->tcp_ack_max_hold;
3761 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
3762 				sizeof(data), respbuflen);
3763 		ret = sizeof(data);
3764 	} else {
3765 		/* set operation */
3766 		if (user_data_len >= 3) {
3767 			PRINTM(MERROR, "Too many arguments\n");
3768 			ret = -EINVAL;
3769 			goto done;
3770 		}
3771 		if (data[0] > 1 || data[1] > TCP_ACK_MAX_HOLD) {
3772 			PRINTM(MERROR, "Invalid argument\n");
3773 			ret = -EINVAL;
3774 			goto done;
3775 		}
3776 		if (data[0] == MTRUE) {
3777 			PRINTM(MINFO, "Enabling TCP Ack enhancement\n");
3778 			priv->enable_tcp_ack_enh = MTRUE;
3779 		} else if (data[0] == MFALSE) {
3780 			PRINTM(MINFO, "Disabling TCP Ack enhancement\n");
3781 			priv->enable_tcp_ack_enh = MFALSE;
3782 			/* release the tcp sessions if any */
3783 			woal_flush_tcp_sess_queue(priv);
3784 		}
3785 		if (user_data_len >= 2) {
3786 			PRINTM(MINFO, "TCP drop Ack configure: %d\n", data[1]);
3787 			priv->tcp_ack_max_hold = data[1];
3788 		}
3789 		data[0] = priv->enable_tcp_ack_enh;
3790 		data[1] = priv->tcp_ack_max_hold;
3791 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
3792 				sizeof(data), respbuflen);
3793 		ret = sizeof(data);
3794 	}
3795 
3796 done:
3797 	LEAVE();
3798 	return ret;
3799 }
3800 
3801 #ifdef REASSOCIATION
3802 /**
3803  *  @brief Set Asynced ESSID
3804  *
3805  *  @param priv         A pointer to moal_private structure
3806  *  @param respbuf      A pointer to response buffer
3807  *  @param respbuflen   Available length of response buffer
3808  *  @param bBSSID       A variable that bssid is set or not
3809  *
3810  *  @return             Number of bytes written, negative for failure.
3811  */
woal_priv_assocessid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,t_u8 bBSSID)3812 static int woal_priv_assocessid(moal_private *priv, t_u8 *respbuf,
3813 				t_u32 respbuflen, t_u8 bBSSID)
3814 {
3815 	mlan_ssid_bssid ssid_bssid;
3816 	moal_handle *handle = priv->phandle;
3817 	int ret = 0;
3818 	int header_len = 0;
3819 	int copy_len = 0;
3820 	char buf[64];
3821 	t_u8 buflen = 0;
3822 	t_u8 i = 0;
3823 	t_u8 mac_idx = 0;
3824 
3825 	ENTER();
3826 
3827 	if (bBSSID)
3828 		header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCBSSID);
3829 	else
3830 		header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCESSID);
3831 
3832 	if ((int)strlen(respbuf) == header_len) {
3833 		PRINTM(MERROR, "No argument, invalid operation!\n");
3834 		ret = -EINVAL;
3835 		LEAVE();
3836 		return ret;
3837 	}
3838 	copy_len = strlen(respbuf) - header_len;
3839 	buflen = MIN(copy_len, (int)(sizeof(buf) - 1));
3840 	memset(buf, 0, sizeof(buf));
3841 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
3842 	moal_memcpy_ext(handle, buf, respbuf + header_len, buflen, sizeof(buf));
3843 	priv->assoc_with_mac = MFALSE;
3844 
3845 	/* check if has parameter BSSID */
3846 	if (bBSSID) {
3847 		if (buflen < (3 * ETH_ALEN) + 2) {
3848 			PRINTM(MERROR,
3849 			       "Associate: Insufficient length in IOCTL input\n");
3850 			/* buffer should be at least 3 characters per BSSID
3851 			 *octet "00:"
3852 			 **   plus a space separater and at least 1 char in the
3853 			 *SSID
3854 			 */
3855 			ret = -EINVAL;
3856 			goto setessid_ret;
3857 		}
3858 		for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' ');
3859 		     i++) {
3860 			if (buf[i] == ':') {
3861 				mac_idx++;
3862 			} else {
3863 				ssid_bssid.bssid[mac_idx] =
3864 					(t_u8)woal_atox(buf + i);
3865 				while ((i < buflen) && isxdigit(buf[i + 1]))
3866 					/* Skip entire hex value */
3867 					i++;
3868 			}
3869 		}
3870 		/* Skip one space between the BSSID and start of the SSID */
3871 		i++;
3872 		PRINTM(MMSG, "Trying to associate AP BSSID = [" MACSTR "]\n",
3873 		       MAC2STR(ssid_bssid.bssid));
3874 		priv->assoc_with_mac = MTRUE;
3875 	}
3876 
3877 	ssid_bssid.ssid.ssid_len = buflen - i;
3878 	/* Check the size of the ssid_len */
3879 	if (ssid_bssid.ssid.ssid_len > MLAN_MAX_SSID_LENGTH + 1) {
3880 		PRINTM(MERROR, "ssid_bssid.ssid.ssid_len = %d\n",
3881 		       ssid_bssid.ssid.ssid_len);
3882 		ret = -E2BIG;
3883 		goto setessid_ret;
3884 	}
3885 
3886 	/* Copy the SSID */
3887 	moal_memcpy_ext(handle, ssid_bssid.ssid.ssid, buf + i,
3888 			ssid_bssid.ssid.ssid_len, MLAN_MAX_SSID_LENGTH);
3889 
3890 	if (!ssid_bssid.ssid.ssid_len ||
3891 	    (MFALSE == woal_ssid_valid(&ssid_bssid.ssid))) {
3892 		PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
3893 		ret = -EINVAL;
3894 		goto setessid_ret;
3895 	}
3896 
3897 	PRINTM(MMSG, "Trying to associate AP SSID = %s\n",
3898 	       (char *)ssid_bssid.ssid.ssid);
3899 
3900 	/* Cancel re-association */
3901 	priv->reassoc_required = MFALSE;
3902 
3903 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
3904 		PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
3905 		ret = -EBUSY;
3906 		LEAVE();
3907 		return ret;
3908 	}
3909 
3910 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
3911 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
3912 
3913 	if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
3914 		PRINTM(MIOCTL, "Already connect to the network\n");
3915 		ret = sprintf(respbuf,
3916 			      "Has already connected to this ESSID!\n") +
3917 		      1;
3918 		goto setessid_ret;
3919 	}
3920 	moal_memcpy_ext(handle, &priv->prev_ssid_bssid, &ssid_bssid,
3921 			sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid));
3922 	priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
3923 	priv->auto_assoc_priv.auto_assoc_trigger_flag =
3924 		AUTO_ASSOC_TYPE_DRV_ASSOC;
3925 	priv->auto_assoc_priv.drv_assoc.status = MTRUE;
3926 	if (priv->auto_assoc_priv.auto_assoc_type_on &
3927 	    (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC - 1))) {
3928 		PRINTM(MINFO, " auto assoc: trigger driver auto re-assoc\n");
3929 	} else {
3930 		PRINTM(MINFO, " Set Asynced ESSID: trigger auto re-assoc\n");
3931 	}
3932 	priv->reassoc_required = MTRUE;
3933 	priv->phandle->is_reassoc_timer_set = MTRUE;
3934 	woal_mod_timer(&priv->phandle->reassoc_timer, 0);
3935 	ret = sprintf(respbuf, "%s\n", buf) + 1;
3936 
3937 setessid_ret:
3938 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
3939 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
3940 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
3941 	LEAVE();
3942 	return ret;
3943 }
3944 #endif
3945 
3946 /**
3947  *  @brief Set/Get deep auto assoc configurations
3948  *
3949  *  @param priv         A pointer to moal_private structure
3950  *  @param respbuf      A pointer to response buffer
3951  *  @param respbuflen   Available length of response buffer
3952  *
3953  *  @return             Number of bytes written, negative for failure.
3954  */
woal_priv_setgetautoassoc(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3955 static int woal_priv_setgetautoassoc(moal_private *priv, t_u8 *respbuf,
3956 				     t_u32 respbuflen)
3957 {
3958 #ifdef REASSOCIATION
3959 	moal_handle *handle = priv->phandle;
3960 #endif
3961 	mlan_ioctl_req *req = NULL;
3962 	mlan_ds_misc_cfg *misc = NULL;
3963 	t_u32 data[5];
3964 	int ret = 0;
3965 	int user_data_len = 0;
3966 	mlan_status status = MLAN_STATUS_SUCCESS;
3967 
3968 	ENTER();
3969 
3970 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTOASSOC))) {
3971 		PRINTM(MERROR, "No argument, invalid operation!\n");
3972 		ret = -EINVAL;
3973 		goto done;
3974 	} else {
3975 		/* GET/SET operation */
3976 		memset((char *)data, 0, sizeof(data));
3977 		parse_arguments(respbuf + strlen(CMD_NXP) +
3978 					strlen(PRIV_CMD_AUTOASSOC),
3979 				data, ARRAY_SIZE(data), &user_data_len);
3980 	}
3981 
3982 	if (sizeof(t_u32) * user_data_len > sizeof(data)) {
3983 		PRINTM(MERROR, "Too many arguments\n");
3984 		ret = -EINVAL;
3985 		goto done;
3986 	}
3987 
3988 	if (data[0] != AUTO_ASSOC_TYPE_DRV_ASSOC &&
3989 	    data[0] != AUTO_ASSOC_TYPE_DRV_RECONN &&
3990 	    data[0] != AUTO_ASSOC_TYPE_FW_RECONN) {
3991 		PRINTM(MERROR, "Invalid auto assoc type option = %u\n",
3992 		       data[0]);
3993 		ret = -EINVAL;
3994 		goto done;
3995 	}
3996 
3997 	if (user_data_len == 1) {
3998 		/* Get operation */
3999 		if (data[0] == AUTO_ASSOC_TYPE_FW_RECONN) {
4000 			/* Get fw auto re-connect parameters */
4001 			req = woal_alloc_mlan_ioctl_req(
4002 				sizeof(mlan_ds_misc_cfg));
4003 			if (req == NULL) {
4004 				LEAVE();
4005 				return -ENOMEM;
4006 			}
4007 
4008 			misc = (mlan_ds_misc_cfg *)req->pbuf;
4009 			misc->sub_command = MLAN_OID_MISC_AUTO_ASSOC;
4010 			req->req_id = MLAN_IOCTL_MISC_CFG;
4011 			req->action = MLAN_ACT_GET;
4012 
4013 			status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4014 			if (status != MLAN_STATUS_SUCCESS) {
4015 				ret = -EFAULT;
4016 				if (status != MLAN_STATUS_PENDING)
4017 					kfree(req);
4018 				goto done;
4019 			} else {
4020 				data[2] = misc->param.fw_auto_reconnect
4021 						  .fw_reconn_counter;
4022 				if (data[2] == 0) {
4023 					data[1] = 0;
4024 					sprintf(respbuf, "%d %d", data[0],
4025 						data[1]);
4026 					ret = strlen(respbuf) + 1;
4027 				} else {
4028 					data[1] = 1;
4029 					data[3] = misc->param.fw_auto_reconnect
4030 							  .fw_reconn_interval;
4031 					data[4] = misc->param.fw_auto_reconnect
4032 							  .fw_reconn_flags;
4033 					sprintf(respbuf, "%d %d 0x%x 0x%x 0x%x",
4034 						data[0], data[1], data[2],
4035 						data[3], data[4]);
4036 					ret = strlen(respbuf) + 1;
4037 				}
4038 				kfree(req);
4039 			}
4040 		} else {
4041 			if (priv->auto_assoc_priv.auto_assoc_type_on &
4042 			    (0x1 << (data[0] - 1))) {
4043 				data[1] = 1;
4044 				if (data[0] == AUTO_ASSOC_TYPE_DRV_RECONN) {
4045 					/* Get driver auto re-connect parameters
4046 					 */
4047 					data[2] = priv->auto_assoc_priv
4048 							  .drv_reconnect
4049 							  .retry_count;
4050 					data[3] = priv->auto_assoc_priv
4051 							  .drv_reconnect
4052 							  .retry_interval;
4053 				} else {
4054 					/* Get driver auto assoc parameters */
4055 					data[2] =
4056 						priv->auto_assoc_priv.drv_assoc
4057 							.retry_count;
4058 					data[3] =
4059 						priv->auto_assoc_priv.drv_assoc
4060 							.retry_interval;
4061 				}
4062 				sprintf(respbuf, "%d %d 0x%x 0x%x", data[0],
4063 					data[1], data[2], data[3]);
4064 				ret = strlen(respbuf) + 1;
4065 			} else {
4066 				data[1] = 0;
4067 				sprintf(respbuf, "%d %d", data[0], data[1]);
4068 				ret = strlen(respbuf) + 1;
4069 			}
4070 		}
4071 	} else {
4072 		/* Set operation */
4073 		if (data[1] == MFALSE) {
4074 			/* Set Disable */
4075 			if (user_data_len > 2) {
4076 				PRINTM(MERROR,
4077 				       "Invalid number of arguments for setting Disable\n");
4078 				ret = -EINVAL;
4079 				goto done;
4080 			}
4081 			priv->auto_assoc_priv.auto_assoc_type_on &=
4082 				~(0x1 << (data[0] - 1));
4083 		} else if (data[1] == MTRUE) {
4084 			/* Set Enable */
4085 			if (user_data_len > 2) {
4086 				if (data[2] == 0 || data[2] > 0xFF) {
4087 					PRINTM(MERROR,
4088 					       "Invalid auto assoc retry count option = %u\n",
4089 					       data[2]);
4090 					ret = -EINVAL;
4091 					goto done;
4092 				}
4093 				if (user_data_len > 3) {
4094 					if (data[3] > 0xFF) {
4095 						PRINTM(MERROR,
4096 						       "Invalid auto assoc interval option = %u\n",
4097 						       data[3]);
4098 						ret = -EINVAL;
4099 						goto done;
4100 					}
4101 				} else {
4102 					data[3] = 0xa; /* Default retry
4103 							  interval: 10 seconds
4104 							*/
4105 				}
4106 			} else {
4107 				data[2] = 0xff; /* Default retry count: retry
4108 						   forever */
4109 				data[3] = 0xa; /* Default retry interval: 10
4110 						  seconds */
4111 			}
4112 			priv->auto_assoc_priv.auto_assoc_type_on |=
4113 				0x1 << (data[0] - 1);
4114 		} else {
4115 			PRINTM(MERROR,
4116 			       "Invalid auto assoc on/off option = %u\n",
4117 			       data[1]);
4118 			ret = -EINVAL;
4119 			goto done;
4120 		}
4121 
4122 		if (data[0] == AUTO_ASSOC_TYPE_FW_RECONN) {
4123 			/* Set fw auto re-connect operation */
4124 			if (user_data_len == 5) {
4125 				if (data[4] > 0x1) {
4126 					PRINTM(MERROR,
4127 					       "Invalid fw auto re-connect flag option = %u\n",
4128 					       data[4]);
4129 					ret = -EINVAL;
4130 					goto done;
4131 				}
4132 			} else {
4133 				data[4] = 0; /* Default fw auto re-connect flags
4134 					      */
4135 			}
4136 			req = woal_alloc_mlan_ioctl_req(
4137 				sizeof(mlan_ds_misc_cfg));
4138 			if (req == NULL) {
4139 				LEAVE();
4140 				return -ENOMEM;
4141 			}
4142 
4143 			misc = (mlan_ds_misc_cfg *)req->pbuf;
4144 			misc->sub_command = MLAN_OID_MISC_AUTO_ASSOC;
4145 			req->req_id = MLAN_IOCTL_MISC_CFG;
4146 			req->action = MLAN_ACT_SET;
4147 
4148 			if (data[1] == MFALSE) {
4149 				/* Set fw auto re-connect Disable */
4150 				misc->param.fw_auto_reconnect.fw_reconn_counter =
4151 					0;
4152 				misc->param.fw_auto_reconnect
4153 					.fw_reconn_interval = 0;
4154 				misc->param.fw_auto_reconnect.fw_reconn_flags =
4155 					0;
4156 			} else {
4157 				/* Set fw auto re-connect Enable */
4158 				misc->param.fw_auto_reconnect.fw_reconn_counter =
4159 					data[2];
4160 				misc->param.fw_auto_reconnect
4161 					.fw_reconn_interval = data[3];
4162 				misc->param.fw_auto_reconnect.fw_reconn_flags =
4163 					data[4];
4164 			}
4165 
4166 			status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4167 			if (status != MLAN_STATUS_SUCCESS) {
4168 				ret = -EFAULT;
4169 				if (status != MLAN_STATUS_PENDING)
4170 					kfree(req);
4171 				goto done;
4172 			} else {
4173 				kfree(req);
4174 			}
4175 		} else {
4176 			if (user_data_len == 5) {
4177 				PRINTM(MERROR,
4178 				       "The fifth parameter is only used for FW auto re-connect!\n");
4179 				ret = -EINVAL;
4180 				goto done;
4181 			}
4182 			if (data[0] == AUTO_ASSOC_TYPE_DRV_RECONN) {
4183 				/* Set driver auto re-connect operation */
4184 				if (data[1] == MFALSE) {
4185 					if (!(priv->auto_assoc_priv
4186 						      .auto_assoc_type_on &
4187 					      (0x1
4188 					       << (AUTO_ASSOC_TYPE_DRV_ASSOC -
4189 						   1)))) {
4190 						priv->auto_assoc_priv
4191 							.drv_reconnect.status =
4192 							MFALSE;
4193 #ifdef REASSOCIATION
4194 						handle->reassoc_on &=
4195 							~MBIT(priv->bss_index);
4196 						priv->reassoc_on = MFALSE;
4197 						priv->reassoc_required = MFALSE;
4198 						if (!handle->reassoc_on &&
4199 						    handle->is_reassoc_timer_set ==
4200 							    MTRUE) {
4201 							woal_cancel_timer(
4202 								&handle->reassoc_timer);
4203 							handle->is_reassoc_timer_set =
4204 								MFALSE;
4205 						}
4206 #endif
4207 					}
4208 				}
4209 #ifdef REASSOCIATION
4210 				else {
4211 					handle->reassoc_on |=
4212 						MBIT(priv->bss_index);
4213 					priv->reassoc_on = MTRUE;
4214 				}
4215 #endif
4216 				priv->auto_assoc_priv.drv_reconnect.retry_count =
4217 					data[2];
4218 				priv->auto_assoc_priv.drv_reconnect
4219 					.retry_interval = data[3];
4220 			}
4221 			if (data[0] == AUTO_ASSOC_TYPE_DRV_ASSOC) {
4222 				/* Set driver auto assoc operation */
4223 				if (data[1] == MFALSE) {
4224 					if (!(priv->auto_assoc_priv
4225 						      .auto_assoc_type_on &
4226 					      (0x1
4227 					       << (AUTO_ASSOC_TYPE_DRV_RECONN -
4228 						   1)))) {
4229 						priv->auto_assoc_priv.drv_assoc
4230 							.status = MFALSE;
4231 #ifdef REASSOCIATION
4232 						handle->reassoc_on &=
4233 							~MBIT(priv->bss_index);
4234 						priv->reassoc_on = MFALSE;
4235 						priv->reassoc_required = MFALSE;
4236 						if (!handle->reassoc_on &&
4237 						    handle->is_reassoc_timer_set ==
4238 							    MTRUE) {
4239 							woal_cancel_timer(
4240 								&handle->reassoc_timer);
4241 							handle->is_reassoc_timer_set =
4242 								MFALSE;
4243 						}
4244 #endif
4245 					}
4246 				}
4247 #ifdef REASSOCIATION
4248 				else {
4249 					handle->reassoc_on |=
4250 						MBIT(priv->bss_index);
4251 					priv->reassoc_on = MTRUE;
4252 				}
4253 #endif
4254 				priv->auto_assoc_priv.drv_assoc.retry_count =
4255 					data[2];
4256 				priv->auto_assoc_priv.drv_assoc.retry_interval =
4257 					data[3];
4258 			}
4259 		}
4260 		ret = sprintf(respbuf, "OK\n") + 1;
4261 	}
4262 
4263 done:
4264 	LEAVE();
4265 	return ret;
4266 }
4267 
4268 /**
4269  *  @brief Get wakeup reason
4270  *
4271  *  @param priv         A pointer to moal_private structure
4272  *  @param respbuf      A pointer to response buffer
4273  *  @param respbuflen   Available length of response buffer
4274  *
4275  *  @return             Number of bytes written, negative for failure.
4276  */
woal_priv_getwakeupreason(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4277 static int woal_priv_getwakeupreason(moal_private *priv, t_u8 *respbuf,
4278 				     t_u32 respbuflen)
4279 {
4280 	mlan_ioctl_req *req = NULL;
4281 	mlan_ds_pm_cfg *pm_cfg = NULL;
4282 	t_u32 data;
4283 	int ret = 0;
4284 	mlan_status status = MLAN_STATUS_SUCCESS;
4285 
4286 	ENTER();
4287 
4288 	if (strlen(respbuf) ==
4289 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_WAKEUPREASON))) {
4290 		/* GET operation */
4291 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
4292 		if (req == NULL) {
4293 			LEAVE();
4294 			return -ENOMEM;
4295 		}
4296 
4297 		pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
4298 		pm_cfg->sub_command = MLAN_OID_PM_HS_WAKEUP_REASON;
4299 		req->req_id = MLAN_IOCTL_PM_CFG;
4300 		req->action = MLAN_ACT_GET;
4301 
4302 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4303 		if (status != MLAN_STATUS_SUCCESS) {
4304 			ret = -EFAULT;
4305 			if (status != MLAN_STATUS_PENDING)
4306 				kfree(req);
4307 			goto done;
4308 		} else {
4309 			data = pm_cfg->param.wakeup_reason.hs_wakeup_reason;
4310 			sprintf(respbuf, " %d", data);
4311 			ret = strlen(respbuf) + 1;
4312 			kfree(req);
4313 		}
4314 	} else {
4315 		PRINTM(MERROR, "Not need argument, invalid operation!\n");
4316 		ret = -EINVAL;
4317 		goto done;
4318 	}
4319 
4320 done:
4321 	LEAVE();
4322 	return ret;
4323 }
4324 
4325 #ifdef STA_SUPPORT
4326 /**
4327  *  @brief Set / Get listen interval
4328  *
4329  *  @param priv         A pointer to moal_private structure
4330  *  @param respbuf      A pointer to response buffer
4331  *  @param respbuflen   Available length of response buffer
4332  *
4333  *  @return             Number of bytes written, negative for failure.
4334  */
woal_priv_set_get_listeninterval(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4335 static int woal_priv_set_get_listeninterval(moal_private *priv, t_u8 *respbuf,
4336 					    t_u32 respbuflen)
4337 {
4338 	int data[1];
4339 	int user_data_len = 0;
4340 	int ret = 0;
4341 	mlan_ioctl_req *req = NULL;
4342 	mlan_ds_bss *pcfg_bss = NULL;
4343 	mlan_status status = MLAN_STATUS_SUCCESS;
4344 
4345 	ENTER();
4346 
4347 	if (strlen(respbuf) ==
4348 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_LISTENINTERVAL))) {
4349 		/* GET operation */
4350 		user_data_len = 0;
4351 	} else {
4352 		/* SET operation */
4353 		memset((char *)data, 0, sizeof(data));
4354 		parse_arguments(respbuf + strlen(CMD_NXP) +
4355 					strlen(PRIV_CMD_LISTENINTERVAL),
4356 				data, ARRAY_SIZE(data), &user_data_len);
4357 	}
4358 
4359 	if (user_data_len > 1) {
4360 		PRINTM(MERROR, "Too many arguments\n");
4361 		ret = -EINVAL;
4362 		goto done;
4363 	}
4364 
4365 	/* Allocate an IOCTL request buffer */
4366 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4367 	if (req == NULL) {
4368 		ret = -ENOMEM;
4369 		goto done;
4370 	}
4371 
4372 	/* Fill request buffer */
4373 	pcfg_bss = (mlan_ds_bss *)req->pbuf;
4374 	pcfg_bss->sub_command = MLAN_OID_BSS_LISTEN_INTERVAL;
4375 	req->req_id = MLAN_IOCTL_BSS;
4376 
4377 	if (user_data_len) {
4378 		pcfg_bss->param.listen_interval = (t_u16)data[0];
4379 		req->action = MLAN_ACT_SET;
4380 	} else {
4381 		req->action = MLAN_ACT_GET;
4382 	}
4383 
4384 	/* Send IOCTL request to MLAN */
4385 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4386 	if (status != MLAN_STATUS_SUCCESS) {
4387 		ret = -EFAULT;
4388 		goto done;
4389 	}
4390 	if (req->action == MLAN_ACT_GET) {
4391 		sprintf(respbuf, "%d", pcfg_bss->param.listen_interval);
4392 		ret = strlen(respbuf) + 1;
4393 	} else {
4394 		ret = sprintf(respbuf, "OK\n") + 1;
4395 	}
4396 
4397 done:
4398 	if (status != MLAN_STATUS_PENDING)
4399 		kfree(req);
4400 
4401 	LEAVE();
4402 	return ret;
4403 }
4404 #endif
4405 
4406 #ifdef DEBUG_LEVEL1
4407 /**
4408  *  @brief Set / Get driver debug level
4409  *
4410  *  @param priv         A pointer to moal_private structure
4411  *  @param respbuf      A pointer to response buffer
4412  *  @param respbuflen   Available length of response buffer
4413  *
4414  *  @return             Number of bytes written, negative for failure.
4415  */
woal_priv_set_get_drvdbg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4416 static int woal_priv_set_get_drvdbg(moal_private *priv, t_u8 *respbuf,
4417 				    t_u32 respbuflen)
4418 {
4419 	int data[4];
4420 	int user_data_len = 0;
4421 	int ret = 0;
4422 
4423 	ENTER();
4424 
4425 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DRVDBG))) {
4426 		/* GET operation */
4427 		user_data_len = 0;
4428 	} else {
4429 		/* SET operation */
4430 		memset((char *)data, 0, sizeof(data));
4431 		parse_arguments(respbuf + strlen(CMD_NXP) +
4432 					strlen(PRIV_CMD_DRVDBG),
4433 				data, ARRAY_SIZE(data), &user_data_len);
4434 	}
4435 
4436 	if (user_data_len > 1) {
4437 		PRINTM(MERROR, "Too many arguments\n");
4438 		ret = -EINVAL;
4439 		goto done;
4440 	}
4441 
4442 	if (user_data_len) {
4443 		/* Get the driver debug bit masks from user */
4444 		drvdbg = data[0];
4445 		/* Set the driver debug bit masks into mlan */
4446 		if (woal_set_drvdbg(priv, drvdbg)) {
4447 			PRINTM(MERROR, "Set drvdbg failed!\n");
4448 			ret = MLAN_STATUS_FAILURE;
4449 			goto done;
4450 		}
4451 	}
4452 
4453 	ret = sizeof(drvdbg);
4454 
4455 	moal_memcpy_ext(priv->phandle, respbuf, &drvdbg, sizeof(drvdbg),
4456 			respbuflen);
4457 
4458 	printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
4459 #ifdef DEBUG_LEVEL2
4460 	printk(KERN_ALERT "MINFO  (%08x) %s\n", MINFO,
4461 	       (drvdbg & MINFO) ? "X" : "");
4462 	printk(KERN_ALERT "MWARN  (%08x) %s\n", MWARN,
4463 	       (drvdbg & MWARN) ? "X" : "");
4464 	printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
4465 	       (drvdbg & MENTRY) ? "X" : "");
4466 #endif
4467 	printk(KERN_ALERT "MMPA_D (%08x) %s\n", MMPA_D,
4468 	       (drvdbg & MMPA_D) ? "X" : "");
4469 	printk(KERN_ALERT "MIF_D  (%08x) %s\n", MIF_D,
4470 	       (drvdbg & MIF_D) ? "X" : "");
4471 	printk(KERN_ALERT "MFW_D  (%08x) %s\n", MFW_D,
4472 	       (drvdbg & MFW_D) ? "X" : "");
4473 	printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
4474 	       (drvdbg & MEVT_D) ? "X" : "");
4475 	printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
4476 	       (drvdbg & MCMD_D) ? "X" : "");
4477 	printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
4478 	       (drvdbg & MDAT_D) ? "X" : "");
4479 	printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D,
4480 	       (drvdbg & MREG_D) ? "X" : "");
4481 	printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
4482 	       (drvdbg & MIOCTL) ? "X" : "");
4483 	printk(KERN_ALERT "MINTR  (%08x) %s\n", MINTR,
4484 	       (drvdbg & MINTR) ? "X" : "");
4485 	printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
4486 	       (drvdbg & MEVENT) ? "X" : "");
4487 	printk(KERN_ALERT "MCMND  (%08x) %s\n", MCMND,
4488 	       (drvdbg & MCMND) ? "X" : "");
4489 	printk(KERN_ALERT "MDATA  (%08x) %s\n", MDATA,
4490 	       (drvdbg & MDATA) ? "X" : "");
4491 	printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
4492 	       (drvdbg & MERROR) ? "X" : "");
4493 	printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
4494 	       (drvdbg & MFATAL) ? "X" : "");
4495 	printk(KERN_ALERT "MMSG   (%08x) %s\n", MMSG,
4496 	       (drvdbg & MMSG) ? "X" : "");
4497 
4498 done:
4499 	LEAVE();
4500 	return ret;
4501 }
4502 
4503 #endif
4504 
4505 /**
4506  *  @brief management frame filter wakeup config
4507  *
4508  *  @param priv             A pointer to moal_private structure
4509  *  @param respbuf          A pointer to response buffer
4510  *  @param respbuflen       Available length of response buffer
4511  *
4512  *  @return             0 --success, otherwise fail
4513  */
woal_priv_mgmt_filter(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4514 static int woal_priv_mgmt_filter(moal_private *priv, t_u8 *respbuf,
4515 				 t_u32 respbuflen)
4516 {
4517 	mlan_ioctl_req *ioctl_req = NULL;
4518 	mlan_ds_pm_cfg *pm_cfg = NULL;
4519 	mlan_status status = MLAN_STATUS_SUCCESS;
4520 	int header_len = 0, data_len = 0;
4521 	int ret = 0;
4522 	t_u16 action;
4523 	t_u8 *argument;
4524 
4525 	ENTER();
4526 
4527 	if (!priv || !priv->phandle) {
4528 		PRINTM(MERROR, "priv or handle is null\n");
4529 		ret = -EFAULT;
4530 		goto done;
4531 	}
4532 
4533 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
4534 	if (ioctl_req == NULL) {
4535 		ret = -ENOMEM;
4536 		goto done;
4537 	}
4538 
4539 	pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
4540 	pm_cfg->sub_command = MLAN_OID_PM_MGMT_FILTER;
4541 	ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
4542 
4543 	header_len = strlen(PRIV_CMD_MGMT_FILTER) + strlen(CMD_NXP);
4544 
4545 	if ((int)strlen(respbuf) == header_len) {
4546 		/* GET operation */
4547 		action = MLAN_ACT_GET;
4548 	} else {
4549 		/* SET operation */
4550 		argument = (t_u8 *)(respbuf + header_len);
4551 		data_len = respbuflen - header_len;
4552 		if (data_len > (int)(MAX_MGMT_FRAME_FILTER *
4553 				     sizeof(mlan_mgmt_frame_wakeup))) {
4554 			PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
4555 			ret = -EINVAL;
4556 			goto done;
4557 		}
4558 		moal_memcpy_ext(priv->phandle,
4559 				(t_u8 *)pm_cfg->param.mgmt_filter, argument,
4560 				data_len, sizeof(pm_cfg->param.mgmt_filter));
4561 		action = MLAN_ACT_SET;
4562 	}
4563 
4564 	ioctl_req->action = action;
4565 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
4566 	if (status != MLAN_STATUS_SUCCESS) {
4567 		ret = -EFAULT;
4568 		goto done;
4569 	}
4570 
4571 done:
4572 	if (status != MLAN_STATUS_PENDING)
4573 		kfree(ioctl_req);
4574 
4575 	LEAVE();
4576 	return ret;
4577 }
4578 
4579 #define PARAMETER_GPIO_INDICATION 1
4580 #define PARAMETER_EXTEND_HSCFG 2
4581 #define PARAMETER_HS_WAKEUP_INTERVAL 3
4582 #define PARAMETER_MIN_WAKE_HOLDOFF 4
4583 /**
4584  *  @brief Set/Get Host Sleep configuration
4585  *
4586  *  @param priv             A pointer to moal_private structure
4587  *  @param respbuf          A pointer to response buffer
4588  *  @param respbuflen       Available length of response buffer
4589  *  @param invoke_hostcmd   MTRUE --invoke HostCmd, otherwise MFALSE
4590  *
4591  *  @return             0 --success, otherwise fail
4592  */
woal_priv_hscfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,BOOLEAN invoke_hostcmd)4593 static int woal_priv_hscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
4594 			   BOOLEAN invoke_hostcmd)
4595 {
4596 	int data[15] = {0};
4597 	int *temp_data, type;
4598 	int user_data_len = 0;
4599 	int ret = 0;
4600 	mlan_ds_hs_cfg hscfg, hscfg_temp;
4601 	t_u16 action;
4602 	mlan_bss_info bss_info;
4603 	int is_negative = MFALSE;
4604 	t_u8 *arguments = NULL;
4605 
4606 	ENTER();
4607 
4608 	memset(data, 0, sizeof(data));
4609 	memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
4610 	memset(&hscfg_temp, 0, sizeof(mlan_ds_hs_cfg));
4611 
4612 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG))) {
4613 		/* GET operation */
4614 		user_data_len = 0;
4615 	} else {
4616 		/* SET operation */
4617 		memset((char *)data, 0, sizeof(data));
4618 		arguments = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG);
4619 		if (*arguments == '-') {
4620 			is_negative = MTRUE;
4621 			arguments += 1;
4622 		}
4623 		parse_arguments(arguments, data, ARRAY_SIZE(data),
4624 				&user_data_len);
4625 
4626 		if (is_negative == MTRUE) {
4627 			if (data[0] == 1) {
4628 				data[0] = -1;
4629 			} else {
4630 				PRINTM(MERROR, "Invalid arguments\n");
4631 				ret = -EINVAL;
4632 				goto done;
4633 			}
4634 		}
4635 	}
4636 
4637 	if (sizeof(int) * user_data_len > sizeof(data)) {
4638 		PRINTM(MERROR, "Too many arguments\n");
4639 		LEAVE();
4640 		return -EINVAL;
4641 	}
4642 
4643 	if (user_data_len == 0) {
4644 		action = MLAN_ACT_GET;
4645 	} else {
4646 		if (user_data_len >= 1 && user_data_len <= 15) {
4647 			action = MLAN_ACT_SET;
4648 		} else {
4649 			PRINTM(MERROR, "Invalid arguments\n");
4650 			ret = -EINVAL;
4651 			goto done;
4652 		}
4653 	}
4654 
4655 	/* HS config is blocked if HS is already activated */
4656 	if (user_data_len && (data[0] != (int)HOST_SLEEP_CFG_CANCEL ||
4657 			      invoke_hostcmd == MFALSE)) {
4658 		memset(&bss_info, 0, sizeof(bss_info));
4659 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
4660 		if (bss_info.is_hs_configured) {
4661 			PRINTM(MERROR, "HS already configured\n");
4662 			ret = -EFAULT;
4663 			goto done;
4664 		}
4665 	}
4666 
4667 	/* Do a GET first if some arguments are not provided */
4668 	if (user_data_len >= 1 && user_data_len < 11) {
4669 		woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
4670 				       &hscfg_temp);
4671 	}
4672 	hscfg.conditions = hscfg_temp.conditions;
4673 	hscfg.gpio = hscfg_temp.gpio;
4674 	hscfg.gap = hscfg_temp.gap;
4675 
4676 	if (user_data_len)
4677 		hscfg.conditions = data[0];
4678 	if (user_data_len >= 2)
4679 		hscfg.gpio = data[1];
4680 	if (user_data_len >= 3)
4681 		hscfg.gap = data[2];
4682 	user_data_len = user_data_len - 3;
4683 	if (user_data_len > 0) {
4684 		temp_data = data + 3;
4685 		while ((user_data_len > 0) && temp_data) {
4686 			type = *temp_data;
4687 			switch (type) {
4688 			case PARAMETER_GPIO_INDICATION:
4689 				if (user_data_len >= 2)
4690 					hscfg.ind_gpio = *(++temp_data);
4691 				else {
4692 					PRINTM(MERROR,
4693 					       "Invaild number of parameters\n");
4694 					ret = -EINVAL;
4695 					goto done;
4696 				}
4697 				if (user_data_len >= 3) {
4698 					hscfg.level = *(++temp_data);
4699 					if (hscfg.level != 0 &&
4700 					    hscfg.level != 1) {
4701 						PRINTM(MERROR,
4702 						       "Invalid indication gpio arguments\n");
4703 						ret = -EINVAL;
4704 						goto done;
4705 					}
4706 				}
4707 				hscfg.param_type_ind = type;
4708 				user_data_len = user_data_len - 3;
4709 				temp_data++;
4710 				break;
4711 			case PARAMETER_EXTEND_HSCFG:
4712 				if (user_data_len >= 4) {
4713 					hscfg.event_force_ignore =
4714 						*(++temp_data);
4715 					hscfg.event_use_ext_gap =
4716 						*(++temp_data);
4717 					hscfg.ext_gap = *(++temp_data);
4718 					hscfg.gpio_wave = *(++temp_data);
4719 				} else {
4720 					PRINTM(MERROR,
4721 					       "Invaild number of parameters\n");
4722 					ret = -EINVAL;
4723 					goto done;
4724 				}
4725 				/* Force_ignore_gpio and ext_gap_gpio should not
4726 				 * set the same bit(s)*/
4727 				if ((hscfg.event_force_ignore &
4728 				     hscfg.event_use_ext_gap) ||
4729 				    (hscfg.gpio_wave != 1 &&
4730 				     hscfg.gpio_wave != 0)) {
4731 					PRINTM(MERROR,
4732 					       "Invalid arguments for extend hscfg\n");
4733 					ret = -EINVAL;
4734 					goto done;
4735 				}
4736 				hscfg.param_type_ext = type;
4737 				user_data_len = user_data_len - 5;
4738 				temp_data++;
4739 				break;
4740 			case PARAMETER_HS_WAKEUP_INTERVAL:
4741 				if (user_data_len >= 2)
4742 					hscfg.hs_wake_interval = *(++temp_data);
4743 				else {
4744 					PRINTM(MERROR,
4745 					       "Invaild number of parameters\n");
4746 					ret = -EINVAL;
4747 					goto done;
4748 				}
4749 				user_data_len = user_data_len - 2;
4750 				temp_data++;
4751 				break;
4752 			case PARAMETER_MIN_WAKE_HOLDOFF:
4753 				if (user_data_len >= 2)
4754 					hscfg.min_wake_holdoff = *(++temp_data);
4755 				else {
4756 					PRINTM(MERROR,
4757 					       "Invaild number of parameters\n");
4758 					ret = -EINVAL;
4759 					goto done;
4760 				}
4761 				user_data_len = user_data_len - 2;
4762 				temp_data++;
4763 				break;
4764 			default:
4765 				PRINTM(MERROR, "Unsupported type\n");
4766 				ret = -EINVAL;
4767 				goto done;
4768 			}
4769 		}
4770 	}
4771 
4772 	if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
4773 		/* Need to issue an extra IOCTL first to set up parameters */
4774 		hscfg.is_invoke_hostcmd = MFALSE;
4775 		if (MLAN_STATUS_SUCCESS !=
4776 		    woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
4777 					   &hscfg)) {
4778 			ret = -EFAULT;
4779 			goto done;
4780 		}
4781 	}
4782 	hscfg.is_invoke_hostcmd = invoke_hostcmd;
4783 	if (MLAN_STATUS_SUCCESS !=
4784 	    woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
4785 		ret = -EFAULT;
4786 		goto done;
4787 	}
4788 
4789 	if (action == MLAN_ACT_GET) {
4790 		/* Return the current driver host sleep configurations */
4791 		moal_memcpy_ext(priv->phandle, respbuf, &hscfg,
4792 				sizeof(mlan_ds_hs_cfg), respbuflen);
4793 		ret = sizeof(mlan_ds_hs_cfg);
4794 	}
4795 done:
4796 	LEAVE();
4797 	return ret;
4798 }
4799 
4800 /**
4801  *  @brief Process Set Host Sleep parameters from proc buffer
4802  *
4803  *  @param handle       A pointer to moal_handle structure
4804  *  @param pbuf         A pointer to buffer for host sleep parameters
4805  *  @param respbuflen   Available length of response buffer
4806  *
4807  *  @return             0 --success, otherwise fail
4808  */
woal_process_proc_hssetpara(moal_handle * handle,t_u8 * buf)4809 int woal_process_proc_hssetpara(moal_handle *handle, t_u8 *buf)
4810 {
4811 	int data[15] = {0};
4812 	int user_data_len = 0;
4813 	int ret = 0;
4814 	t_u8 respbuf[500];
4815 	moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
4816 
4817 	ENTER();
4818 	if (!priv) {
4819 		LEAVE();
4820 		return ret;
4821 	}
4822 	memset((char *)data, 0, sizeof(data));
4823 	parse_arguments(buf, data, ARRAY_SIZE(data), &user_data_len);
4824 	if (sizeof(int) * user_data_len > sizeof(data)) {
4825 		PRINTM(MERROR, "Too many arguments\n");
4826 		LEAVE();
4827 		return -EINVAL;
4828 	}
4829 	if (user_data_len >= 1 && user_data_len <= 15) {
4830 		sprintf(respbuf, "%s%s%s", CMD_NXP, PRIV_CMD_HSCFG, buf);
4831 		ret = woal_priv_hscfg(priv, respbuf, sizeof(respbuf), MFALSE);
4832 	}
4833 	LEAVE();
4834 	return ret;
4835 }
4836 
4837 /**
4838  *  @brief Set Host Sleep parameters
4839  *
4840  *  @param priv         A pointer to moal_private structure
4841  *  @param respbuf      A pointer to response buffer
4842  *  @param respbuflen   Available length of response buffer
4843  *
4844  *  @return             0 --success, otherwise fail
4845  */
woal_priv_hssetpara(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4846 static int woal_priv_hssetpara(moal_private *priv, t_u8 *respbuf,
4847 			       t_u32 respbuflen)
4848 {
4849 	int data[15] = {0};
4850 	int user_data_len = 0;
4851 	int ret = 0;
4852 
4853 	ENTER();
4854 
4855 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA))) {
4856 		PRINTM(MERROR, "Invalid arguments\n");
4857 		ret = -EINVAL;
4858 		goto done;
4859 	} else {
4860 		/* SET operation */
4861 		memset((char *)data, 0, sizeof(data));
4862 		parse_arguments(respbuf + strlen(CMD_NXP) +
4863 					strlen(PRIV_CMD_HSSETPARA),
4864 				data, ARRAY_SIZE(data), &user_data_len);
4865 	}
4866 
4867 	if (sizeof(int) * user_data_len > sizeof(data)) {
4868 		PRINTM(MERROR, "Too many arguments\n");
4869 		LEAVE();
4870 		return -EINVAL;
4871 	}
4872 
4873 	if (user_data_len >= 1 && user_data_len <= 15) {
4874 		sprintf(respbuf, "%s%s%s", CMD_NXP, PRIV_CMD_HSCFG,
4875 			respbuf +
4876 				(strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA)));
4877 		respbuflen = strlen(respbuf);
4878 		ret = woal_priv_hscfg(priv, respbuf, respbuflen, MFALSE);
4879 		goto done;
4880 	}
4881 done:
4882 	LEAVE();
4883 	return ret;
4884 }
4885 
4886 /**
4887  * @brief Set/Get scan configuration parameters
4888  *
4889  * @param priv         A pointer to moal_private structure
4890  * @param respbuf      A pointer to response buffer
4891  * @param respbuflen   Available length of response buffer
4892  *
4893  * @return         0 --success, otherwise fail
4894  */
woal_priv_set_get_scancfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4895 static int woal_priv_set_get_scancfg(moal_private *priv, t_u8 *respbuf,
4896 				     t_u32 respbuflen)
4897 {
4898 	int ret = 0;
4899 	int user_data_len = 0;
4900 	int data[9];
4901 	mlan_ds_scan *scan = NULL;
4902 	mlan_ioctl_req *req = NULL;
4903 	mlan_status status = MLAN_STATUS_SUCCESS;
4904 
4905 	ENTER();
4906 
4907 	memset(data, 0, sizeof(data));
4908 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_SCANCFG))) {
4909 		/* GET operation */
4910 		user_data_len = 0;
4911 	} else {
4912 		/* SET operation */
4913 		memset((char *)data, 0, sizeof(data));
4914 		parse_arguments(respbuf + strlen(CMD_NXP) +
4915 					strlen(PRIV_CMD_SCANCFG),
4916 				data, ARRAY_SIZE(data), &user_data_len);
4917 	}
4918 
4919 	if (sizeof(int) * user_data_len > sizeof(data)) {
4920 		PRINTM(MERROR, "Too many arguments\n");
4921 		LEAVE();
4922 		return -EINVAL;
4923 	}
4924 
4925 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
4926 	if (req == NULL) {
4927 		ret = -ENOMEM;
4928 		goto done;
4929 	}
4930 	scan = (mlan_ds_scan *)req->pbuf;
4931 	scan->sub_command = MLAN_OID_SCAN_CONFIG;
4932 	req->req_id = MLAN_IOCTL_SCAN;
4933 
4934 	if (user_data_len) {
4935 		moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
4936 				sizeof(data), sizeof(scan->param.scan_cfg));
4937 		if (scan->param.scan_cfg.scan_type > MLAN_SCAN_TYPE_PASSIVE) {
4938 			PRINTM(MERROR, "Invalid argument for scan type\n");
4939 			ret = -EINVAL;
4940 			goto done;
4941 		}
4942 		if (scan->param.scan_cfg.scan_mode > MLAN_SCAN_MODE_ANY) {
4943 			PRINTM(MERROR, "Invalid argument for scan mode\n");
4944 			ret = -EINVAL;
4945 			goto done;
4946 		}
4947 		if (scan->param.scan_cfg.scan_probe > MAX_PROBES) {
4948 			PRINTM(MERROR, "Invalid argument for scan probes\n");
4949 			ret = -EINVAL;
4950 			goto done;
4951 		}
4952 		if ((scan->param.scan_cfg.scan_time.specific_scan_time >
4953 		     MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) ||
4954 		    (scan->param.scan_cfg.scan_time.active_scan_time >
4955 		     MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) ||
4956 		    (scan->param.scan_cfg.scan_time.passive_scan_time >
4957 		     MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME)) {
4958 			PRINTM(MERROR, "Invalid argument for scan time\n");
4959 			ret = -EINVAL;
4960 			goto done;
4961 		}
4962 		if (scan->param.scan_cfg.passive_to_active_scan >
4963 		    MLAN_PASS_TO_ACT_SCAN_DIS) {
4964 			PRINTM(MERROR,
4965 			       "Invalid argument for Passive to Active Scan\n");
4966 			ret = -EINVAL;
4967 			goto done;
4968 		}
4969 		if (scan->param.scan_cfg.ext_scan > MLAN_EXT_SCAN_ENH) {
4970 			PRINTM(MERROR, "Invalid argument for extended scan\n");
4971 			ret = -EINVAL;
4972 			goto done;
4973 		}
4974 		if (scan->param.scan_cfg.scan_chan_gap >
4975 		    MRVDRV_MAX_SCAN_CHAN_GAP_TIME) {
4976 			PRINTM(MERROR,
4977 			       "Invalid argument for scan channel gap\n");
4978 			ret = -EINVAL;
4979 			goto done;
4980 		}
4981 
4982 		req->action = MLAN_ACT_SET;
4983 		moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
4984 				sizeof(data), sizeof(scan->param.scan_cfg));
4985 	} else
4986 		req->action = MLAN_ACT_GET;
4987 
4988 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4989 	if (status != MLAN_STATUS_SUCCESS) {
4990 		ret = -EFAULT;
4991 		goto done;
4992 	}
4993 	moal_memcpy_ext(priv->phandle, respbuf, &scan->param.scan_cfg,
4994 			sizeof(mlan_scan_cfg), respbuflen);
4995 	ret = sizeof(mlan_scan_cfg);
4996 done:
4997 	if (status != MLAN_STATUS_PENDING)
4998 		kfree(req);
4999 	LEAVE();
5000 	return ret;
5001 }
5002 
5003 /**
5004  * @brief Get Netlink Number
5005  *
5006  * @param priv         A pointer to moal_private structure
5007  * @param respbuf      A pointer to response buffer
5008  * @param respbuflen   Available length of response buffer
5009  *
5010  * @return         Number of bytes written, negative for failure.
5011  */
woal_priv_getnlnum(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5012 static int woal_priv_getnlnum(moal_private *priv, t_u8 *respbuf,
5013 			      t_u32 respbuflen)
5014 {
5015 	int ret = 0;
5016 	int data = 0;
5017 
5018 	ENTER();
5019 
5020 	if (!priv || !priv->phandle) {
5021 		PRINTM(MERROR, "priv or handle is null in %s\n", __FUNCTION__);
5022 		ret = -EFAULT;
5023 		goto done;
5024 	}
5025 
5026 	data = priv->phandle->netlink_num;
5027 	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
5028 			respbuflen);
5029 	ret = sizeof(data);
5030 
5031 done:
5032 	LEAVE();
5033 	return ret;
5034 }
5035 
5036 /**
5037  *  @brief Set / Get packet aggregation control
5038  *
5039  *  @param priv         A pointer to moal_private structure
5040  *  @param respbuf      A pointer to response buffer
5041  *  @param respbuflen   Available length of response buffer
5042  *
5043  *  @return             Number of bytes written, negative for failure.
5044  */
woal_priv_set_get_aggrctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5045 static int woal_priv_set_get_aggrctrl(moal_private *priv, t_u8 *respbuf,
5046 				      t_u32 respbuflen)
5047 {
5048 	int data[1];
5049 	int user_data_len = 0;
5050 	int ret = 0;
5051 	mlan_ioctl_req *req = NULL;
5052 	mlan_ds_misc_cfg *pcfg_misc = NULL;
5053 	moal_handle *handle = priv->phandle;
5054 	mlan_status status = MLAN_STATUS_SUCCESS;
5055 
5056 	ENTER();
5057 
5058 	if (!handle || !handle->card) {
5059 		PRINTM(MERROR, "Handle or card is null\n");
5060 		ret = -EFAULT;
5061 		goto done;
5062 	}
5063 
5064 	memset((char *)data, 0, sizeof(data));
5065 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRCTRL))) {
5066 		/* GET operation */
5067 		user_data_len = 0;
5068 	} else {
5069 		if (woal_is_any_interface_active(priv->phandle)) {
5070 			PRINTM(MERROR,
5071 			       "aggrctrl are not allowed to change after BSS active!\n");
5072 			ret = -EFAULT;
5073 			goto done;
5074 		}
5075 		/* SET operation */
5076 		parse_arguments(respbuf + strlen(CMD_NXP) +
5077 					strlen(PRIV_CMD_AGGRCTRL),
5078 				data, ARRAY_SIZE(data), &user_data_len);
5079 
5080 		if (sizeof(int) * user_data_len > sizeof(data)) {
5081 			PRINTM(MERROR, "Too many arguments\n");
5082 			ret = -EINVAL;
5083 			goto done;
5084 		}
5085 	}
5086 
5087 	/* Allocate an IOCTL request buffer */
5088 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
5089 	if (req == NULL) {
5090 		ret = -ENOMEM;
5091 		goto done;
5092 	}
5093 
5094 	/* Fill request buffer */
5095 	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
5096 	pcfg_misc->sub_command = MLAN_OID_MISC_AGGR_CTRL;
5097 	req->req_id = MLAN_IOCTL_MISC_CFG;
5098 
5099 	/* Get the values first, then modify these values if user had modified
5100 	 * them */
5101 	if (user_data_len == 0)
5102 		req->action = MLAN_ACT_GET;
5103 	else {
5104 		req->action = MLAN_ACT_SET;
5105 		pcfg_misc->param.aggr_params.tx.enable = (t_u16)data[0];
5106 	}
5107 
5108 	/* Send IOCTL request to MLAN */
5109 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5110 	if (status != MLAN_STATUS_SUCCESS) {
5111 		/* MLAN will return CMD_INVALID if FW does not support this
5112 		 * feature */
5113 		if (MLAN_ERROR_CMD_INVALID == req->status_code)
5114 			ret = -EOPNOTSUPP;
5115 		else
5116 			ret = -EFAULT;
5117 		goto done;
5118 	}
5119 
5120 	moal_memcpy_ext(handle, respbuf, (t_u8 *)&pcfg_misc->param.aggr_params,
5121 			sizeof(mlan_ds_misc_aggr_ctrl), respbuflen);
5122 	ret = sizeof(mlan_ds_misc_aggr_ctrl);
5123 done:
5124 	if (status != MLAN_STATUS_PENDING)
5125 		kfree(req);
5126 
5127 	LEAVE();
5128 	return ret;
5129 }
5130 
5131 #ifdef USB
5132 /**
5133  *  @brief Set / Get USB packet aggregation control
5134  *
5135  *  @param priv         A pointer to moal_private structure
5136  *  @param respbuf      A pointer to response buffer
5137  *  @param respbuflen   Available length of response buffer
5138  *
5139  *  @return             Number of bytes written, negative for failure.
5140  */
woal_priv_set_get_usbaggrctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5141 static int woal_priv_set_get_usbaggrctrl(moal_private *priv, t_u8 *respbuf,
5142 					 t_u32 respbuflen)
5143 {
5144 	int data[8];
5145 	int user_data_len = 0;
5146 	int ret = 0;
5147 	mlan_ioctl_req *req = NULL;
5148 	mlan_ds_misc_cfg *pcfg_misc = NULL;
5149 	moal_handle *handle = priv->phandle;
5150 	struct usb_card_rec *cardp = NULL;
5151 	int i = 0, usb_resubmit_urbs = 0;
5152 	mlan_status status = MLAN_STATUS_SUCCESS;
5153 
5154 	ENTER();
5155 
5156 	if (!handle || !handle->card) {
5157 		PRINTM(MERROR, "Handle or card is null\n");
5158 		ret = -EFAULT;
5159 		goto done;
5160 	}
5161 	cardp = (struct usb_card_rec *)handle->card;
5162 
5163 	memset((char *)data, 0, sizeof(data));
5164 	if (strlen(respbuf) ==
5165 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_USBAGGRCTRL))) {
5166 		/* GET operation */
5167 		user_data_len = 0;
5168 	} else {
5169 		/* SET operation */
5170 		parse_arguments(respbuf + strlen(CMD_NXP) +
5171 					strlen(PRIV_CMD_USBAGGRCTRL),
5172 				data, ARRAY_SIZE(data), &user_data_len);
5173 
5174 		if (sizeof(int) * user_data_len > sizeof(data)) {
5175 			PRINTM(MERROR, "Too many arguments\n");
5176 			ret = -EINVAL;
5177 			goto done;
5178 		}
5179 	}
5180 
5181 	/* Allocate an IOCTL request buffer */
5182 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
5183 	if (req == NULL) {
5184 		ret = -ENOMEM;
5185 		goto done;
5186 	}
5187 
5188 	/* Fill request buffer */
5189 	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
5190 	pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
5191 	req->req_id = MLAN_IOCTL_MISC_CFG;
5192 
5193 	/* Get the values first, then modify these values if user had modified
5194 	 * them */
5195 	req->action = MLAN_ACT_GET;
5196 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5197 	if (status != MLAN_STATUS_SUCCESS) {
5198 		/* MLAN will return CMD_INVALID if FW does not support this
5199 		 * feature */
5200 		if (MLAN_ERROR_CMD_INVALID == req->status_code)
5201 			ret = -EOPNOTSUPP;
5202 		else
5203 			ret = -EFAULT;
5204 		goto done;
5205 	}
5206 
5207 	if (user_data_len == 0) {
5208 		moal_memcpy_ext(handle, respbuf,
5209 				(t_u8 *)&pcfg_misc->param.usb_aggr_params,
5210 				sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
5211 		ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);
5212 		goto done;
5213 	}
5214 
5215 	switch (user_data_len) {
5216 	case 8:
5217 		if (data[7] < 0) {
5218 			PRINTM(MERROR, "Invalid Rx timeout value (%d)\n",
5219 			       data[7]);
5220 			ret = -EINVAL;
5221 			goto done;
5222 		}
5223 		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_tmo =
5224 			(t_u16)data[7];
5225 		/* fall through */
5226 	case 7:
5227 		if (data[6] < 0 || (data[6] > 10000 &&
5228 				    data[6] != MLAN_USB_TX_AGGR_TIMEOUT_DYN)) {
5229 			PRINTM(MERROR, "Invalid Tx timeout value (%d)\n",
5230 			       data[6]);
5231 			ret = -EINVAL;
5232 			goto done;
5233 		}
5234 		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_tmo =
5235 			(t_u16)data[6];
5236 		/* fall through */
5237 	case 6:
5238 		if ((data[5] < 512) || ((data[5] % 512) != 0)) {
5239 			PRINTM(MERROR, "Invalid Rx alignment value (%d)\n",
5240 			       data[5]);
5241 			ret = -EINVAL;
5242 			goto done;
5243 		}
5244 		if (cardp->rx_deaggr_ctrl.enable &&
5245 		    pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align !=
5246 			    (t_u16)data[5])
5247 			usb_resubmit_urbs = 1;
5248 		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align =
5249 			(t_u16)data[5];
5250 		/* fall through */
5251 	case 5:
5252 		if ((data[4] < 2048) || ((data[4] % 2048) != 0)) {
5253 			PRINTM(MERROR, "Invalid Tx alignment value (%d)\n",
5254 			       data[4]);
5255 			ret = -EINVAL;
5256 			goto done;
5257 		}
5258 		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_align =
5259 			(t_u16)data[4];
5260 		/* fall through */
5261 	case 4:
5262 		if ((data[3] == 2) || (data[3] == 4) || (data[3] == 8) ||
5263 		    (data[3] == 16)) {
5264 			pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
5265 				.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
5266 		} else if ((data[3] == 4096) || (data[3] == 8192) ||
5267 			   (data[3] == 16384) || (data[3] == 32768)) {
5268 			pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
5269 				.aggr_mode = MLAN_USB_AGGR_MODE_LEN;
5270 		} else {
5271 			PRINTM(MERROR, "Invalid Rx max size/num value (%d)\n",
5272 			       data[3]);
5273 			ret = -EINVAL;
5274 			goto done;
5275 		}
5276 		if (cardp->rx_deaggr_ctrl.enable &&
5277 		    pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max !=
5278 			    (t_u16)data[3])
5279 			usb_resubmit_urbs = 1;
5280 		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max =
5281 			(t_u16)data[3];
5282 		/* fall through */
5283 	case 3:
5284 		if ((data[2] == 2) || (data[2] == 4) || (data[2] == 8) ||
5285 		    (data[2] == 16)) {
5286 			pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
5287 				MLAN_USB_AGGR_MODE_NUM;
5288 		} else if ((data[2] == 4096) || (data[2] == 8192) ||
5289 			   (data[2] == 16384) || (data[2] == 32768)) {
5290 			pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
5291 				MLAN_USB_AGGR_MODE_LEN;
5292 		} else {
5293 			PRINTM(MERROR, "Invalid Tx max size/num value (%d)\n",
5294 			       data[2]);
5295 			ret = -EINVAL;
5296 			goto done;
5297 		}
5298 		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_max =
5299 			(t_u16)data[2];
5300 		/* fall through */
5301 	case 2:
5302 		if ((data[1] != 0) && (data[1] != 1)) {
5303 			PRINTM(MERROR, "Invalid Rx enable value (%d)\n",
5304 			       data[1]);
5305 			ret = -EINVAL;
5306 			goto done;
5307 		}
5308 		if (pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable !=
5309 		    (t_u16)data[1])
5310 			usb_resubmit_urbs = 1;
5311 		pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable =
5312 			(t_u16)data[1];
5313 		/* fall through */
5314 	case 1:
5315 		if ((data[0] != 0) && (data[0] != 1)) {
5316 			PRINTM(MERROR, "Invalid Tx enable value (%d)\n",
5317 			       data[0]);
5318 			ret = -EINVAL;
5319 			goto done;
5320 		}
5321 		pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.enable =
5322 			(t_u16)data[0];
5323 	default:
5324 		break;
5325 	}
5326 
5327 	pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
5328 	req->req_id = MLAN_IOCTL_MISC_CFG;
5329 	req->action = MLAN_ACT_SET;
5330 
5331 	/* Send IOCTL request to MLAN */
5332 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5333 	if (status != MLAN_STATUS_SUCCESS) {
5334 		ret = -EFAULT;
5335 		goto done;
5336 	}
5337 
5338 	moal_memcpy_ext(handle, respbuf,
5339 			(t_u8 *)&pcfg_misc->param.usb_aggr_params,
5340 			sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
5341 	ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);
5342 
5343 	/* Keep a copy of the latest Tx aggregation parameters in MOAL */
5344 	moal_memcpy_ext(handle, &cardp->tx_aggr_ctrl,
5345 			&pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl,
5346 			sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg));
5347 
5348 	if (usb_resubmit_urbs) {
5349 		/* Indicate resubmition from here */
5350 		cardp->resubmit_urbs = 1;
5351 		/* Rx SG parameters has changed or disabled, kill the URBs, they
5352 		   will be resubmitted after saving the parameters to USB card
5353 		 */
5354 		if (atomic_read(&cardp->rx_data_urb_pending)) {
5355 			for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
5356 				if (cardp->rx_data_list[i].urb) {
5357 					usb_kill_urb(
5358 						cardp->rx_data_list[i].urb);
5359 					usb_init_urb(
5360 						cardp->rx_data_list[i].urb);
5361 				}
5362 			}
5363 		}
5364 	}
5365 
5366 	/* Keep a copy of the latest Rx deaggregation parameters in MOAL */
5367 	moal_memcpy_ext(handle, &cardp->rx_deaggr_ctrl,
5368 			&pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl,
5369 			sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg));
5370 
5371 	if (usb_resubmit_urbs) {
5372 		/* Ensure the next data URBs will use the modified parameters */
5373 		if (!atomic_read(&cardp->rx_data_urb_pending)) {
5374 			/* Submit multiple Rx data URBs */
5375 			woal_usb_submit_rx_data_urbs(handle);
5376 		}
5377 		cardp->resubmit_urbs = 0;
5378 	}
5379 
5380 done:
5381 	if (status != MLAN_STATUS_PENDING)
5382 		kfree(req);
5383 
5384 	LEAVE();
5385 	return ret;
5386 }
5387 #endif
5388 
5389 #ifdef STA_SUPPORT
5390 /**
5391  * @brief Set AP settings
5392  *
5393  * @param priv         A pointer to moal_private structure
5394  * @param respbuf      A pointer to response buffer
5395  * @param respbuflen   Available length of response buffer
5396  *
5397  * @return         Number of bytes written if successful, otherwise fail
5398  */
woal_priv_set_ap(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5399 static int woal_priv_set_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
5400 {
5401 	int ret = 0;
5402 	t_u8 *data_ptr;
5403 	const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {255, 255, 255, 255, 255, 255};
5404 	const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
5405 	mlan_ssid_bssid ssid_bssid;
5406 	mlan_bss_info bss_info;
5407 	struct mwreq *mwr;
5408 	struct sockaddr *awrq;
5409 
5410 	ENTER();
5411 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AP));
5412 
5413 	mwr = (struct mwreq *)data_ptr;
5414 
5415 	if (mwr->u.ap_addr.sa_family != ARPHRD_ETHER) {
5416 		ret = -EINVAL;
5417 		goto done;
5418 	}
5419 
5420 	awrq = (struct sockaddr *)&(mwr->u.ap_addr);
5421 
5422 	PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
5423 	       MAC2STR((t_u8 *)awrq->sa_data));
5424 
5425 	if (MLAN_STATUS_SUCCESS !=
5426 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5427 		ret = -EFAULT;
5428 		goto done;
5429 	}
5430 
5431 #ifdef REASSOCIATION
5432 	/* Cancel re-association */
5433 	priv->reassoc_required = MFALSE;
5434 #endif
5435 
5436 	/* zero_mac means disconnect */
5437 	if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
5438 		woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
5439 				DEF_DEAUTH_REASON_CODE);
5440 		goto done;
5441 	}
5442 
5443 	/* Broadcast MAC means search for best network */
5444 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
5445 
5446 	if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
5447 		/* Check if we are already assoicated to the AP */
5448 		if (bss_info.media_connected == MTRUE) {
5449 			if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
5450 				goto done;
5451 		}
5452 		moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, awrq->sa_data,
5453 				ETH_ALEN, sizeof(mlan_802_11_mac_addr));
5454 	}
5455 
5456 	if (MLAN_STATUS_SUCCESS !=
5457 	    woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
5458 		PRINTM(MERROR,
5459 		       "ASSOC: WAP: MAC address not found in BSSID List\n");
5460 		ret = -ENETUNREACH;
5461 		goto done;
5462 	}
5463 	/* Zero SSID implies use BSSID to connect */
5464 	memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
5465 	if (MLAN_STATUS_SUCCESS !=
5466 	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
5467 		ret = -EFAULT;
5468 		goto done;
5469 	}
5470 
5471 #ifdef REASSOCIATION
5472 	memset(&bss_info, 0, sizeof(bss_info));
5473 	if (MLAN_STATUS_SUCCESS !=
5474 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5475 		ret = -EFAULT;
5476 		goto done;
5477 	}
5478 	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
5479 			&bss_info.ssid, sizeof(mlan_802_11_ssid),
5480 			sizeof(mlan_802_11_ssid));
5481 	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
5482 			&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
5483 			sizeof(mlan_802_11_mac_addr));
5484 #endif /* REASSOCIATION */
5485 
5486 done:
5487 	LEAVE();
5488 	return ret;
5489 }
5490 #endif
5491 
5492 /**
5493  * @brief Set BSS mode
5494  *
5495  * @param priv         A pointer to moal_private structure
5496  * @param respbuf      A pointer to response buffer
5497  * @param respbuflen   Available length of response buffer
5498  *
5499  * @return         Number of bytes written if successful, otherwise fail
5500  */
woal_priv_set_bss_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5501 static int woal_priv_set_bss_mode(moal_private *priv, t_u8 *respbuf,
5502 				  t_u32 respbuflen)
5503 {
5504 	int ret = 0;
5505 	mlan_ds_bss *bss = NULL;
5506 	mlan_ioctl_req *req = NULL;
5507 	struct mwreq *mwr;
5508 	t_u8 *data_ptr;
5509 	t_u32 mode;
5510 	mlan_status status = MLAN_STATUS_SUCCESS;
5511 
5512 	ENTER();
5513 
5514 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_BSS_MODE));
5515 
5516 	mwr = (struct mwreq *)data_ptr;
5517 	mode = mwr->u.mode;
5518 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
5519 	if (req == NULL) {
5520 		ret = -ENOMEM;
5521 		goto done;
5522 	}
5523 	bss = (mlan_ds_bss *)req->pbuf;
5524 	bss->sub_command = MLAN_OID_BSS_MODE;
5525 	req->req_id = MLAN_IOCTL_BSS;
5526 	req->action = MLAN_ACT_SET;
5527 
5528 	switch (mode) {
5529 	case MW_MODE_INFRA:
5530 		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
5531 		break;
5532 	case MW_MODE_ADHOC:
5533 		bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
5534 		break;
5535 	case MW_MODE_AUTO:
5536 		bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
5537 		break;
5538 	default:
5539 		ret = -EINVAL;
5540 		break;
5541 	}
5542 	if (ret)
5543 		goto done;
5544 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5545 	if (status != MLAN_STATUS_SUCCESS) {
5546 		ret = -EFAULT;
5547 		goto done;
5548 	}
5549 done:
5550 	if (status != MLAN_STATUS_PENDING)
5551 		kfree(req);
5552 	LEAVE();
5553 	return ret;
5554 }
5555 
5556 #ifdef STA_SUPPORT
5557 /**
5558  * @brief Set power management
5559  *
5560  * @param priv         A pointer to moal_private structure
5561  * @param respbuf      A pointer to response buffer
5562  * @param respbuflen   Available length of response buffer
5563  *
5564  * @return         Number of bytes written if successful, otherwise fail
5565  */
woal_priv_set_power(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5566 static int woal_priv_set_power(moal_private *priv, t_u8 *respbuf,
5567 			       t_u32 respbuflen)
5568 {
5569 	struct mwreq *mwr;
5570 	t_u8 *data_ptr;
5571 	int ret = 0, disabled;
5572 
5573 	ENTER();
5574 
5575 	if (moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
5576 		PRINTM(MIOCTL, "block set power in hw_test mode\n");
5577 		LEAVE();
5578 		return ret;
5579 	}
5580 
5581 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_POWER));
5582 
5583 	mwr = (struct mwreq *)data_ptr;
5584 	disabled = mwr->u.power.disabled;
5585 
5586 	if (MLAN_STATUS_SUCCESS !=
5587 	    woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled,
5588 				    mwr->u.power.flags, MOAL_IOCTL_WAIT)) {
5589 		return -EFAULT;
5590 	}
5591 	LEAVE();
5592 	return ret;
5593 }
5594 
5595 /**
5596  *  @brief Set essid
5597  *
5598  * @param priv         A pointer to moal_private structure
5599  * @param respbuf      A pointer to response buffer
5600  * @param respbuflen   Available length of response buffer
5601  *
5602  * @return         Number of bytes written if successful, otherwise fail
5603  */
woal_priv_set_essid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5604 static int woal_priv_set_essid(moal_private *priv, t_u8 *respbuf,
5605 			       t_u32 respbuflen)
5606 {
5607 	mlan_802_11_ssid req_ssid;
5608 	mlan_ssid_bssid ssid_bssid;
5609 	moal_handle *handle = priv->phandle;
5610 #ifdef REASSOCIATION
5611 	mlan_bss_info bss_info;
5612 #endif
5613 	int ret = 0;
5614 	t_u32 mode = 0;
5615 	struct mwreq *mwr;
5616 	t_u8 *data_ptr;
5617 
5618 	ENTER();
5619 
5620 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_ESSID));
5621 
5622 	mwr = (struct mwreq *)data_ptr;
5623 
5624 #ifdef REASSOCIATION
5625 	/* Cancel re-association */
5626 	priv->reassoc_required = MFALSE;
5627 
5628 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
5629 		PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
5630 		LEAVE();
5631 		return -EBUSY;
5632 	}
5633 #endif /* REASSOCIATION */
5634 
5635 	/* Check the size of the string */
5636 	if (mwr->u.essid.length > MW_ESSID_MAX_SIZE - 1) {
5637 		ret = -E2BIG;
5638 		goto setessid_ret;
5639 	}
5640 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5641 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
5642 	memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
5643 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
5644 
5645 	req_ssid.ssid_len = mwr->u.essid.length;
5646 
5647 	/* Check if we asked for 'any' or 'particular' */
5648 	if (!mwr->u.essid.flags) {
5649 #ifdef REASSOCIATION
5650 		if (!req_ssid.ssid_len) {
5651 			memset(&priv->prev_ssid_bssid.ssid, 0x00,
5652 			       sizeof(mlan_802_11_ssid));
5653 			memset(&priv->prev_ssid_bssid.bssid, 0x00,
5654 			       MLAN_MAC_ADDR_LENGTH);
5655 			goto setessid_ret;
5656 		}
5657 #endif
5658 		/* Do normal SSID scanning */
5659 		if (MLAN_STATUS_SUCCESS !=
5660 		    woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
5661 			ret = -EFAULT;
5662 			goto setessid_ret;
5663 		}
5664 	} else {
5665 		/* Set the SSID */
5666 		moal_memcpy_ext(handle, req_ssid.ssid, mwr->u.essid.pointer,
5667 				req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH);
5668 		if (!req_ssid.ssid_len ||
5669 		    (MFALSE == woal_ssid_valid(&req_ssid))) {
5670 			PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
5671 			ret = -EINVAL;
5672 			goto setessid_ret;
5673 		}
5674 
5675 		PRINTM(MINFO, "Requested new SSID = %s\n",
5676 		       (char *)req_ssid.ssid);
5677 		moal_memcpy_ext(handle, &ssid_bssid.ssid, &req_ssid,
5678 				sizeof(mlan_802_11_ssid),
5679 				sizeof(mlan_802_11_ssid));
5680 		if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
5681 			PRINTM(MIOCTL, "Already connect to the network\n");
5682 			goto setessid_ret;
5683 		}
5684 
5685 		priv->auto_assoc_priv.drv_assoc.status = MFALSE;
5686 		priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
5687 #ifdef REASSOCIATION
5688 		if (priv->reassoc_on == MTRUE) {
5689 			if (priv->auto_assoc_priv.auto_assoc_type_on &
5690 			    (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC - 1))) {
5691 				if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5692 					woal_set_scan_type(
5693 						priv, MLAN_SCAN_TYPE_PASSIVE);
5694 				MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
5695 				moal_memcpy_ext(handle,
5696 						&priv->prev_ssid_bssid.ssid,
5697 						&req_ssid,
5698 						sizeof(mlan_802_11_ssid),
5699 						sizeof(mlan_802_11_ssid));
5700 				priv->auto_assoc_priv.auto_assoc_trigger_flag =
5701 					AUTO_ASSOC_TYPE_DRV_ASSOC;
5702 				priv->auto_assoc_priv.drv_assoc.status = MTRUE;
5703 				priv->reassoc_required = MTRUE;
5704 				priv->phandle->is_reassoc_timer_set = MTRUE;
5705 				PRINTM(MINFO,
5706 				       " auto assoc: trigger driver auto re-assoc\n");
5707 				woal_mod_timer(&priv->phandle->reassoc_timer,
5708 					       0);
5709 				ret = MLAN_STATUS_SUCCESS;
5710 
5711 				LEAVE();
5712 				return ret;
5713 			}
5714 		}
5715 #endif
5716 
5717 		if (mwr->u.essid.flags != 0xFFFF) {
5718 			if (MLAN_STATUS_SUCCESS !=
5719 			    woal_find_essid(priv, &ssid_bssid,
5720 					    MOAL_IOCTL_WAIT)) {
5721 				/* Do specific SSID scanning */
5722 				if (MLAN_STATUS_SUCCESS !=
5723 				    woal_request_scan(priv, MOAL_IOCTL_WAIT,
5724 						      &req_ssid)) {
5725 					ret = -EFAULT;
5726 					goto setessid_ret;
5727 				}
5728 			}
5729 		}
5730 	}
5731 
5732 	mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
5733 
5734 	if (mode != MW_MODE_ADHOC) {
5735 		if (MLAN_STATUS_SUCCESS !=
5736 		    woal_find_best_network(priv, MOAL_IOCTL_WAIT,
5737 					   &ssid_bssid)) {
5738 			ret = -EFAULT;
5739 			goto setessid_ret;
5740 		}
5741 	}
5742 #ifdef UAP_SUPPORT
5743 	else if (MLAN_STATUS_SUCCESS !=
5744 		 woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
5745 		/* Adhoc start, Check the channel command */
5746 		woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
5747 #endif
5748 
5749 	/* Connect to BSS by ESSID */
5750 	memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
5751 
5752 	if (MLAN_STATUS_SUCCESS !=
5753 	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
5754 		ret = -EFAULT;
5755 		goto setessid_ret;
5756 	}
5757 
5758 #ifdef REASSOCIATION
5759 	memset(&bss_info, 0, sizeof(bss_info));
5760 	if (MLAN_STATUS_SUCCESS !=
5761 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5762 		ret = -EFAULT;
5763 		goto setessid_ret;
5764 	}
5765 	moal_memcpy_ext(handle, &priv->prev_ssid_bssid.ssid, &bss_info.ssid,
5766 			sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
5767 	moal_memcpy_ext(handle, &priv->prev_ssid_bssid.bssid, &bss_info.bssid,
5768 			MLAN_MAC_ADDR_LENGTH, sizeof(mlan_802_11_mac_addr));
5769 #endif /* REASSOCIATION */
5770 
5771 setessid_ret:
5772 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5773 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
5774 #ifdef REASSOCIATION
5775 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
5776 #endif
5777 	LEAVE();
5778 	return ret;
5779 }
5780 
5781 /**
5782  *  @brief Set authentication mode parameters
5783  *
5784  * @param priv         A pointer to moal_private structure
5785  * @param respbuf      A pointer to response buffer
5786  * @param respbuflen   Available length of response buffer
5787  *
5788  * @return         Number of bytes written if successful, otherwise fail
5789  */
woal_priv_set_auth(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5790 static int woal_priv_set_auth(moal_private *priv, t_u8 *respbuf,
5791 			      t_u32 respbuflen)
5792 {
5793 	struct mwreq *mwr;
5794 	t_u8 *data_ptr;
5795 	int ret = 0;
5796 	t_u32 auth_mode = 0;
5797 	t_u32 encrypt_mode = 0;
5798 
5799 	ENTER();
5800 
5801 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AUTH));
5802 
5803 	mwr = (struct mwreq *)data_ptr;
5804 
5805 	switch (mwr->u.param.flags & MW_AUTH_INDEX) {
5806 	case MW_AUTH_CIPHER_PAIRWISE:
5807 	case MW_AUTH_CIPHER_GROUP:
5808 		if (mwr->u.param.value & MW_AUTH_CIPHER_NONE)
5809 			encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
5810 		else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP40)
5811 			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
5812 		else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP104)
5813 			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
5814 		else if (mwr->u.param.value & MW_AUTH_CIPHER_TKIP)
5815 			encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
5816 		else if (mwr->u.param.value & MW_AUTH_CIPHER_CCMP)
5817 			encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
5818 		if (MLAN_STATUS_SUCCESS !=
5819 		    woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
5820 			ret = -EFAULT;
5821 		break;
5822 	case MW_AUTH_80211_AUTH_ALG:
5823 		switch (mwr->u.param.value) {
5824 		case MW_AUTH_ALG_SHARED_KEY:
5825 			PRINTM(MINFO, "Auth mode shared key!\n");
5826 			auth_mode = MLAN_AUTH_MODE_SHARED;
5827 			break;
5828 		case MW_AUTH_ALG_LEAP:
5829 			PRINTM(MINFO, "Auth mode LEAP!\n");
5830 			auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
5831 			break;
5832 		case MW_AUTH_ALG_OPEN_SYSTEM:
5833 			PRINTM(MINFO, "Auth mode open!\n");
5834 			auth_mode = MLAN_AUTH_MODE_OPEN;
5835 			break;
5836 		case MW_AUTH_ALG_SHARED_KEY | MW_AUTH_ALG_OPEN_SYSTEM:
5837 		default:
5838 			PRINTM(MINFO, "Auth mode auto!\n");
5839 			auth_mode = MLAN_AUTH_MODE_AUTO;
5840 			break;
5841 		}
5842 		if (MLAN_STATUS_SUCCESS !=
5843 		    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
5844 			ret = -EFAULT;
5845 		break;
5846 	case MW_AUTH_WPA_ENABLED:
5847 		if (MLAN_STATUS_SUCCESS !=
5848 		    woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT,
5849 					mwr->u.param.value))
5850 			ret = -EFAULT;
5851 		break;
5852 #define MW_AUTH_WAPI_ENABLED 0x20
5853 	case MW_AUTH_WAPI_ENABLED:
5854 		if (MLAN_STATUS_SUCCESS !=
5855 		    woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT,
5856 					 mwr->u.param.value))
5857 			ret = -EFAULT;
5858 		break;
5859 	case MW_AUTH_WPA_VERSION:
5860 		/* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
5861 		priv->wpa_version = mwr->u.param.value;
5862 		break;
5863 	case MW_AUTH_KEY_MGMT:
5864 		/* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
5865 		priv->key_mgmt = mwr->u.param.value;
5866 		break;
5867 	case MW_AUTH_TKIP_COUNTERMEASURES:
5868 	case MW_AUTH_DROP_UNENCRYPTED:
5869 	case MW_AUTH_RX_UNENCRYPTED_EAPOL:
5870 	case MW_AUTH_ROAMING_CONTROL:
5871 	case MW_AUTH_PRIVACY_INVOKED:
5872 		break;
5873 	default:
5874 		ret = -EOPNOTSUPP;
5875 		break;
5876 	}
5877 	LEAVE();
5878 	return ret;
5879 }
5880 
5881 /**
5882  *  @brief Get current BSSID
5883  *
5884  * @param priv         A pointer to moal_private structure
5885  * @param respbuf      A pointer to response buffer
5886  * @param respbuflen   Available length of response buffer
5887  *
5888  * @return         Number of bytes written if successful else negative value
5889  */
woal_priv_get_ap(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5890 static int woal_priv_get_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
5891 {
5892 	struct mwreq *mwr;
5893 	t_u8 *data_ptr;
5894 	int ret = 0;
5895 	mlan_bss_info bss_info;
5896 
5897 	ENTER();
5898 
5899 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP));
5900 
5901 	mwr = (struct mwreq *)data_ptr;
5902 
5903 	memset(&bss_info, 0, sizeof(bss_info));
5904 
5905 	ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
5906 	if (ret != MLAN_STATUS_SUCCESS)
5907 		return -EFAULT;
5908 
5909 	if (bss_info.media_connected == MTRUE) {
5910 		moal_memcpy_ext(priv->phandle, mwr->u.ap_addr.sa_data,
5911 				&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
5912 				sizeof(mwr->u.ap_addr.sa_data));
5913 	} else {
5914 		memset(mwr->u.ap_addr.sa_data, 0, MLAN_MAC_ADDR_LENGTH);
5915 	}
5916 	mwr->u.ap_addr.sa_family = ARPHRD_ETHER;
5917 	ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP) + sizeof(struct mwreq);
5918 
5919 	LEAVE();
5920 	return ret;
5921 }
5922 
5923 /**
5924  *  @brief  Get power management
5925  *
5926  * @param priv         A pointer to moal_private structure
5927  * @param respbuf      A pointer to response buffer
5928  * @param respbuflen   Available length of response buffer
5929  *
5930  * @return         Number of bytes written if successful else negative value
5931  */
woal_priv_get_power(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5932 static int woal_priv_get_power(moal_private *priv, t_u8 *respbuf,
5933 			       t_u32 respbuflen)
5934 {
5935 	struct mwreq *mwr;
5936 	t_u8 *data_ptr;
5937 	int ret = 0, ps_mode;
5938 
5939 	ENTER();
5940 
5941 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER));
5942 
5943 	mwr = (struct mwreq *)data_ptr;
5944 
5945 	if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
5946 							   &ps_mode, 0,
5947 							   MOAL_IOCTL_WAIT)) {
5948 		return -EFAULT;
5949 	}
5950 
5951 	if (ps_mode)
5952 		mwr->u.power.disabled = 0;
5953 	else
5954 		mwr->u.power.disabled = 1;
5955 
5956 	mwr->u.power.value = 0;
5957 	ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER) +
5958 	      sizeof(struct mwreq);
5959 	LEAVE();
5960 	return ret;
5961 }
5962 
5963 /**
5964  * @brief Set/Get power save mode
5965  *
5966  * @param priv         A pointer to moal_private structure
5967  * @param respbuf      A pointer to response buffer
5968  * @param respbuflen   Available length of response buffer
5969  *
5970  * @return         0 --success, otherwise fail
5971  */
woal_priv_set_get_psmode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5972 static int woal_priv_set_get_psmode(moal_private *priv, t_u8 *respbuf,
5973 				    t_u32 respbuflen)
5974 {
5975 	int ret = 0;
5976 	int data = 0;
5977 	int user_data_len = 0, header_len = 0;
5978 	t_u32 action = MLAN_ACT_GET;
5979 
5980 	ENTER();
5981 
5982 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSMODE);
5983 
5984 	if ((int)strlen(respbuf) == header_len) {
5985 		/* GET operation */
5986 		user_data_len = 0;
5987 		action = MLAN_ACT_GET;
5988 	} else {
5989 		/* SET operation */
5990 		parse_arguments(respbuf + header_len, &data,
5991 				sizeof(data) / sizeof(int), &user_data_len);
5992 		action = MLAN_ACT_SET;
5993 	}
5994 
5995 	if (sizeof(int) * user_data_len > sizeof(data)) {
5996 		PRINTM(MERROR, "Too many arguments\n");
5997 		ret = -EINVAL;
5998 		goto done;
5999 	}
6000 
6001 	if (data != 0 && data != 1) {
6002 		PRINTM(MERROR, "Invalid psmode=%d\n", data);
6003 		ret = -EINVAL;
6004 		goto done;
6005 	}
6006 
6007 	/* Flip the value */
6008 	data = !data;
6009 
6010 	if (MLAN_STATUS_SUCCESS !=
6011 	    woal_set_get_power_mgmt(priv, action, &data, 0, MOAL_IOCTL_WAIT)) {
6012 		ret = -EFAULT;
6013 		goto done;
6014 	}
6015 
6016 	if (action == MLAN_ACT_SET)
6017 		data = !data;
6018 
6019 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
6020 			respbuflen);
6021 	ret = sizeof(data);
6022 
6023 done:
6024 	LEAVE();
6025 	return ret;
6026 }
6027 #endif /* STA_SUPPORT */
6028 
6029 /**
6030  * @brief Performs warm reset
6031  *
6032  * @param priv         A pointer to moal_private structure
6033  * @param respbuf      A pointer to response buffer
6034  * @param respbuflen   Available length of response buffer
6035  *
6036  * @return         Number of bytes written if successful else negative value
6037  */
woal_priv_warmreset(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6038 static int woal_priv_warmreset(moal_private *priv, t_u8 *respbuf,
6039 			       t_u32 respbuflen)
6040 {
6041 	int ret = 0;
6042 	moal_handle *handle = priv->phandle;
6043 	moal_handle *ref_handle;
6044 	moal_private *ref_priv;
6045 	ENTER();
6046 	ret = woal_pre_warmreset(priv);
6047 	if (ret)
6048 		goto done;
6049 	ref_handle = (moal_handle *)handle->pref_mac;
6050 	if (ref_handle) {
6051 		ref_priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
6052 		if (ref_priv) {
6053 			ret = woal_pre_warmreset(ref_priv);
6054 			if (ret)
6055 				goto done;
6056 			ret = woal_warmreset(ref_priv);
6057 			if (ret)
6058 				goto done;
6059 		}
6060 	}
6061 	ret = woal_warmreset(priv);
6062 done:
6063 	LEAVE();
6064 	return ret;
6065 }
6066 
6067 /**
6068  *  @brief Set/Get TX power configurations
6069  *
6070  *  @param priv         A pointer to moal_private structure
6071  *  @param respbuf      A pointer to response buffer
6072  *  @param respbuflen   Available length of response buffer
6073  *
6074  *  @return         0 --success, otherwise fail
6075  */
woal_priv_txpowercfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6076 static int woal_priv_txpowercfg(moal_private *priv, t_u8 *respbuf,
6077 				t_u32 respbuflen)
6078 {
6079 	int data[5];
6080 	int user_data_len;
6081 	int ret = 0;
6082 	mlan_bss_info bss_info;
6083 	mlan_ds_power_cfg *pcfg = NULL;
6084 	mlan_ioctl_req *req = NULL;
6085 	t_u8 *arguments = NULL;
6086 	mlan_status status = MLAN_STATUS_SUCCESS;
6087 	ENTER();
6088 
6089 	memset(data, 0, sizeof(data));
6090 	memset(&bss_info, 0, sizeof(bss_info));
6091 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
6092 
6093 	if (strlen(respbuf) ==
6094 	    (strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG))) {
6095 		/* GET operation */
6096 		user_data_len = 0;
6097 	} else {
6098 		/* SET operation */
6099 		arguments =
6100 			respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG);
6101 		parse_arguments(arguments, data, ARRAY_SIZE(data),
6102 				&user_data_len);
6103 	}
6104 
6105 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
6106 	if (req == NULL) {
6107 		ret = -ENOMEM;
6108 		goto done;
6109 	}
6110 	pcfg = (mlan_ds_power_cfg *)req->pbuf;
6111 	pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
6112 	req->req_id = MLAN_IOCTL_POWER_CFG;
6113 
6114 	if (!user_data_len)
6115 		req->action = MLAN_ACT_GET;
6116 	else {
6117 		/* SET operation */
6118 		req->action = MLAN_ACT_SET;
6119 		if (sizeof(int) * user_data_len > sizeof(data)) {
6120 			PRINTM(MERROR, "Too many arguments\n");
6121 			ret = -EINVAL;
6122 			goto done;
6123 		}
6124 		switch (user_data_len) {
6125 		case 1:
6126 			if (data[0] == 0xFF)
6127 				pcfg->param.power_ext.power_group[0]
6128 					.rate_format = TX_PWR_CFG_AUTO_CTRL_OFF;
6129 			else
6130 				ret = -EINVAL;
6131 			break;
6132 		case 3:
6133 		case 5:
6134 			switch (data[0]) {
6135 			case 0: /* LG */
6136 				pcfg->param.power_ext.power_group[0]
6137 					.rate_format = MLAN_RATE_FORMAT_LG;
6138 				pcfg->param.power_ext.power_group[0].bandwidth =
6139 					MLAN_HT_BW20;
6140 				break;
6141 			case 1: /* 20 MHz HT */
6142 				pcfg->param.power_ext.power_group[0]
6143 					.rate_format = MLAN_RATE_FORMAT_HT;
6144 				pcfg->param.power_ext.power_group[0].bandwidth =
6145 					MLAN_HT_BW20;
6146 				break;
6147 			case 2: /* 40 MHz HT */
6148 				pcfg->param.power_ext.power_group[0]
6149 					.rate_format = MLAN_RATE_FORMAT_HT;
6150 				pcfg->param.power_ext.power_group[0].bandwidth =
6151 					MLAN_HT_BW40;
6152 				break;
6153 			case 3: /* 1 NSS 20 MHZ VHT */
6154 				pcfg->param.power_ext.power_group[0]
6155 					.rate_format = MLAN_RATE_FORMAT_VHT;
6156 				pcfg->param.power_ext.power_group[0].bandwidth =
6157 					MLAN_HT_BW20;
6158 				pcfg->param.power_ext.power_group[0].nss = 1;
6159 				break;
6160 			case 4: /* 2 NSS 20 MHZ VHT */
6161 				pcfg->param.power_ext.power_group[0]
6162 					.rate_format = MLAN_RATE_FORMAT_VHT;
6163 				pcfg->param.power_ext.power_group[0].bandwidth =
6164 					MLAN_HT_BW20;
6165 				pcfg->param.power_ext.power_group[0].nss = 2;
6166 				break;
6167 			case 5: /* 1 NSS 40 MHZ VHT */
6168 				pcfg->param.power_ext.power_group[0]
6169 					.rate_format = MLAN_RATE_FORMAT_VHT;
6170 				pcfg->param.power_ext.power_group[0].bandwidth =
6171 					MLAN_HT_BW40;
6172 				pcfg->param.power_ext.power_group[0].nss = 1;
6173 				break;
6174 			case 6: /* 2 NSS 40 MHZ VHT */
6175 				pcfg->param.power_ext.power_group[0]
6176 					.rate_format = MLAN_RATE_FORMAT_VHT;
6177 				pcfg->param.power_ext.power_group[0].bandwidth =
6178 					MLAN_HT_BW40;
6179 				pcfg->param.power_ext.power_group[0].nss = 2;
6180 				break;
6181 			case 7: /* 1 NSS 80 MHZ VHT */
6182 				pcfg->param.power_ext.power_group[0]
6183 					.rate_format = MLAN_RATE_FORMAT_VHT;
6184 				pcfg->param.power_ext.power_group[0].bandwidth =
6185 					MLAN_VHT_BW80;
6186 				pcfg->param.power_ext.power_group[0].nss = 1;
6187 				break;
6188 			case 8: /* 2 NSS 80 MHZ VHT */
6189 				pcfg->param.power_ext.power_group[0]
6190 					.rate_format = MLAN_RATE_FORMAT_VHT;
6191 				pcfg->param.power_ext.power_group[0].bandwidth =
6192 					MLAN_VHT_BW80;
6193 				pcfg->param.power_ext.power_group[0].nss = 2;
6194 				break;
6195 			default:
6196 				ret = -EINVAL;
6197 				break;
6198 			}
6199 			pcfg->param.power_ext.power_group[0].first_rate_ind =
6200 				data[1];
6201 			pcfg->param.power_ext.power_group[0].last_rate_ind =
6202 				data[1];
6203 			if (data[2] < bss_info.min_power_level) {
6204 				PRINTM(MERROR,
6205 				       "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
6206 				       data[2], (int)bss_info.min_power_level,
6207 				       (int)bss_info.max_power_level);
6208 				ret = -EINVAL;
6209 				break;
6210 			}
6211 			if (data[2] > bss_info.max_power_level) {
6212 				PRINTM(MERROR,
6213 				       "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
6214 				       data[2], (int)bss_info.min_power_level,
6215 				       (int)bss_info.max_power_level);
6216 				ret = -EINVAL;
6217 				break;
6218 			}
6219 			pcfg->param.power_ext.power_group[0].power_min =
6220 				data[2];
6221 			pcfg->param.power_ext.power_group[0].power_max =
6222 				data[2];
6223 			pcfg->param.power_ext.power_group[0].power_step = 0;
6224 			pcfg->param.power_ext.num_pwr_grp = 1;
6225 
6226 			break;
6227 		default:
6228 			ret = -EINVAL;
6229 			break;
6230 		}
6231 		if (ret)
6232 			goto done;
6233 	}
6234 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6235 	if (status != MLAN_STATUS_SUCCESS) {
6236 		ret = -EFAULT;
6237 		goto done;
6238 	}
6239 	if (!user_data_len) {
6240 		/* GET operation */
6241 		moal_memcpy_ext(priv->phandle, respbuf,
6242 				(t_u8 *)&pcfg->param.power_ext,
6243 				sizeof(pcfg->param.power_ext.num_pwr_grp) +
6244 					(MIN(pcfg->param.power_ext.num_pwr_grp,
6245 					     MAX_POWER_GROUP) *
6246 					 sizeof(mlan_power_group)),
6247 				respbuflen);
6248 		ret = sizeof(pcfg->param.power_ext.num_pwr_grp) +
6249 		      (MIN(pcfg->param.power_ext.num_pwr_grp, MAX_POWER_GROUP) *
6250 		       sizeof(mlan_power_group));
6251 	}
6252 done:
6253 	if (status != MLAN_STATUS_PENDING)
6254 		kfree(req);
6255 	LEAVE();
6256 	return ret;
6257 }
6258 
6259 /**
6260  * @brief Set/Get PS configuration parameters
6261  *
6262  * @param priv         A pointer to moal_private structure
6263  * @param respbuf      A pointer to response buffer
6264  * @param respbuflen   Available length of response buffer
6265  *
6266  * @return         0 --success, otherwise fail
6267  */
woal_priv_pscfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6268 static int woal_priv_pscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
6269 {
6270 	int data[7] = {0}, ret = 0;
6271 	mlan_ds_pm_cfg *pm_cfg = NULL;
6272 	mlan_ioctl_req *req = NULL;
6273 	int allowed = 3;
6274 	int i = 3;
6275 	int user_data_len = 0, header_len = 0;
6276 	mlan_status status = MLAN_STATUS_SUCCESS;
6277 
6278 	ENTER();
6279 
6280 	allowed++; /* For beacon missing timeout parameter */
6281 	allowed += 2; /* For delay to PS and PS mode parameters */
6282 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
6283 	if (req == NULL) {
6284 		ret = -ENOMEM;
6285 		goto done;
6286 	}
6287 
6288 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSCFG);
6289 
6290 	if ((int)strlen(respbuf) == header_len) {
6291 		/* GET operation */
6292 		user_data_len = 0;
6293 	} else {
6294 		/* SET operation */
6295 		memset((char *)data, 0, sizeof(data));
6296 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6297 				&user_data_len);
6298 	}
6299 
6300 	if (user_data_len && user_data_len > allowed) {
6301 		PRINTM(MERROR, "Too many arguments\n");
6302 		ret = -EINVAL;
6303 		goto done;
6304 	}
6305 	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6306 	pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
6307 	req->req_id = MLAN_IOCTL_PM_CFG;
6308 	if (user_data_len) {
6309 		if ((data[0] < PS_NULL_DISABLE)) {
6310 			PRINTM(MERROR,
6311 			       "Invalid argument for PS null interval\n");
6312 			ret = -EINVAL;
6313 			goto done;
6314 		}
6315 		if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM) &&
6316 		    (data[1] != MRVDRV_MATCH_CLOSEST_DTIM) &&
6317 		    ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM) ||
6318 		     (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
6319 			PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
6320 			ret = -EINVAL;
6321 			goto done;
6322 		}
6323 
6324 		if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL) &&
6325 		    (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
6326 			PRINTM(MERROR,
6327 			       "Invalid argument for listen interval\n");
6328 			ret = -EINVAL;
6329 			goto done;
6330 		}
6331 
6332 		if ((data[i] != DISABLE_BCN_MISS_TO) &&
6333 		    ((data[i] < MIN_BCN_MISS_TO) ||
6334 		     (data[i] > MAX_BCN_MISS_TO))) {
6335 			PRINTM(MERROR,
6336 			       "Invalid argument for beacon miss timeout\n");
6337 			ret = -EINVAL;
6338 			goto done;
6339 		}
6340 		i++;
6341 		if (user_data_len < allowed - 1)
6342 			data[i] = DELAY_TO_PS_UNCHANGED;
6343 		else if ((data[i] < MIN_DELAY_TO_PS) ||
6344 			 (data[i] > MAX_DELAY_TO_PS)) {
6345 			PRINTM(MERROR, "Invalid argument for delay to PS\n");
6346 			ret = -EINVAL;
6347 			goto done;
6348 		}
6349 		i++;
6350 		if ((data[i] != PS_MODE_UNCHANGED) &&
6351 		    (data[i] != PS_MODE_AUTO) && (data[i] != PS_MODE_POLL) &&
6352 		    (data[i] != PS_MODE_NULL)) {
6353 			PRINTM(MERROR, "Invalid argument for PS mode\n");
6354 			ret = -EINVAL;
6355 			goto done;
6356 		}
6357 		i++;
6358 		req->action = MLAN_ACT_SET;
6359 		moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_cfg, data,
6360 				sizeof(data), sizeof(pm_cfg->param.ps_cfg));
6361 	} else
6362 		req->action = MLAN_ACT_GET;
6363 
6364 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6365 	if (status != MLAN_STATUS_SUCCESS) {
6366 		ret = -EFAULT;
6367 		goto done;
6368 	}
6369 	moal_memcpy_ext(priv->phandle, data, &pm_cfg->param.ps_cfg,
6370 			MIN((sizeof(int) * allowed),
6371 			    sizeof(pm_cfg->param.ps_cfg)),
6372 			sizeof(data));
6373 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
6374 			sizeof(int) * allowed, respbuflen);
6375 	ret = sizeof(int) * allowed;
6376 	if (req->action == MLAN_ACT_SET) {
6377 		pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6378 		pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
6379 		pm_cfg->param.ps_mode = 1;
6380 		req->req_id = MLAN_IOCTL_PM_CFG;
6381 		req->action = MLAN_ACT_SET;
6382 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6383 	}
6384 
6385 done:
6386 	if (status != MLAN_STATUS_PENDING)
6387 		kfree(req);
6388 	LEAVE();
6389 	return ret;
6390 }
6391 
6392 /**
6393  * @brief Set/Get PS configuration parameters
6394  *
6395  * @param priv         A pointer to moal_private structure
6396  * @param respbuf      A pointer to response buffer
6397  * @param respbuflen   Available length of response buffer
6398  *
6399  * @return         0 --success, otherwise fail
6400  */
woal_priv_bcntimeoutcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6401 static int woal_priv_bcntimeoutcfg(moal_private *priv, t_u8 *respbuf,
6402 				   t_u32 respbuflen)
6403 {
6404 	int data[4] = {0}, ret = 0;
6405 	mlan_ds_pm_cfg *pm_cfg = NULL;
6406 	mlan_ioctl_req *req = NULL;
6407 	int allowed = 4;
6408 	int i = 0;
6409 	int user_data_len = 0, header_len = 0;
6410 	mlan_status status = MLAN_STATUS_SUCCESS;
6411 
6412 	ENTER();
6413 
6414 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCNTIMEOUTCFG);
6415 
6416 	memset((char *)data, 0, sizeof(data));
6417 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6418 			&user_data_len);
6419 	if (user_data_len != allowed) {
6420 		PRINTM(MERROR, "Invalid args num: input=%d allowed=%d\n",
6421 		       user_data_len, allowed);
6422 		ret = -EINVAL;
6423 		goto done;
6424 	}
6425 	for (i = 0; i < allowed; i++) {
6426 		if (data[i] <= 0) {
6427 			PRINTM(MERROR, "Invalid data[%d]=%d\n", i, data[i]);
6428 			ret = -EINVAL;
6429 			goto done;
6430 		}
6431 	}
6432 
6433 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
6434 	if (req == NULL) {
6435 		ret = -ENOMEM;
6436 		goto done;
6437 	}
6438 	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6439 	pm_cfg->sub_command = MLAN_OID_PM_CFG_BCN_TIMEOUT;
6440 	req->req_id = MLAN_IOCTL_PM_CFG;
6441 	req->action = MLAN_ACT_SET;
6442 	pm_cfg->param.bcn_timeout.bcn_miss_tmo_window = (t_u16)data[0];
6443 	pm_cfg->param.bcn_timeout.bcn_miss_tmo_period = (t_u16)data[1];
6444 	pm_cfg->param.bcn_timeout.bcn_rq_tmo_window = (t_u16)data[2];
6445 	pm_cfg->param.bcn_timeout.bcn_rq_tmo_period = (t_u16)data[3];
6446 
6447 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6448 	if (status != MLAN_STATUS_SUCCESS) {
6449 		ret = -EFAULT;
6450 		goto done;
6451 	}
6452 
6453 done:
6454 	if (status != MLAN_STATUS_PENDING)
6455 		kfree(req);
6456 	LEAVE();
6457 	return ret;
6458 }
6459 
6460 /**
6461  * @brief Set/Get sleep period
6462  *
6463  * @param priv         A pointer to moal_private structure
6464  * @param respbuf      A pointer to response buffer
6465  * @param respbuflen   Available length of response buffer
6466  *
6467  * @return         0 --success, otherwise fail
6468  */
woal_priv_sleeppd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6469 static int woal_priv_sleeppd(moal_private *priv, t_u8 *respbuf,
6470 			     t_u32 respbuflen)
6471 {
6472 	int ret = 0;
6473 	mlan_ds_pm_cfg *pm_cfg = NULL;
6474 	mlan_ioctl_req *req = NULL;
6475 	int data = 0;
6476 	int user_data_len = 0, header_len = 0;
6477 	mlan_status status = MLAN_STATUS_SUCCESS;
6478 
6479 	ENTER();
6480 
6481 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
6482 	if (req == NULL) {
6483 		ret = -ENOMEM;
6484 		goto done;
6485 	}
6486 	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6487 	pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
6488 	req->req_id = MLAN_IOCTL_PM_CFG;
6489 
6490 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEPPD);
6491 
6492 	if ((int)strlen(respbuf) == header_len) {
6493 		/* GET operation */
6494 		user_data_len = 0;
6495 	} else {
6496 		/* SET operation */
6497 		parse_arguments(respbuf + header_len, &data,
6498 				sizeof(data) / sizeof(int), &user_data_len);
6499 	}
6500 
6501 	if (sizeof(int) * user_data_len > sizeof(data)) {
6502 		PRINTM(MERROR, "Too many arguments\n");
6503 		ret = -EINVAL;
6504 		goto done;
6505 	}
6506 
6507 	if (user_data_len) {
6508 		if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
6509 		    (data == 0) || (data == SLEEP_PERIOD_RESERVED_FF)) {
6510 			req->action = MLAN_ACT_SET;
6511 			pm_cfg->param.sleep_period = data;
6512 		} else {
6513 			ret = -EINVAL;
6514 			goto done;
6515 		}
6516 	} else
6517 		req->action = MLAN_ACT_GET;
6518 
6519 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6520 	if (status != MLAN_STATUS_SUCCESS) {
6521 		ret = -EFAULT;
6522 		goto done;
6523 	}
6524 	if (!user_data_len) {
6525 		data = pm_cfg->param.sleep_period;
6526 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
6527 				sizeof(data), respbuflen);
6528 		ret = sizeof(data);
6529 	}
6530 
6531 done:
6532 	if (status != MLAN_STATUS_PENDING)
6533 		kfree(req);
6534 	LEAVE();
6535 	return ret;
6536 }
6537 
6538 /**
6539  * @brief Set/Get Tx control flag
6540  *
6541  * @param priv         A pointer to moal_private structure
6542  * @param respbuf      A pointer to response buffer
6543  * @param respbuflen   Available length of response buffer
6544  *
6545  * @return         0 --success, otherwise fail
6546  */
woal_priv_txcontrol(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6547 static int woal_priv_txcontrol(moal_private *priv, t_u8 *respbuf,
6548 			       t_u32 respbuflen)
6549 {
6550 	int ret = 0;
6551 	mlan_ds_misc_cfg *misc_cfg = NULL;
6552 	mlan_ioctl_req *req = NULL;
6553 	int data = 0;
6554 	int user_data_len = 0, header_len = 0;
6555 	mlan_status status = MLAN_STATUS_SUCCESS;
6556 
6557 	ENTER();
6558 
6559 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6560 	if (req == NULL) {
6561 		ret = -ENOMEM;
6562 		goto done;
6563 	}
6564 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
6565 	misc_cfg->sub_command = MLAN_OID_MISC_TXCONTROL;
6566 	req->req_id = MLAN_IOCTL_MISC_CFG;
6567 
6568 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXCONTROL);
6569 
6570 	if ((int)strlen(respbuf) == header_len) {
6571 		/* GET operation */
6572 		user_data_len = 0;
6573 	} else {
6574 		/* SET operation */
6575 		parse_arguments(respbuf + header_len, &data,
6576 				sizeof(data) / sizeof(int), &user_data_len);
6577 	}
6578 
6579 	if (sizeof(int) * user_data_len > sizeof(data)) {
6580 		PRINTM(MERROR, "Too many arguments\n");
6581 		ret = -EINVAL;
6582 		goto done;
6583 	}
6584 
6585 	if (user_data_len) {
6586 		req->action = MLAN_ACT_SET;
6587 		misc_cfg->param.tx_control = (t_u32)data;
6588 	} else {
6589 		req->action = MLAN_ACT_GET;
6590 	}
6591 
6592 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6593 	if (status != MLAN_STATUS_SUCCESS) {
6594 		ret = -EFAULT;
6595 		goto done;
6596 	}
6597 	if (!user_data_len) {
6598 		data = misc_cfg->param.tx_control;
6599 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
6600 				sizeof(data), respbuflen);
6601 		ret = sizeof(data);
6602 	}
6603 
6604 done:
6605 	if (status != MLAN_STATUS_PENDING)
6606 		kfree(req);
6607 	LEAVE();
6608 	return ret;
6609 }
6610 
6611 /**
6612  * @brief Read/Write adapter registers value
6613  *
6614  * @param priv         A pointer to moal_private structure
6615  * @param respbuf      A pointer to response buffer
6616  * @param respbuflen   Available length of response buffer
6617  *
6618  * @return         0 --success, otherwise fail
6619  */
woal_priv_regrdwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6620 static int woal_priv_regrdwr(moal_private *priv, t_u8 *respbuf,
6621 			     t_u32 respbuflen)
6622 {
6623 	int data[3];
6624 	int ret = 0;
6625 	mlan_ioctl_req *req = NULL;
6626 	mlan_ds_reg_mem *reg_mem = NULL;
6627 	int user_data_len = 0, header_len = 0;
6628 	t_u8 *arguments = NULL, *space_ind = NULL;
6629 	t_u32 is_negative_val = MFALSE;
6630 	mlan_status status = MLAN_STATUS_SUCCESS;
6631 	gfp_t flag;
6632 
6633 	ENTER();
6634 
6635 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
6636 	if (req == NULL) {
6637 		ret = -ENOMEM;
6638 		goto done;
6639 	}
6640 
6641 	reg_mem = (mlan_ds_reg_mem *)req->pbuf;
6642 	reg_mem->sub_command = MLAN_OID_REG_RW;
6643 	req->req_id = MLAN_IOCTL_REG_MEM;
6644 
6645 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGRDWR);
6646 
6647 	if ((int)strlen(respbuf) == header_len) {
6648 		ret = -EINVAL;
6649 		goto done;
6650 	}
6651 	/* SET operation */
6652 	memset((char *)data, 0, sizeof(data));
6653 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
6654 	arguments = kzalloc(strlen(respbuf) * sizeof(char), flag);
6655 	if (arguments == NULL) {
6656 		ret = -ENOMEM;
6657 		goto done;
6658 	}
6659 	strcpy(arguments, respbuf + header_len);
6660 	space_ind = strstr((char *)arguments, " ");
6661 	if (space_ind)
6662 		space_ind = strstr(space_ind + 1, " ");
6663 	if (space_ind) {
6664 		if (*(char *)(space_ind + 1) == '-') {
6665 			is_negative_val = MTRUE;
6666 			arguments[space_ind + 1 - arguments] = '\0';
6667 			strcat(arguments, space_ind + 2);
6668 		}
6669 	}
6670 	parse_arguments(arguments, data, ARRAY_SIZE(data), &user_data_len);
6671 	if (is_negative_val == MTRUE)
6672 		data[2] *= -1;
6673 
6674 	if (user_data_len == 2) {
6675 		req->action = MLAN_ACT_GET;
6676 	} else if (user_data_len == 3) {
6677 		req->action = MLAN_ACT_SET;
6678 	} else {
6679 		ret = -EINVAL;
6680 		goto done;
6681 	}
6682 
6683 	reg_mem->param.reg_rw.type = (t_u32)data[0];
6684 	reg_mem->param.reg_rw.offset = (t_u32)data[1];
6685 	if (user_data_len == 3)
6686 		reg_mem->param.reg_rw.value = (t_u32)data[2];
6687 
6688 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6689 	if (status != MLAN_STATUS_SUCCESS) {
6690 		ret = -EFAULT;
6691 		goto done;
6692 	}
6693 
6694 	if (req->action == MLAN_ACT_GET) {
6695 		moal_memcpy_ext(priv->phandle, respbuf, &reg_mem->param.reg_rw,
6696 				sizeof(reg_mem->param.reg_rw), respbuflen);
6697 		ret = sizeof(reg_mem->param.reg_rw);
6698 	}
6699 
6700 done:
6701 	if (status != MLAN_STATUS_PENDING)
6702 		kfree(req);
6703 	kfree(arguments);
6704 	LEAVE();
6705 	return ret;
6706 }
6707 
6708 /**
6709  * @brief Read the EEPROM contents of the card
6710  *
6711  * @param priv         A pointer to moal_private structure
6712  * @param respbuf      A pointer to response buffer
6713  * @param respbuflen   Available length of response buffer
6714  *
6715  * @return         0 --success, otherwise fail
6716  */
woal_priv_rdeeprom(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6717 static int woal_priv_rdeeprom(moal_private *priv, t_u8 *respbuf,
6718 			      t_u32 respbuflen)
6719 {
6720 	int data[2];
6721 	int ret = 0;
6722 	mlan_ioctl_req *req = NULL;
6723 	mlan_ds_reg_mem *reg_mem = NULL;
6724 	int user_data_len = 0, header_len = 0;
6725 	mlan_status status = MLAN_STATUS_SUCCESS;
6726 
6727 	ENTER();
6728 
6729 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
6730 	if (req == NULL) {
6731 		ret = -ENOMEM;
6732 		goto done;
6733 	}
6734 
6735 	reg_mem = (mlan_ds_reg_mem *)req->pbuf;
6736 	reg_mem->sub_command = MLAN_OID_EEPROM_RD;
6737 	req->req_id = MLAN_IOCTL_REG_MEM;
6738 
6739 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RDEEPROM);
6740 
6741 	if ((int)strlen(respbuf) == header_len) {
6742 		ret = -EINVAL;
6743 		goto done;
6744 	}
6745 	/* SET operation */
6746 	memset((char *)data, 0, sizeof(data));
6747 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6748 			&user_data_len);
6749 
6750 	if (user_data_len == 2) {
6751 		req->action = MLAN_ACT_GET;
6752 	} else {
6753 		ret = -EINVAL;
6754 		goto done;
6755 	}
6756 
6757 	reg_mem->param.rd_eeprom.offset = (t_u16)data[0];
6758 	reg_mem->param.rd_eeprom.byte_count = (t_u16)data[1];
6759 
6760 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6761 	if (status != MLAN_STATUS_SUCCESS) {
6762 		ret = -EFAULT;
6763 		goto done;
6764 	}
6765 
6766 	if (req->action == MLAN_ACT_GET) {
6767 		moal_memcpy_ext(priv->phandle, respbuf,
6768 				&reg_mem->param.rd_eeprom,
6769 				sizeof(reg_mem->param.rd_eeprom), respbuflen);
6770 		ret = sizeof(reg_mem->param.rd_eeprom);
6771 	}
6772 
6773 done:
6774 	if (status != MLAN_STATUS_PENDING)
6775 		kfree(req);
6776 	LEAVE();
6777 	return ret;
6778 }
6779 
6780 /**
6781  * @brief Read/Write device memory value
6782  *
6783  * @param priv         A pointer to moal_private structure
6784  * @param respbuf      A pointer to response buffer
6785  * @param respbuflen   Available length of response buffer
6786  *
6787  * @return         0 --success, otherwise fail
6788  */
woal_priv_memrdwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6789 static int woal_priv_memrdwr(moal_private *priv, t_u8 *respbuf,
6790 			     t_u32 respbuflen)
6791 {
6792 	int data[2];
6793 	int ret = 0;
6794 	mlan_ioctl_req *req = NULL;
6795 	mlan_ds_reg_mem *reg_mem = NULL;
6796 	int user_data_len = 0, header_len = 0;
6797 	mlan_status status = MLAN_STATUS_SUCCESS;
6798 
6799 	ENTER();
6800 
6801 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
6802 	if (req == NULL) {
6803 		ret = -ENOMEM;
6804 		goto done;
6805 	}
6806 
6807 	reg_mem = (mlan_ds_reg_mem *)req->pbuf;
6808 	reg_mem->sub_command = MLAN_OID_MEM_RW;
6809 	req->req_id = MLAN_IOCTL_REG_MEM;
6810 
6811 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MEMRDWR);
6812 
6813 	if ((int)strlen(respbuf) == header_len) {
6814 		ret = -EINVAL;
6815 		goto done;
6816 	}
6817 	/* SET operation */
6818 	memset((char *)data, 0, sizeof(data));
6819 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6820 			&user_data_len);
6821 
6822 	if (user_data_len == 1) {
6823 		PRINTM(MINFO, "MEM_RW: GET\n");
6824 		req->action = MLAN_ACT_GET;
6825 	} else if (user_data_len == 2) {
6826 		PRINTM(MINFO, "MEM_RW: SET\n");
6827 		req->action = MLAN_ACT_SET;
6828 	} else {
6829 		ret = -EINVAL;
6830 		goto done;
6831 	}
6832 
6833 	reg_mem->param.mem_rw.addr = (t_u32)data[0];
6834 	if (user_data_len == 2)
6835 		reg_mem->param.mem_rw.value = (t_u32)data[1];
6836 
6837 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6838 	if (status != MLAN_STATUS_SUCCESS) {
6839 		ret = -EFAULT;
6840 		goto done;
6841 	}
6842 
6843 	if (req->action == MLAN_ACT_GET) {
6844 		moal_memcpy_ext(priv->phandle, respbuf, &reg_mem->param.mem_rw,
6845 				sizeof(reg_mem->param.mem_rw), respbuflen);
6846 		ret = sizeof(reg_mem->param.mem_rw);
6847 	}
6848 
6849 done:
6850 	if (status != MLAN_STATUS_PENDING)
6851 		kfree(req);
6852 	LEAVE();
6853 	return ret;
6854 }
6855 
6856 #ifdef SDIO
6857 /**
6858  *  @brief Cmd52 read/write register
6859  *
6860  *  @param priv         A pointer to moal_private structure
6861  *  @param respbuf      A pointer to response buffer
6862  *  @param respbuflen   Available length of response buffer
6863  *
6864  *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
6865  */
woal_priv_sdcmd52rw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6866 static int woal_priv_sdcmd52rw(moal_private *priv, t_u8 *respbuf,
6867 			       t_u32 respbuflen)
6868 {
6869 	t_u8 rw = 0, func, data = 0;
6870 	int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
6871 	int user_data_len = 0, header_len = 0;
6872 
6873 	ENTER();
6874 
6875 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDCMD52RW);
6876 	memset((t_u8 *)buf, 0, sizeof(buf));
6877 
6878 	if ((int)strlen(respbuf) == header_len) {
6879 		PRINTM(MERROR, "Invalid number of arguments\n");
6880 		ret = -EINVAL;
6881 		goto done;
6882 	}
6883 	parse_arguments(respbuf + header_len, buf, ARRAY_SIZE(buf),
6884 			&user_data_len);
6885 
6886 	if (user_data_len < 2 || user_data_len > 3) {
6887 		PRINTM(MERROR, "Invalid number of arguments\n");
6888 		ret = -EINVAL;
6889 		goto done;
6890 	}
6891 
6892 	func = (t_u8)buf[0];
6893 	if (func > 7) {
6894 		PRINTM(MERROR, "Invalid function number!\n");
6895 		ret = -EINVAL;
6896 		goto done;
6897 	}
6898 	reg = (t_u32)buf[1];
6899 	if (user_data_len == 2) {
6900 		rw = 0; /* CMD52 read */
6901 		PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
6902 	}
6903 	if (user_data_len == 3) {
6904 		rw = 1; /* CMD52 write */
6905 		data = (t_u8)buf[2];
6906 		PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
6907 		       func, reg, data);
6908 	}
6909 
6910 	if (!rw) {
6911 #ifdef SDIO_MMC
6912 		sdio_claim_host(
6913 			((struct sdio_mmc_card *)priv->phandle->card)->func);
6914 		if (func)
6915 			data = sdio_readb(
6916 				((struct sdio_mmc_card *)priv->phandle->card)
6917 					->func,
6918 				reg, &ret);
6919 		else
6920 			data = sdio_f0_readb(
6921 				((struct sdio_mmc_card *)priv->phandle->card)
6922 					->func,
6923 				reg, &ret);
6924 		sdio_release_host(
6925 			((struct sdio_mmc_card *)priv->phandle->card)->func);
6926 		if (ret) {
6927 			PRINTM(MERROR,
6928 			       "sdio_readb: reading register 0x%X failed\n",
6929 			       reg);
6930 			goto done;
6931 		}
6932 #else
6933 		if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) <
6934 		    0) {
6935 			PRINTM(MERROR,
6936 			       "sdio_read_ioreg: reading register 0x%X failed\n",
6937 			       reg);
6938 			ret = MLAN_STATUS_FAILURE;
6939 			goto done;
6940 		}
6941 #endif /* SDIO_MMC */
6942 	} else {
6943 #ifdef SDIO_MMC
6944 		sdio_claim_host(
6945 			((struct sdio_mmc_card *)priv->phandle->card)->func);
6946 		if (func)
6947 			sdio_writeb(
6948 				((struct sdio_mmc_card *)priv->phandle->card)
6949 					->func,
6950 				data, reg, &ret);
6951 		else
6952 			sdio_f0_writeb(
6953 				((struct sdio_mmc_card *)priv->phandle->card)
6954 					->func,
6955 				data, reg, &ret);
6956 		sdio_release_host(
6957 			((struct sdio_mmc_card *)priv->phandle->card)->func);
6958 		if (ret) {
6959 			PRINTM(MERROR,
6960 			       "sdio_writeb: writing register 0x%X failed\n",
6961 			       reg);
6962 			goto done;
6963 		}
6964 #else
6965 		if (sdio_write_ioreg(priv->phandle->card, func, reg, data) <
6966 		    0) {
6967 			PRINTM(MERROR,
6968 			       "sdio_write_ioreg: writing register 0x%X failed\n",
6969 			       reg);
6970 			ret = MLAN_STATUS_FAILURE;
6971 			goto done;
6972 		}
6973 #endif /* SDIO_MMC */
6974 	}
6975 
6976 	/* Action = GET */
6977 	buf[0] = data;
6978 
6979 	moal_memcpy_ext(priv->phandle, respbuf, &buf, sizeof(int), respbuflen);
6980 	ret = sizeof(int);
6981 
6982 done:
6983 	LEAVE();
6984 	return ret;
6985 }
6986 #endif /* SDIO */
6987 
6988 #ifdef STA_SUPPORT
6989 /**
6990  *  @brief arpfilter ioctl function
6991  *
6992  *  @param priv         A pointer to moal_private structure
6993  *  @param respbuf      A pointer to response buffer
6994  *  @param respbuflen   Available length of response buffer
6995  *
6996  *  @return		0 --success, otherwise fail
6997  */
woal_priv_arpfilter(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6998 static int woal_priv_arpfilter(moal_private *priv, t_u8 *respbuf,
6999 			       t_u32 respbuflen)
7000 {
7001 	int ret = 0;
7002 	mlan_ds_misc_cfg *misc = NULL;
7003 	mlan_ioctl_req *req = NULL;
7004 	t_u8 *data_ptr = NULL;
7005 	t_u32 buf_len = 0;
7006 	mlan_status status = MLAN_STATUS_SUCCESS;
7007 
7008 	ENTER();
7009 
7010 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7011 	if (req == NULL) {
7012 		ret = -ENOMEM;
7013 		goto done;
7014 	}
7015 	misc = (mlan_ds_misc_cfg *)req->pbuf;
7016 	misc->sub_command = MLAN_OID_MISC_GEN_IE;
7017 	req->req_id = MLAN_IOCTL_MISC_CFG;
7018 	req->action = MLAN_ACT_SET;
7019 	misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER;
7020 
7021 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_ARPFILTER));
7022 	buf_len = *((t_u16 *)data_ptr);
7023 	misc->param.gen_ie.len = buf_len;
7024 	moal_memcpy_ext(priv->phandle, (void *)(misc->param.gen_ie.ie_data),
7025 			data_ptr + sizeof(buf_len), buf_len, MAX_IE_SIZE);
7026 
7027 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7028 	if (status != MLAN_STATUS_SUCCESS) {
7029 		ret = -EFAULT;
7030 		goto done;
7031 	}
7032 done:
7033 	if (status != MLAN_STATUS_PENDING)
7034 		kfree(req);
7035 	LEAVE();
7036 	return ret;
7037 }
7038 #endif /* STA_SUPPORT */
7039 
7040 /**
7041  *  @brief Set / Get Auto ARP Response configuration
7042  *
7043  *  @param priv         A pointer to moal_private structure
7044  *  @param respbuf      A pointer to response buffer
7045  *  @param respbuflen   Available length of response buffer
7046  *
7047  *  @return             Number of bytes written, negative for failure.
7048  */
woal_priv_set_get_auto_arp(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7049 static int woal_priv_set_get_auto_arp(moal_private *priv, t_u8 *respbuf,
7050 				      t_u32 respbuflen)
7051 {
7052 	int data[4];
7053 	int user_data_len = 0;
7054 	int ret = 0;
7055 	moal_handle *handle = NULL;
7056 
7057 	ENTER();
7058 
7059 	if (priv == NULL) {
7060 		PRINTM(MERROR, "Invalid priv\n");
7061 		goto done;
7062 	}
7063 	handle = priv->phandle;
7064 
7065 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_ARP))) {
7066 		/* GET operation */
7067 		user_data_len = 0;
7068 	} else {
7069 		/* SET operation */
7070 		memset((char *)data, 0, sizeof(data));
7071 		parse_arguments(respbuf + strlen(CMD_NXP) +
7072 					strlen(PRIV_CMD_AUTO_ARP),
7073 				data, ARRAY_SIZE(data), &user_data_len);
7074 	}
7075 
7076 	if (user_data_len > 1) {
7077 		PRINTM(MERROR, "Too many arguments\n");
7078 		ret = -EINVAL;
7079 		goto done;
7080 	}
7081 
7082 	if (user_data_len) {
7083 		/* Get the enable/disable value from user */
7084 		handle->hs_auto_arp = data[0];
7085 		PRINTM(MIOCTL, "Auto ARP : %s\n",
7086 		       handle->hs_auto_arp ? "enable" : "disable");
7087 	}
7088 
7089 	moal_memcpy_ext(handle, respbuf, &handle->hs_auto_arp,
7090 			sizeof(handle->hs_auto_arp), respbuflen);
7091 	ret = sizeof(handle->hs_auto_arp);
7092 
7093 done:
7094 	LEAVE();
7095 	return ret;
7096 }
7097 
7098 /**
7099  *  @brief Get/Set deauth control
7100  *
7101  *  @param priv         A pointer to moal_private structure
7102  *  @param respbuf      A pointer to response buffer
7103  *  @param respbuflen   Available length of response buffer
7104  *
7105  *  @return             Number of bytes written, negative for failure.
7106  */
woal_priv_deauth_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7107 static int woal_priv_deauth_ctrl(moal_private *priv, t_u8 *respbuf,
7108 				 t_u32 respbuflen)
7109 {
7110 	mlan_ds_snmp_mib *cfg = NULL;
7111 	mlan_ioctl_req *req = NULL;
7112 	int ret = 0, header_len = 0, data = 0, user_data_len = 0;
7113 	mlan_status status = MLAN_STATUS_SUCCESS;
7114 
7115 	ENTER();
7116 
7117 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
7118 	if (req == NULL) {
7119 		ret = -ENOMEM;
7120 		goto done;
7121 	}
7122 
7123 	cfg = (mlan_ds_snmp_mib *)req->pbuf;
7124 	cfg->sub_command = MLAN_OID_SNMP_MIB_CTRL_DEAUTH;
7125 	req->req_id = MLAN_IOCTL_SNMP_MIB;
7126 
7127 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH_CTRL);
7128 
7129 	if ((int)strlen(respbuf) == header_len) {
7130 		/* GET operation */
7131 		req->action = MLAN_ACT_GET;
7132 	} else {
7133 		/* SET operation */
7134 		parse_arguments(respbuf + header_len, &data,
7135 				sizeof(data) / sizeof(int), &user_data_len);
7136 		if (user_data_len != 1) {
7137 			PRINTM(MERROR, "Invalid number of args! %d\n",
7138 			       user_data_len);
7139 			ret = -EINVAL;
7140 			goto done;
7141 		}
7142 		req->action = MLAN_ACT_SET;
7143 		cfg->param.deauthctrl = (t_u8)data;
7144 	}
7145 
7146 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7147 	if (status != MLAN_STATUS_SUCCESS) {
7148 		ret = -EFAULT;
7149 		goto done;
7150 	}
7151 
7152 	data = (int)cfg->param.deauthctrl;
7153 	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
7154 			respbuflen);
7155 	ret = sizeof(data);
7156 
7157 done:
7158 	if (status != MLAN_STATUS_PENDING)
7159 		kfree(req);
7160 	LEAVE();
7161 	return ret;
7162 }
7163 
7164 #define MRVL_TLV_HEADER_SIZE 4
7165 /**
7166  *  @brief              Get/Set per packet Txctl and Rxinfo configuration
7167  *
7168  *  @param priv         A pointer to moal_private structure
7169  *  @param respbuf      A pointer to response buffer
7170  *  @param respbuflen   Available length of response buffer
7171  *
7172  *  @return             Number of bytes written, negative for failure.
7173  */
woal_priv_per_pkt_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7174 static int woal_priv_per_pkt_cfg(moal_private *priv, t_u8 *respbuf,
7175 				 t_u32 respbuflen)
7176 {
7177 	mlan_ds_misc_cfg *misc = NULL;
7178 	mlan_ioctl_req *req = NULL;
7179 	int ret = 0;
7180 	t_u8 *pos = NULL;
7181 	int left_len, header_len = 0;
7182 	mlan_per_pkt_cfg *perpkt = NULL;
7183 	mlan_status status = MLAN_STATUS_SUCCESS;
7184 
7185 	ENTER();
7186 
7187 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PER_PKT_CFG);
7188 	pos = respbuf + header_len;
7189 	left_len = respbuflen - header_len;
7190 
7191 	if (priv->phandle->card_info->per_pkt_cfg_support == 0) {
7192 		PRINTM(MERROR, "Device not support per packet configuration\n");
7193 		ret = -EFAULT;
7194 		goto done;
7195 	}
7196 
7197 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7198 	if (req == NULL) {
7199 		ret = -ENOMEM;
7200 		goto done;
7201 	}
7202 
7203 	misc = (mlan_ds_misc_cfg *)req->pbuf;
7204 	misc->sub_command = MLAN_OID_MISC_PER_PKT_CFG;
7205 	req->req_id = MLAN_IOCTL_MISC_CFG;
7206 
7207 	if (*pos == 0) {
7208 		/* GET operation */
7209 		pos++;
7210 		if (priv->tx_protocols.protocol_num) {
7211 			perpkt = (mlan_per_pkt_cfg *)pos;
7212 			perpkt->type = TLV_TYPE_PER_PKT_CFG;
7213 			perpkt->tx_rx_control = TX_PKT_CTRL;
7214 			perpkt->proto_type_num =
7215 				priv->tx_protocols.protocol_num;
7216 			moal_memcpy_ext(priv->phandle, perpkt->ether_type,
7217 					priv->tx_protocols.protocols,
7218 					perpkt->proto_type_num * sizeof(t_u16),
7219 					MAX_NUM_ETHER_TYPE * sizeof(t_u16));
7220 			perpkt->len =
7221 				(perpkt->proto_type_num + 1) * sizeof(t_u16);
7222 			pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
7223 		}
7224 		if (priv->rx_protocols.protocol_num) {
7225 			perpkt = (mlan_per_pkt_cfg *)pos;
7226 			perpkt->type = TLV_TYPE_PER_PKT_CFG;
7227 			perpkt->tx_rx_control = RX_PKT_INFO;
7228 			perpkt->proto_type_num =
7229 				priv->rx_protocols.protocol_num;
7230 			moal_memcpy_ext(priv->phandle, perpkt->ether_type,
7231 					priv->rx_protocols.protocols,
7232 					perpkt->proto_type_num * sizeof(t_u16),
7233 					MAX_NUM_ETHER_TYPE * sizeof(t_u16));
7234 			perpkt->len =
7235 				(perpkt->proto_type_num + 1) * sizeof(t_u16);
7236 			pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
7237 		}
7238 		ret = pos - respbuf;
7239 		goto done;
7240 	} else if (*pos == 1) {
7241 		/* SET operation */
7242 		req->action = MLAN_ACT_SET;
7243 		pos++;
7244 		left_len--;
7245 		while (*pos == TLV_TYPE_PER_PKT_CFG && (left_len > 2)) {
7246 			perpkt = (mlan_per_pkt_cfg *)pos;
7247 			if (perpkt->tx_rx_control & TX_PKT_CTRL) {
7248 				priv->tx_protocols.protocol_num =
7249 					perpkt->proto_type_num;
7250 				if (perpkt->proto_type_num <=
7251 				    MAX_NUM_ETHER_TYPE)
7252 					moal_memcpy_ext(
7253 						priv->phandle,
7254 						priv->tx_protocols.protocols,
7255 						perpkt->ether_type,
7256 						perpkt->proto_type_num *
7257 							sizeof(t_u16),
7258 						MAX_NUM_ETHER_TYPE *
7259 							sizeof(t_u16));
7260 			}
7261 			if (perpkt->tx_rx_control & RX_PKT_INFO) {
7262 				priv->rx_protocols.protocol_num =
7263 					perpkt->proto_type_num;
7264 				if (perpkt->proto_type_num <=
7265 				    MAX_NUM_ETHER_TYPE)
7266 					moal_memcpy_ext(
7267 						priv->phandle,
7268 						priv->rx_protocols.protocols,
7269 						perpkt->ether_type,
7270 						perpkt->proto_type_num *
7271 							sizeof(t_u16),
7272 						MAX_NUM_ETHER_TYPE *
7273 							sizeof(t_u16));
7274 			}
7275 			if (!perpkt->tx_rx_control) {
7276 				memset(&priv->tx_protocols, 0,
7277 				       sizeof(dot11_protocol));
7278 				memset(&priv->rx_protocols, 0,
7279 				       sizeof(dot11_protocol));
7280 			}
7281 			pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
7282 			left_len -= (perpkt->len + MRVL_TLV_HEADER_SIZE);
7283 		}
7284 	} else
7285 		goto done;
7286 
7287 	if (perpkt != NULL)
7288 		misc->param.txrx_pkt_ctrl = perpkt->tx_rx_control;
7289 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7290 	if (status != MLAN_STATUS_SUCCESS) {
7291 		ret = -EFAULT;
7292 		goto done;
7293 	}
7294 
7295 done:
7296 	if (status != MLAN_STATUS_PENDING)
7297 		kfree(req);
7298 	LEAVE();
7299 	return ret;
7300 }
7301 
7302 /**
7303  *  @brief              Get Region Channel Power
7304  *
7305  *  @param priv         A pointer to moal_private structure
7306  *  @param respbuf      A pointer to response buffer
7307  *  @param respbuflen   Available length of response buffer
7308  *
7309  *  @return             Number of bytes written, negative for failure.
7310  */
woal_priv_get_chnrgpwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7311 static int woal_priv_get_chnrgpwr(moal_private *priv, t_u8 *respbuf,
7312 				  t_u32 respbuflen)
7313 {
7314 	int ret = 0;
7315 	mlan_ioctl_req *req = NULL;
7316 	mlan_ds_misc_cfg *misc = NULL;
7317 	int header_len = 0;
7318 	t_u8 *pos = NULL;
7319 	mlan_status status = MLAN_STATUS_SUCCESS;
7320 
7321 	ENTER();
7322 	header_len = strlen(PRIV_CMD_GET_CHNRGPWR);
7323 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7324 	if (req == NULL) {
7325 		ret = -ENOMEM;
7326 		goto done;
7327 	}
7328 	misc = (mlan_ds_misc_cfg *)req->pbuf;
7329 	misc->sub_command = MLAN_OID_MISC_GET_REGIONPWR_CFG;
7330 	req->req_id = MLAN_IOCTL_MISC_CFG;
7331 	req->action = MLAN_ACT_GET;
7332 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7333 	if (status != MLAN_STATUS_SUCCESS) {
7334 		ret = -EFAULT;
7335 		goto done;
7336 	}
7337 	ret = header_len + sizeof(t_u16) + misc->param.rgchnpwr_cfg.length;
7338 	pos = respbuf + header_len;
7339 	moal_memcpy_ext(priv->phandle, pos, &misc->param.rgchnpwr_cfg,
7340 			sizeof(t_u16) + misc->param.rgchnpwr_cfg.length,
7341 			respbuflen - header_len);
7342 done:
7343 	if (status != MLAN_STATUS_PENDING)
7344 		kfree(req);
7345 	LEAVE();
7346 	return ret;
7347 }
7348 
7349 /**
7350  *  @brief              Get TX/RX histogram statistic
7351  *
7352  *  @param priv         A pointer to moal_private structure
7353  *  @param respbuf      A pointer to response buffer
7354  *  @param respbuflen   Available length of response buffer
7355  *
7356  *  @return             Number of bytes written, negative for failure.
7357  */
woal_priv_get_txpwrlimit(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7358 static int woal_priv_get_txpwrlimit(moal_private *priv, t_u8 *respbuf,
7359 				    t_u32 respbuflen)
7360 {
7361 	int ret = 0;
7362 	mlan_ioctl_req *req = NULL;
7363 	mlan_ds_misc_cfg *misc = NULL;
7364 	mlan_ds_misc_chan_trpc_cfg *trpc_cfg = NULL;
7365 	int header_len = 0;
7366 	t_u8 *pos = NULL;
7367 	mlan_status status = MLAN_STATUS_SUCCESS;
7368 
7369 	ENTER();
7370 	header_len = strlen(PRIV_CMD_GET_TXPWR_LIMIT);
7371 	trpc_cfg = (mlan_ds_misc_chan_trpc_cfg *)(respbuf + header_len);
7372 	if ((trpc_cfg->sub_band != 0) && (trpc_cfg->sub_band != 0x10) &&
7373 	    (trpc_cfg->sub_band != 0x11) && (trpc_cfg->sub_band != 0x12) &&
7374 	    (trpc_cfg->sub_band != 0x13)) {
7375 		PRINTM(MERROR, "Invalid subband=0x%x\n", trpc_cfg->sub_band);
7376 		ret = -EINVAL;
7377 		goto done;
7378 	}
7379 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7380 	if (req == NULL) {
7381 		ret = -ENOMEM;
7382 		goto done;
7383 	}
7384 	misc = (mlan_ds_misc_cfg *)req->pbuf;
7385 	misc->sub_command = MLAN_OID_MISC_GET_CHAN_TRPC_CFG;
7386 	req->req_id = MLAN_IOCTL_MISC_CFG;
7387 	req->action = MLAN_ACT_GET;
7388 	misc->param.trpc_cfg.sub_band = trpc_cfg->sub_band;
7389 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7390 	if (status != MLAN_STATUS_SUCCESS) {
7391 		ret = -EFAULT;
7392 		goto done;
7393 	}
7394 	ret = header_len + sizeof(t_u16) + sizeof(t_u16) +
7395 	      misc->param.trpc_cfg.length;
7396 	pos = respbuf + header_len;
7397 	moal_memcpy_ext(priv->phandle, pos, &misc->param.trpc_cfg,
7398 			sizeof(t_u16) + sizeof(t_u16) +
7399 				misc->param.trpc_cfg.length,
7400 			respbuflen - header_len);
7401 done:
7402 	if (status != MLAN_STATUS_PENDING)
7403 		kfree(req);
7404 	LEAVE();
7405 	return ret;
7406 }
7407 
7408 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
7409 /**
7410  *  @brief              Get TX/RX histogram statistic
7411  *
7412  *  @param priv         A pointer to moal_private structure
7413  *  @param respbuf      A pointer to response buffer
7414  *  @param respbuflen   Available length of response buffer
7415  *
7416  *  @return             Number of bytes written, negative for failure.
7417  */
woal_priv_getcfgchanlist(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7418 static int woal_priv_getcfgchanlist(moal_private *priv, t_u8 *respbuf,
7419 				    t_u32 respbuflen)
7420 {
7421 	int ret = 0;
7422 	int num_chan = 0;
7423 	wlan_ieee80211_chan_list *plist = NULL;
7424 	struct ieee80211_supported_band *sband;
7425 	struct wiphy *wiphy = NULL;
7426 	int i;
7427 
7428 	ENTER();
7429 	if (priv && priv->wdev)
7430 		wiphy = priv->wdev->wiphy;
7431 	if (!wiphy) {
7432 		PRINTM(MERROR, "wiphy is NULL\n");
7433 		ret = -EFAULT;
7434 		goto done;
7435 	}
7436 	plist = (wlan_ieee80211_chan_list *)respbuf;
7437 	sband = wiphy->bands[NL80211_BAND_2GHZ];
7438 	if (sband) {
7439 		num_chan += sband->n_channels;
7440 		for (i = 0; i < sband->n_channels; i++) {
7441 			plist->chan_list[i].center_freq =
7442 				sband->channels[i].center_freq;
7443 			plist->chan_list[i].hw_value =
7444 				sband->channels[i].hw_value;
7445 			plist->chan_list[i].flags = sband->channels[i].flags;
7446 			plist->chan_list[i].max_power =
7447 				sband->channels[i].max_power;
7448 		}
7449 	}
7450 	sband = wiphy->bands[NL80211_BAND_5GHZ];
7451 	if (sband) {
7452 		for (i = 0; i < sband->n_channels; i++) {
7453 			plist->chan_list[i + num_chan].center_freq =
7454 				sband->channels[i].center_freq;
7455 			plist->chan_list[i + num_chan].hw_value =
7456 				sband->channels[i].hw_value;
7457 			plist->chan_list[i + num_chan].flags =
7458 				sband->channels[i].flags;
7459 			plist->chan_list[i + num_chan].max_power =
7460 				sband->channels[i].max_power;
7461 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
7462 			plist->chan_list[i + num_chan].dfs_state =
7463 				sband->channels[i].dfs_state;
7464 #endif
7465 		}
7466 		num_chan += sband->n_channels;
7467 	}
7468 	plist->num_chan = num_chan;
7469 	ret = sizeof(wlan_ieee80211_chan_list) +
7470 	      sizeof(wlan_ieee80211_chan) * num_chan;
7471 done:
7472 	LEAVE();
7473 	return ret;
7474 }
7475 #endif
7476 
7477 /**
7478  *  @brief              Get TX/RX histogram statistic
7479  *
7480  *  @param priv         A pointer to moal_private structure
7481  *  @param respbuf      A pointer to response buffer
7482  *  @param respbuflen   Available length of response buffer
7483  *
7484  *  @return             Number of bytes written, negative for failure.
7485  */
woal_priv_get_rx_tx_histogram(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7486 static int woal_priv_get_rx_tx_histogram(moal_private *priv, t_u8 *respbuf,
7487 					 t_u32 respbuflen)
7488 {
7489 	int ret = 0;
7490 	mlan_ioctl_req *req = NULL;
7491 	mlan_ds_misc_cfg *misc = NULL;
7492 	tx_rx_histogram *tx_rx_info = NULL;
7493 	int header_len = 0;
7494 	t_u8 *pos = NULL;
7495 	mlan_status status = MLAN_STATUS_SUCCESS;
7496 
7497 	ENTER();
7498 	header_len = strlen(PRIV_CMD_TX_RX_HISTOGRAM);
7499 	tx_rx_info = (tx_rx_histogram *)(respbuf + header_len);
7500 	if (tx_rx_info->enable > 2 ||
7501 	    (tx_rx_info->enable == GET_TX_RX_HISTOGRAM &&
7502 	     (tx_rx_info->action > 3 || tx_rx_info->action <= 0))) {
7503 		PRINTM(MERROR, "Invalid parameters\n");
7504 		ret = -EINVAL;
7505 		goto done;
7506 	}
7507 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7508 	if (req == NULL) {
7509 		ret = -ENOMEM;
7510 		goto done;
7511 	}
7512 	misc = (mlan_ds_misc_cfg *)req->pbuf;
7513 	misc->sub_command = MLAN_OID_MISC_GET_TX_RX_HISTOGRAM;
7514 	req->req_id = MLAN_IOCTL_MISC_CFG;
7515 	if (tx_rx_info->enable == GET_TX_RX_HISTOGRAM) {
7516 		misc->param.tx_rx_histogram.enable = ENABLE_TX_RX_HISTOGRAM;
7517 		misc->param.tx_rx_histogram.action = (t_u16)tx_rx_info->action;
7518 	} else {
7519 		misc->param.tx_rx_histogram.enable = tx_rx_info->enable;
7520 		misc->param.tx_rx_histogram.action |=
7521 			FLAG_TX_HISTOGRAM | FLAG_RX_HISTOGRAM;
7522 	}
7523 
7524 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7525 	if (status != MLAN_STATUS_SUCCESS) {
7526 		ret = -EFAULT;
7527 		goto done;
7528 	}
7529 
7530 	ret = header_len + 2 * sizeof(t_u8);
7531 	if (tx_rx_info->enable & GET_TX_RX_HISTOGRAM) {
7532 		pos = respbuf + header_len + 2 * sizeof(t_u8);
7533 		/* Save tx/rx histogram size */
7534 		moal_memcpy_ext(priv->phandle, pos,
7535 				&misc->param.tx_rx_histogram.size,
7536 				sizeof(misc->param.tx_rx_histogram.size),
7537 				respbuflen - (header_len + 2 * sizeof(t_u8)));
7538 		ret += sizeof(misc->param.tx_rx_histogram.size);
7539 		pos += sizeof(misc->param.tx_rx_histogram.size);
7540 		moal_memcpy_ext(
7541 			priv->phandle, pos, &misc->param.tx_rx_histogram.value,
7542 			misc->param.tx_rx_histogram.size,
7543 			respbuflen - (header_len + 2 * sizeof(t_u8)) -
7544 				sizeof(misc->param.tx_rx_histogram.size));
7545 		ret += misc->param.tx_rx_histogram.size;
7546 	}
7547 
7548 done:
7549 	if (status != MLAN_STATUS_PENDING)
7550 		kfree(req);
7551 	LEAVE();
7552 	return ret;
7553 }
7554 
7555 /**
7556  *  @brief Set/Get hotspot mode configurations
7557  *
7558  *  @param priv         A pointer to moal_private structure
7559  *  @param respbuf      A pointer to response buffer
7560  *  @param respbuflen   Available length of response buffer
7561  *
7562  *  @return         0 --success, otherwise fail
7563  */
woal_priv_hotspotcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7564 static int woal_priv_hotspotcfg(moal_private *priv, t_u8 *respbuf,
7565 				t_u32 respbuflen)
7566 {
7567 	int ret = 0;
7568 	mlan_ioctl_req *req = NULL;
7569 	mlan_ds_misc_cfg *cfg = NULL;
7570 	int data = 0;
7571 	int user_data_len = 0, header_len = 0;
7572 	mlan_status status = MLAN_STATUS_SUCCESS;
7573 
7574 	ENTER();
7575 
7576 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HOTSPOTCFG);
7577 	if ((int)strlen(respbuf) == header_len) {
7578 		/* GET operation */
7579 		user_data_len = 0;
7580 	} else {
7581 		/* SET operation */
7582 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
7583 	}
7584 	if (user_data_len >= 2) {
7585 		PRINTM(MERROR, "Too many arguments\n");
7586 		ret = -EINVAL;
7587 		goto done;
7588 	} else {
7589 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7590 		if (req == NULL) {
7591 			ret = -ENOMEM;
7592 			goto done;
7593 		}
7594 
7595 		cfg = (mlan_ds_misc_cfg *)req->pbuf;
7596 		if (user_data_len == 0) {
7597 			req->action = MLAN_ACT_GET;
7598 		} else {
7599 			cfg->param.hotspot_cfg = data;
7600 			req->action = MLAN_ACT_SET;
7601 		}
7602 	}
7603 	cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG;
7604 	req->req_id = MLAN_IOCTL_MISC_CFG;
7605 
7606 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7607 	if (status != MLAN_STATUS_SUCCESS) {
7608 		ret = -EFAULT;
7609 		goto done;
7610 	}
7611 	data = cfg->param.hotspot_cfg;
7612 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
7613 			respbuflen);
7614 	ret = sizeof(data);
7615 
7616 done:
7617 	if (status != MLAN_STATUS_PENDING)
7618 		kfree(req);
7619 	LEAVE();
7620 	return ret;
7621 }
7622 
7623 /**
7624  *  @brief Set/Get Mgmt Frame passthru mask
7625  *
7626  *  @param priv         A pointer to moal_private structure
7627  *  @param respbuf      A pointer to response buffer
7628  *  @param respbuflen   Available length of response buffer
7629  *
7630  *  @return         0 --success, otherwise fail
7631  */
woal_priv_mgmt_frame_passthru_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7632 static int woal_priv_mgmt_frame_passthru_ctrl(moal_private *priv, t_u8 *respbuf,
7633 					      t_u32 respbuflen)
7634 {
7635 	int ret = 0;
7636 	int data = 0;
7637 	int user_data_len = 0, header_len = 0;
7638 	mlan_ioctl_req *req = NULL;
7639 	mlan_ds_misc_cfg *mgmt_cfg = NULL;
7640 	mlan_status status = MLAN_STATUS_SUCCESS;
7641 
7642 	ENTER();
7643 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MGMT_FRAME_CTRL);
7644 	if ((int)strlen(respbuf) == header_len) {
7645 		/* GET operation */
7646 		user_data_len = 0;
7647 	} else {
7648 		/* SET operation */
7649 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
7650 	}
7651 
7652 	if (user_data_len >= 2) {
7653 		PRINTM(MERROR, "Too many arguments\n");
7654 		ret = -EINVAL;
7655 		goto done;
7656 	} else {
7657 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7658 		if (req == NULL) {
7659 			ret = -ENOMEM;
7660 			goto done;
7661 		}
7662 		mgmt_cfg = (mlan_ds_misc_cfg *)req->pbuf;
7663 		req->req_id = MLAN_IOCTL_MISC_CFG;
7664 		mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
7665 
7666 		if (user_data_len == 0) { /* Get */
7667 			req->action = MLAN_ACT_GET;
7668 		} else { /* Set */
7669 			mgmt_cfg->param.mgmt_subtype_mask = data;
7670 			req->action = MLAN_ACT_SET;
7671 		}
7672 	}
7673 
7674 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7675 	if (status != MLAN_STATUS_SUCCESS) {
7676 		ret = -EFAULT;
7677 		goto done;
7678 	}
7679 
7680 	data = mgmt_cfg->param.mgmt_subtype_mask;
7681 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
7682 			respbuflen);
7683 	ret = sizeof(data);
7684 
7685 done:
7686 	if (status != MLAN_STATUS_PENDING)
7687 		kfree(req);
7688 	LEAVE();
7689 	return ret;
7690 }
7691 
7692 /**
7693  *  @brief Private IOCTL entry to send an ADDTS TSPEC
7694  *
7695  *  Receive a ADDTS command from the application.  The command structure
7696  *    contains a TSPEC and timeout in milliseconds.  The timeout is performed
7697  *    in the firmware after the ADDTS command frame is sent.
7698  *
7699  *  The TSPEC is received in the API as an opaque block. The firmware will
7700  *    send the entire data block, including the bytes after the TSPEC.  This
7701  *    is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
7702  *    action frame.
7703  *
7704  *  The IOCTL structure contains two return fields:
7705  *    - The firmware command result, which indicates failure and timeouts
7706  *    - The IEEE Status code which contains the corresponding value from
7707  *      any ADDTS response frame received.
7708  *
7709  *  In addition, the opaque TSPEC data block passed in is replaced with the
7710  *    TSPEC received in the ADDTS response frame.  In case of failure, the
7711  *    AP may modify the TSPEC on return and in the case of success, the
7712  *    medium time is returned as calculated by the AP.  Along with the TSPEC,
7713  *    any IEs that are sent in the ADDTS response are also returned and can be
7714  *    parsed using the IOCTL length as an indicator of extra elements.
7715  *
7716  *  The return value to the application layer indicates a driver execution
7717  *    success or failure.  A successful return could still indicate a firmware
7718  *    failure or AP negotiation failure via the commandResult field copied
7719  *    back to the application.
7720  *
7721  *  @param priv    Pointer to the mlan_private driver data struct
7722  *  @param respbuf      A pointer to response buffer
7723  *  @param respbuflen   Available length of response buffer
7724  *
7725  *  @return         Number of bytes written if successful else negative value
7726  */
woal_priv_wmm_addts_req_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7727 static int woal_priv_wmm_addts_req_ioctl(moal_private *priv, t_u8 *respbuf,
7728 					 t_u32 respbuflen)
7729 {
7730 	mlan_ioctl_req *req = NULL;
7731 	mlan_ds_wmm_cfg *cfg = NULL;
7732 	wlan_ioctl_wmm_addts_req_t addts_ioctl;
7733 	int ret = 0, header_len = 0, copy_len = sizeof(addts_ioctl);
7734 	t_u8 *data_ptr;
7735 	mlan_status status = MLAN_STATUS_SUCCESS;
7736 
7737 	ENTER();
7738 
7739 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ADDTS);
7740 	data_ptr = respbuf + header_len;
7741 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7742 	if (req == NULL) {
7743 		ret = -ENOMEM;
7744 		goto done;
7745 	}
7746 
7747 	req->req_id = MLAN_IOCTL_WMM_CFG;
7748 	cfg = (mlan_ds_wmm_cfg *)req->pbuf;
7749 	cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
7750 
7751 	memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));
7752 
7753 	moal_memcpy_ext(priv->phandle, (t_u8 *)&addts_ioctl, data_ptr,
7754 			sizeof(addts_ioctl), sizeof(addts_ioctl));
7755 
7756 	cfg->param.addts.timeout = addts_ioctl.timeout_ms;
7757 	cfg->param.addts.ie_data_len = addts_ioctl.ie_data_len;
7758 
7759 	moal_memcpy_ext(priv->phandle, cfg->param.addts.ie_data,
7760 			addts_ioctl.ie_data, cfg->param.addts.ie_data_len,
7761 			MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);
7762 
7763 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7764 	if (status != MLAN_STATUS_SUCCESS) {
7765 		ret = -EFAULT;
7766 		goto done;
7767 	}
7768 	addts_ioctl.cmd_result = cfg->param.addts.result;
7769 	addts_ioctl.ieee_status_code = (t_u8)cfg->param.addts.status_code;
7770 	addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;
7771 
7772 	moal_memcpy_ext(priv->phandle, addts_ioctl.ie_data,
7773 			cfg->param.addts.ie_data, cfg->param.addts.ie_data_len,
7774 			MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);
7775 
7776 	copy_len = (sizeof(addts_ioctl) - sizeof(addts_ioctl.ie_data) +
7777 		    cfg->param.addts.ie_data_len);
7778 
7779 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&addts_ioctl, copy_len,
7780 			respbuflen);
7781 	ret = copy_len;
7782 
7783 done:
7784 	if (status != MLAN_STATUS_PENDING)
7785 		kfree(req);
7786 	LEAVE();
7787 	return ret;
7788 }
7789 
7790 /**
7791  *  @brief Private IOCTL entry to send a DELTS TSPEC
7792  *
7793  *  Receive a DELTS command from the application.  The command structure
7794  *    contains a TSPEC and reason code along with space for a command result
7795  *    to be returned.  The information is packaged is sent to the wlan_cmd.c
7796  *    firmware command prep and send routines for execution in the firmware.
7797  *
7798  *  The reason code is not used for WMM implementations but is indicated in
7799  *    the 802.11e specification.
7800  *
7801  *  The return value to the application layer indicates a driver execution
7802  *    success or failure.  A successful return could still indicate a firmware
7803  *    failure via the cmd_result field copied back to the application.
7804  *
7805  *  @param priv    Pointer to the mlan_private driver data struct
7806  *  @param respbuf      A pointer to response buffer
7807  *  @param respbuflen   Available length of response buffer
7808  *
7809  *  @return         Number of bytes written if successful else negative value
7810  */
woal_priv_wmm_delts_req_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7811 static int woal_priv_wmm_delts_req_ioctl(moal_private *priv, t_u8 *respbuf,
7812 					 t_u32 respbuflen)
7813 {
7814 	mlan_ioctl_req *req = NULL;
7815 	mlan_ds_wmm_cfg *cfg = NULL;
7816 	wlan_ioctl_wmm_delts_req_t delts_ioctl;
7817 	int ret = 0, header_len = 0, copy_len = 0;
7818 	t_u8 *data_ptr;
7819 	mlan_status status = MLAN_STATUS_SUCCESS;
7820 
7821 	ENTER();
7822 
7823 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELTS);
7824 	data_ptr = respbuf + header_len;
7825 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7826 	if (req == NULL) {
7827 		ret = -ENOMEM;
7828 		goto done;
7829 	}
7830 
7831 	req->req_id = MLAN_IOCTL_WMM_CFG;
7832 	cfg = (mlan_ds_wmm_cfg *)req->pbuf;
7833 	cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
7834 
7835 	memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));
7836 
7837 	if ((int)strlen(respbuf) > header_len) {
7838 		copy_len = MIN(strlen(data_ptr), sizeof(delts_ioctl));
7839 		moal_memcpy_ext(priv->phandle, (t_u8 *)&delts_ioctl, data_ptr,
7840 				copy_len, sizeof(delts_ioctl));
7841 
7842 		cfg->param.delts.status_code =
7843 			(t_u32)delts_ioctl.ieee_reason_code;
7844 		cfg->param.delts.ie_data_len = (t_u8)delts_ioctl.ie_data_len;
7845 
7846 		moal_memcpy_ext(priv->phandle, cfg->param.delts.ie_data,
7847 				delts_ioctl.ie_data,
7848 				cfg->param.delts.ie_data_len,
7849 				MLAN_WMM_TSPEC_SIZE);
7850 
7851 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7852 		if (status != MLAN_STATUS_SUCCESS) {
7853 			ret = -EFAULT;
7854 			goto done;
7855 		}
7856 
7857 		/* Return the firmware command result back to the application
7858 		 * layer */
7859 		delts_ioctl.cmd_result = cfg->param.delts.result;
7860 		copy_len = sizeof(delts_ioctl);
7861 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&delts_ioctl,
7862 				copy_len, respbuflen);
7863 		ret = copy_len;
7864 	}
7865 
7866 done:
7867 	if (status != MLAN_STATUS_PENDING)
7868 		kfree(req);
7869 	LEAVE();
7870 	return ret;
7871 }
7872 
7873 /**
7874  *  @brief Private IOCTL entry to get/set a specified AC Queue's parameters
7875  *
7876  *  Receive a AC Queue configuration command which is used to get, set, or
7877  *    default the parameters associated with a specific WMM AC Queue.
7878  *
7879  *  @param priv         A pointer to moal_private structure
7880  *  @param respbuf      A pointer to response buffer
7881  *  @param respbuflen   Available length of response buffer
7882  *
7883  *  @return         0 --success, otherwise fail
7884  */
woal_priv_qconfig(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7885 static int woal_priv_qconfig(moal_private *priv, t_u8 *respbuf,
7886 			     t_u32 respbuflen)
7887 {
7888 	mlan_ioctl_req *req = NULL;
7889 	mlan_ds_wmm_cfg *pwmm = NULL;
7890 	mlan_ds_wmm_queue_config *pqcfg = NULL;
7891 	wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
7892 	t_u8 *data_ptr;
7893 	int ret = 0;
7894 	mlan_status status = MLAN_STATUS_SUCCESS;
7895 
7896 	ENTER();
7897 
7898 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7899 	if (req == NULL) {
7900 		ret = -ENOMEM;
7901 		goto done;
7902 	}
7903 
7904 	req->req_id = MLAN_IOCTL_WMM_CFG;
7905 	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
7906 	pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
7907 
7908 	memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
7909 	pqcfg = (mlan_ds_wmm_queue_config *)&pwmm->param.q_cfg;
7910 	data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG));
7911 
7912 	moal_memcpy_ext(priv->phandle, (t_u8 *)&qcfg_ioctl, data_ptr,
7913 			sizeof(qcfg_ioctl), sizeof(qcfg_ioctl));
7914 	pqcfg->action = qcfg_ioctl.action;
7915 	pqcfg->access_category = qcfg_ioctl.access_category;
7916 	pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
7917 
7918 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7919 	if (status != MLAN_STATUS_SUCCESS) {
7920 		ret = -EFAULT;
7921 		goto done;
7922 	}
7923 	memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
7924 	qcfg_ioctl.action = pqcfg->action;
7925 	qcfg_ioctl.access_category = pqcfg->access_category;
7926 	qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
7927 	moal_memcpy_ext(priv->phandle, data_ptr, (t_u8 *)&qcfg_ioctl,
7928 			sizeof(qcfg_ioctl),
7929 			respbuflen -
7930 				(strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG)));
7931 	ret = strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG) + sizeof(qcfg_ioctl);
7932 done:
7933 	if (status != MLAN_STATUS_PENDING)
7934 		kfree(req);
7935 	LEAVE();
7936 	return ret;
7937 }
7938 
7939 /**
7940  *  @brief Private IOCTL entry to get the status of the WMM queues
7941  *
7942  *  Return the following information for each WMM AC:
7943  *        - WMM IE Acm Required
7944  *        - Firmware Flow Required
7945  *        - Firmware Flow Established
7946  *        - Firmware Queue Enabled
7947  *        - Firmware Delivery Enabled
7948  *        - Firmware Trigger Enabled
7949  *
7950  *  @param priv    Pointer to the moal_private driver data struct
7951  *  @param respbuf      A pointer to response buffer
7952  *  @param respbuflen   Available length of response buffer
7953  *
7954  *  @return         Number of bytes written if successful else negative value
7955  */
woal_priv_wmm_queue_status_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7956 static int woal_priv_wmm_queue_status_ioctl(moal_private *priv, t_u8 *respbuf,
7957 					    t_u32 respbuflen)
7958 {
7959 	mlan_ioctl_req *req = NULL;
7960 	mlan_ds_wmm_cfg *pwmm = NULL;
7961 	wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
7962 	int ret = 0, header_len = 0;
7963 	mlan_status status = MLAN_STATUS_SUCCESS;
7964 
7965 	ENTER();
7966 
7967 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_QSTATUS);
7968 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7969 	if (req == NULL) {
7970 		ret = -ENOMEM;
7971 		goto done;
7972 	}
7973 
7974 	req->req_id = MLAN_IOCTL_WMM_CFG;
7975 	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
7976 	pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
7977 
7978 	if ((int)strlen(respbuf) == header_len) {
7979 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7980 		if (status != MLAN_STATUS_SUCCESS) {
7981 			ret = -EFAULT;
7982 			goto done;
7983 		}
7984 
7985 		memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
7986 		moal_memcpy_ext(priv->phandle, (void *)&qstatus_ioctl,
7987 				(void *)&pwmm->param.q_status,
7988 				sizeof(qstatus_ioctl), sizeof(qstatus_ioctl));
7989 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&qstatus_ioctl,
7990 				sizeof(qstatus_ioctl), respbuflen);
7991 		ret = sizeof(qstatus_ioctl);
7992 	}
7993 
7994 done:
7995 	if (status != MLAN_STATUS_PENDING)
7996 		kfree(req);
7997 	LEAVE();
7998 	return ret;
7999 }
8000 
8001 /**
8002  *  @brief Private IOCTL entry to get the status of the WMM Traffic Streams
8003  *
8004  *  @param priv    Pointer to the moal_private driver data struct
8005  *  @param respbuf      A pointer to response buffer
8006  *  @param respbuflen   Available length of response buffer
8007  *
8008  *  @return         Number of bytes written if successful else negative value
8009  */
woal_priv_wmm_ts_status_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8010 static int woal_priv_wmm_ts_status_ioctl(moal_private *priv, t_u8 *respbuf,
8011 					 t_u32 respbuflen)
8012 {
8013 	mlan_ioctl_req *req = NULL;
8014 	mlan_ds_wmm_cfg *pwmm = NULL;
8015 	wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
8016 	int ret = 0, header_len = 0;
8017 	t_u8 *data_ptr;
8018 	mlan_status status = MLAN_STATUS_SUCCESS;
8019 
8020 	ENTER();
8021 
8022 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TS_STATUS);
8023 	data_ptr = respbuf + header_len;
8024 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
8025 	if (req == NULL) {
8026 		ret = -ENOMEM;
8027 		goto done;
8028 	}
8029 
8030 	req->req_id = MLAN_IOCTL_WMM_CFG;
8031 	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
8032 	pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
8033 
8034 	memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
8035 
8036 	moal_memcpy_ext(priv->phandle, (t_u8 *)&ts_status_ioctl, data_ptr,
8037 			sizeof(ts_status_ioctl), sizeof(ts_status_ioctl));
8038 
8039 	memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
8040 	pwmm->param.ts_status.tid = ts_status_ioctl.tid;
8041 
8042 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8043 	if (status != MLAN_STATUS_SUCCESS) {
8044 		ret = -EFAULT;
8045 		goto done;
8046 	}
8047 
8048 	memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
8049 	moal_memcpy_ext(priv->phandle, (void *)&ts_status_ioctl,
8050 			(void *)&pwmm->param.ts_status, sizeof(ts_status_ioctl),
8051 			sizeof(ts_status_ioctl));
8052 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&ts_status_ioctl,
8053 			sizeof(ts_status_ioctl), respbuflen);
8054 	ret = sizeof(ts_status_ioctl);
8055 
8056 done:
8057 	if (status != MLAN_STATUS_PENDING)
8058 		kfree(req);
8059 	LEAVE();
8060 	return ret;
8061 }
8062 
8063 /**
8064  *  @brief Set/Get MAC control
8065  *
8066  *  @param priv         A pointer to moal_private structure
8067  *  @param respbuf      A pointer to response buffer
8068  *  @param respbuflen   Available length of response buffer
8069  *
8070  *  @return             Number of bytes written, negative for failure.
8071  */
woal_priv_macctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8072 static int woal_priv_macctrl(moal_private *priv, t_u8 *respbuf,
8073 			     t_u32 respbuflen)
8074 {
8075 	int data = 0;
8076 	mlan_ioctl_req *req = NULL;
8077 	mlan_ds_misc_cfg *cfg = NULL;
8078 	int ret = 0;
8079 	int user_data_len = 0, header_len = 0;
8080 	mlan_status status = MLAN_STATUS_SUCCESS;
8081 
8082 	ENTER();
8083 
8084 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MAC_CTRL);
8085 	if ((int)strlen(respbuf) == header_len) {
8086 		/* GET operation */
8087 		user_data_len = 0;
8088 	} else {
8089 		/* SET operation */
8090 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8091 	}
8092 
8093 	if (user_data_len > 1) {
8094 		PRINTM(MERROR, "Invalid number of arguments\n");
8095 		ret = -EINVAL;
8096 		goto done;
8097 	}
8098 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8099 	if (req == NULL) {
8100 		ret = -ENOMEM;
8101 		goto done;
8102 	}
8103 
8104 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
8105 	cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
8106 	req->req_id = MLAN_IOCTL_MISC_CFG;
8107 
8108 	if (user_data_len == 0)
8109 		req->action = MLAN_ACT_GET;
8110 	else {
8111 		cfg->param.mac_ctrl = (t_u32)data;
8112 		req->action = MLAN_ACT_SET;
8113 	}
8114 
8115 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8116 	if (status != MLAN_STATUS_SUCCESS) {
8117 		ret = -EFAULT;
8118 		goto done;
8119 	}
8120 
8121 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.mac_ctrl,
8122 			sizeof(data), respbuflen);
8123 	ret = sizeof(data);
8124 
8125 done:
8126 	if (status != MLAN_STATUS_PENDING)
8127 		kfree(req);
8128 	LEAVE();
8129 	return ret;
8130 }
8131 
8132 /**
8133  *  @brief Get connection status
8134  *
8135  *  @param priv         A pointer to moal_private structure
8136  *  @param respbuf      A pointer to response buffer
8137  *  @param respbuflen   Available length of response buffer
8138  *
8139  *  @return             0 --success, otherwise fail
8140  */
woal_priv_getwap(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8141 static int woal_priv_getwap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
8142 {
8143 	int ret = 0;
8144 #ifdef STA_SUPPORT
8145 	mlan_bss_info bss_info;
8146 #endif
8147 
8148 	ENTER();
8149 
8150 #ifdef STA_SUPPORT
8151 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
8152 		memset(&bss_info, 0, sizeof(bss_info));
8153 
8154 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
8155 
8156 		if (bss_info.media_connected == MTRUE) {
8157 			moal_memcpy_ext(priv->phandle, respbuf,
8158 					(t_u8 *)&bss_info.bssid,
8159 					MLAN_MAC_ADDR_LENGTH, respbuflen);
8160 		} else {
8161 			memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
8162 		}
8163 	}
8164 #endif
8165 #ifdef UAP_SUPPORT
8166 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
8167 		if (priv->bss_started) {
8168 			moal_memcpy_ext(priv->phandle, respbuf,
8169 					priv->current_addr,
8170 					MLAN_MAC_ADDR_LENGTH, respbuflen);
8171 		} else {
8172 			memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
8173 		}
8174 	}
8175 #endif
8176 	ret = MLAN_MAC_ADDR_LENGTH;
8177 	LEAVE();
8178 	return ret;
8179 }
8180 
8181 /**
8182  *  @brief Set/Get Region Code
8183  *
8184  *  @param priv         A pointer to moal_private structure
8185  *  @param respbuf      A pointer to response buffer
8186  *  @param respbuflen   Available length of response buffer
8187  *
8188  *  @return             Number of bytes written, negative for failure.
8189  */
woal_priv_region_code(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8190 static int woal_priv_region_code(moal_private *priv, t_u8 *respbuf,
8191 				 t_u32 respbuflen)
8192 {
8193 	int data = 0;
8194 	mlan_ioctl_req *req = NULL;
8195 	mlan_ds_misc_cfg *cfg = NULL;
8196 	int ret = 0;
8197 	int user_data_len = 0, header_len = 0;
8198 	mlan_status status = MLAN_STATUS_SUCCESS;
8199 
8200 	ENTER();
8201 
8202 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGION_CODE);
8203 	if ((int)strlen(respbuf) == header_len) {
8204 		/* GET operation */
8205 		user_data_len = 0;
8206 	} else {
8207 		/* SET operation */
8208 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8209 	}
8210 
8211 	if (user_data_len > 1) {
8212 		PRINTM(MERROR, "Invalid number of arguments\n");
8213 		ret = -EINVAL;
8214 		goto done;
8215 	}
8216 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8217 	if (req == NULL) {
8218 		ret = -ENOMEM;
8219 		goto done;
8220 	}
8221 
8222 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
8223 	cfg->sub_command = MLAN_OID_MISC_REGION;
8224 	req->req_id = MLAN_IOCTL_MISC_CFG;
8225 
8226 	if (user_data_len == 0)
8227 		req->action = MLAN_ACT_GET;
8228 	else {
8229 		cfg->param.region_code = (t_u32)data;
8230 		req->action = MLAN_ACT_SET;
8231 	}
8232 
8233 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8234 	if (status != MLAN_STATUS_SUCCESS) {
8235 		ret = -EFAULT;
8236 		goto done;
8237 	}
8238 
8239 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.region_code,
8240 			sizeof(data), respbuflen);
8241 	ret = sizeof(data);
8242 
8243 done:
8244 	if (status != MLAN_STATUS_PENDING)
8245 		kfree(req);
8246 	LEAVE();
8247 	return ret;
8248 }
8249 
8250 #ifdef RX_PACKET_COALESCE
8251 /**
8252  *  @brief Set/Get RX packet coalesceing setting
8253  *
8254  *  @param priv         A pointer to moal_private structure
8255  *  @param respbuf      A pointer to response buffer
8256  *  @param respbuflen   Available length of response buffer
8257  *
8258  *  @return             Number of bytes written, negative for failure.
8259  */
woal_priv_rx_pkt_coalesce_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8260 static int woal_priv_rx_pkt_coalesce_cfg(moal_private *priv, t_u8 *respbuf,
8261 					 t_u32 respbuflen)
8262 {
8263 	int ret = 0;
8264 	t_u32 data[2];
8265 	int user_data_len = 0, header_len = 0;
8266 	mlan_ds_misc_cfg *cfg = NULL;
8267 	t_u8 *data_ptr;
8268 	mlan_ioctl_req *req = NULL;
8269 	mlan_status status = MLAN_STATUS_SUCCESS;
8270 
8271 	ENTER();
8272 
8273 	data_ptr = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG);
8274 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG);
8275 	if ((int)strlen(respbuf) == header_len) {
8276 		/* GET operation */
8277 		user_data_len = 0;
8278 	} else {
8279 		/* SET operation */
8280 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
8281 				&user_data_len);
8282 	}
8283 
8284 	if (sizeof(int) * user_data_len > sizeof(data)) {
8285 		PRINTM(MERROR, "Too many arguments\n");
8286 		ret = -EINVAL;
8287 		goto done;
8288 	}
8289 
8290 	if ((user_data_len != 0) && (user_data_len != 2)) {
8291 		PRINTM(MERROR, "Invalid arguments\n");
8292 		ret = -EINVAL;
8293 		goto done;
8294 	}
8295 
8296 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8297 	if (req == NULL) {
8298 		ret = -ENOMEM;
8299 		goto done;
8300 	}
8301 
8302 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
8303 	cfg->sub_command = MLAN_OID_MISC_RX_PACKET_COALESCE;
8304 	req->req_id = MLAN_IOCTL_MISC_CFG;
8305 
8306 	if (user_data_len == 0) {
8307 		req->action = MLAN_ACT_GET;
8308 	} else {
8309 		req->action = MLAN_ACT_SET;
8310 		cfg->param.rx_coalesce.packet_threshold = data[0];
8311 		cfg->param.rx_coalesce.delay = data[1];
8312 	}
8313 
8314 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8315 	if (status != MLAN_STATUS_SUCCESS) {
8316 		ret = -EFAULT;
8317 		goto done;
8318 	}
8319 
8320 	moal_memcpy_ext(
8321 		priv->phandle, respbuf,
8322 		(mlan_ds_misc_rx_packet_coalesce *)&cfg->param.rx_coalesce,
8323 		req->buf_len, respbuflen);
8324 	ret = req->buf_len;
8325 
8326 done:
8327 	LEAVE();
8328 	return ret;
8329 }
8330 #endif
8331 /**
8332  *  @brief Set/Get FW side mac address
8333  *
8334  *  @param priv         A pointer to moal_private structure
8335  *  @param respbuf      A pointer to response buffer
8336  *  @param respbuflen   Available length of response buffer
8337  *
8338  *  @return             0 --success, otherwise fail
8339  */
woal_priv_fwmacaddr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8340 static int woal_priv_fwmacaddr(moal_private *priv, t_u8 *respbuf,
8341 			       t_u32 respbuflen)
8342 {
8343 	t_u8 data[ETH_ALEN];
8344 	int ret = 0;
8345 	int header_len = 0;
8346 	mlan_ioctl_req *req = NULL;
8347 	mlan_ds_bss *bss = NULL;
8348 	mlan_status status = MLAN_STATUS_SUCCESS;
8349 
8350 	ENTER();
8351 
8352 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_FWMACADDR);
8353 
8354 	/* Allocate an IOCTL request buffer */
8355 	req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
8356 	if (req == NULL) {
8357 		ret = -ENOMEM;
8358 		goto done;
8359 	}
8360 	/* Fill request buffer */
8361 	bss = (mlan_ds_bss *)req->pbuf;
8362 	bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
8363 	req->req_id = MLAN_IOCTL_BSS;
8364 
8365 	if ((int)strlen(respbuf) == header_len) {
8366 		/* GET operation */
8367 		req->action = MLAN_ACT_GET;
8368 	} else {
8369 		/* SET operation */
8370 		req->action = MLAN_ACT_SET;
8371 		memset(data, 0, sizeof(data));
8372 		woal_mac2u8(data, respbuf + header_len);
8373 		moal_memcpy_ext(priv->phandle, bss->param.mac_addr, data,
8374 				ETH_ALEN, sizeof(mlan_802_11_mac_addr));
8375 	}
8376 
8377 	/* Send IOCTL request to MLAN */
8378 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8379 	if (status != MLAN_STATUS_SUCCESS) {
8380 		ret = -EFAULT;
8381 		goto done;
8382 	}
8383 
8384 	moal_memcpy_ext(priv->phandle, respbuf, bss->param.mac_addr,
8385 			sizeof(data), respbuflen);
8386 	ret = sizeof(data);
8387 	HEXDUMP("FW MAC Addr:", respbuf, ETH_ALEN);
8388 
8389 done:
8390 	if (status != MLAN_STATUS_PENDING)
8391 		kfree(req);
8392 	LEAVE();
8393 	return ret;
8394 }
8395 
8396 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
8397 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
8398 /**
8399  *  @brief Set offchannel
8400  *
8401  *  @param priv         A pointer to moal_private structure
8402  *  @param respbuf      A pointer to response buffer
8403  *  @param respbuflen   Available length of response buffer
8404  *
8405  *  @return             0 --success, otherwise fail
8406  */
woal_priv_offchannel(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8407 static int woal_priv_offchannel(moal_private *priv, t_u8 *respbuf,
8408 				t_u32 respbuflen)
8409 {
8410 	int data[4];
8411 	int ret = 0;
8412 	t_u8 status = 1;
8413 	t_u8 chan_type = CHAN_NO_HT;
8414 	int user_data_len = 0, header_len = 0;
8415 
8416 	ENTER();
8417 
8418 	memset(data, 0, sizeof(data));
8419 
8420 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_OFFCHANNEL);
8421 
8422 	if (header_len == (int)strlen(respbuf)) {
8423 		/* Query current remain on channel status */
8424 		if (priv->phandle->remain_on_channel)
8425 			ret = sprintf(respbuf,
8426 				      "There is pending remain on channel from bss %d\n",
8427 				      priv->phandle->remain_bss_index) +
8428 			      1;
8429 		else
8430 			ret = sprintf(respbuf,
8431 				      "There is no pending remain on channel\n") +
8432 			      1;
8433 		goto done;
8434 	} else
8435 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
8436 				&user_data_len);
8437 
8438 	if (sizeof(int) * user_data_len > sizeof(data)) {
8439 		PRINTM(MERROR, "Too many arguments\n");
8440 		ret = -EINVAL;
8441 		goto done;
8442 	}
8443 
8444 	if (user_data_len >= 1) {
8445 		if ((data[0] != 0) && (data[0] != 1)) {
8446 			PRINTM(MERROR, "action (%d) must be either 0 or 1\n",
8447 			       data[0]);
8448 			ret = -EINVAL;
8449 			goto done;
8450 		}
8451 	}
8452 	if (user_data_len == 2) {
8453 		if (data[0] == 1) {
8454 			PRINTM(MERROR,
8455 			       "channel and duration must both the mentioned\n");
8456 			ret = -EINVAL;
8457 			goto done;
8458 		} else {
8459 			PRINTM(MWARN,
8460 			       "extra arguments are ignored since action is 'cancel'\n");
8461 		}
8462 	}
8463 	if (user_data_len >= 3) {
8464 		if (data[0] == 1) {
8465 			if (data[1] < 0) {
8466 				PRINTM(MERROR, "channel cannot be negative\n");
8467 				ret = -EINVAL;
8468 				goto done;
8469 			}
8470 			if (data[2] < 0) {
8471 				PRINTM(MERROR, "duration cannot be negative\n");
8472 				ret = -EINVAL;
8473 				goto done;
8474 			}
8475 			if (user_data_len == 4) {
8476 				if (data[3] &&
8477 				    (data[3] != CHANNEL_BW_40MHZ_ABOVE) &&
8478 				    (data[3] != CHANNEL_BW_40MHZ_BELOW) &&
8479 				    (data[3] != CHANNEL_BW_80MHZ)) {
8480 					PRINTM(MERROR, "invalid bandwidth");
8481 					ret = -EINVAL;
8482 					goto done;
8483 				}
8484 				switch (data[3]) {
8485 				case CHANNEL_BW_40MHZ_ABOVE:
8486 					chan_type = CHAN_HT40PLUS;
8487 					break;
8488 				case CHANNEL_BW_40MHZ_BELOW:
8489 					chan_type = CHAN_HT40MINUS;
8490 					break;
8491 				case CHANNEL_BW_80MHZ:
8492 					chan_type = CHAN_VHT80;
8493 					break;
8494 				default:
8495 					break;
8496 				}
8497 			}
8498 		}
8499 	}
8500 
8501 	if (data[0] == 0) {
8502 		if (!priv->phandle->remain_on_channel) {
8503 			ret = sprintf(respbuf,
8504 				      "There is no pending remain on channel to be canceled\n") +
8505 			      1;
8506 			goto done;
8507 		}
8508 		if (woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
8509 							MTRUE, &status, NULL, 0,
8510 							0)) {
8511 			PRINTM(MERROR, "remain_on_channel: Failed to cancel\n");
8512 			ret = -EFAULT;
8513 			goto done;
8514 		}
8515 		if (status == MLAN_STATUS_SUCCESS)
8516 			priv->phandle->remain_on_channel = MFALSE;
8517 	} else if (data[0] == 1) {
8518 		if (woal_cfg80211_remain_on_channel_cfg(
8519 			    priv, MOAL_IOCTL_WAIT, MFALSE, &status,
8520 			    ieee80211_get_channel(
8521 				    priv->wdev->wiphy,
8522 				    ieee80211_channel_to_frequency(
8523 					    data[1]
8524 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
8525 					    ,
8526 					    (data[1] <= 14 ?
8527 						     IEEE80211_BAND_2GHZ :
8528 						     IEEE80211_BAND_5GHZ)
8529 #endif
8530 						    )),
8531 			    chan_type, (t_u32)data[2])) {
8532 			PRINTM(MERROR, "remain_on_channel: Failed to start\n");
8533 			ret = -EFAULT;
8534 			goto done;
8535 		}
8536 		if (status == MLAN_STATUS_SUCCESS) {
8537 			priv->phandle->remain_on_channel = MTRUE;
8538 			priv->phandle->remain_bss_index = priv->bss_index;
8539 		}
8540 	}
8541 
8542 	if (status != MLAN_STATUS_SUCCESS)
8543 		ret = -EFAULT;
8544 	else
8545 		ret = sprintf(respbuf, "OK\n") + 1;
8546 
8547 done:
8548 	LEAVE();
8549 	return ret;
8550 }
8551 #endif
8552 #endif
8553 
8554 /**
8555  *  @brief Set/Get dscp map
8556  *
8557  *  @param priv         A pointer to moal_private structure
8558  *  @param respbuf      A pointer to response buffer
8559  *  @param respbuflen   Available length of response buffer
8560  *
8561  *  @return             0 --success, otherwise fail
8562  */
woal_priv_set_get_dscp_map(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8563 static int woal_priv_set_get_dscp_map(moal_private *priv, t_u8 *respbuf,
8564 				      t_u32 respbuflen)
8565 {
8566 	int ret = MLAN_STATUS_SUCCESS;
8567 	t_u8 *pos = NULL;
8568 	int copy_size = 0, header_len = 0;
8569 
8570 	ENTER();
8571 
8572 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DSCP_MAP);
8573 	if ((int)strlen(respbuf) != header_len) {
8574 		/* SET operation */
8575 		pos = respbuf + header_len;
8576 		moal_memcpy_ext(priv->phandle, priv->dscp_map, pos,
8577 				sizeof(priv->dscp_map), sizeof(priv->dscp_map));
8578 	}
8579 
8580 	copy_size = MIN(sizeof(priv->dscp_map), respbuflen);
8581 	moal_memcpy_ext(priv->phandle, respbuf, priv->dscp_map, copy_size,
8582 			respbuflen);
8583 	ret = copy_size;
8584 
8585 	LEAVE();
8586 	return ret;
8587 }
8588 
8589 /**
8590  *  @brief Get extended driver version
8591  *
8592  *  @param priv         A pointer to moal_private structure
8593  *  @param respbuf      A pointer to response buffer
8594  *  @param respbuflen   Available length of response buffer
8595  *
8596  *  @return             Number of bytes written, negative for failure.
8597  */
woal_priv_get_driver_verext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8598 static int woal_priv_get_driver_verext(moal_private *priv, t_u8 *respbuf,
8599 				       t_u32 respbuflen)
8600 {
8601 	int data = 0;
8602 	mlan_ds_get_info *info = NULL;
8603 	mlan_ioctl_req *req = NULL;
8604 	int ret = 0;
8605 	int copy_size = 0;
8606 	int user_data_len = 0, header_len = 0;
8607 	mlan_status status = MLAN_STATUS_SUCCESS;
8608 
8609 	ENTER();
8610 
8611 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
8612 	if (req == NULL) {
8613 		ret = -ENOMEM;
8614 		goto done;
8615 	}
8616 
8617 	info = (mlan_ds_get_info *)req->pbuf;
8618 	info->sub_command = MLAN_OID_GET_VER_EXT;
8619 	req->req_id = MLAN_IOCTL_GET_INFO;
8620 	req->action = MLAN_ACT_GET;
8621 
8622 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_VEREXT);
8623 
8624 	if ((int)strlen(respbuf) == header_len) {
8625 		/* GET operation */
8626 		user_data_len = 0;
8627 	} else {
8628 		/* SET operation */
8629 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8630 	}
8631 
8632 	if (user_data_len > 1) {
8633 		PRINTM(MERROR, "Too many arguments\n");
8634 		ret = -EINVAL;
8635 		goto done;
8636 	}
8637 	info->param.ver_ext.version_str_sel = data;
8638 	if (((t_s32)(info->param.ver_ext.version_str_sel)) < 0) {
8639 		PRINTM(MERROR, "Invalid arguments!\n");
8640 		ret = -EINVAL;
8641 		goto done;
8642 	}
8643 
8644 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8645 	if (status != MLAN_STATUS_SUCCESS) {
8646 		ret = -EFAULT;
8647 		goto done;
8648 	}
8649 
8650 	/*
8651 	 * Set the amount to copy back to the application as the minimum of the
8652 	 *   available assoc resp data or the buffer provided by the application
8653 	 */
8654 	copy_size = MIN(strlen(info->param.ver_ext.version_str), respbuflen);
8655 	moal_memcpy_ext(priv->phandle, respbuf, info->param.ver_ext.version_str,
8656 			copy_size, respbuflen);
8657 	ret = copy_size;
8658 	PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
8659 	       info->param.ver_ext.version_str);
8660 
8661 done:
8662 	if (status != MLAN_STATUS_PENDING)
8663 		kfree(req);
8664 	LEAVE();
8665 	return ret;
8666 }
8667 
8668 #ifdef USB
8669 #ifdef CONFIG_USB_SUSPEND
8670 /**
8671  *  @brief This function makes USB device to suspend.
8672  *
8673  *  @param priv         A pointer to moal_private structure
8674  *  @param respbuf      A pointer to response buffer
8675  *  @param respbuflen   Available length of response buffer
8676  *
8677  *  @return             Number of bytes written, negative for failure.
8678  */
woal_priv_enter_usb_suspend(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8679 static int woal_priv_enter_usb_suspend(moal_private *priv, t_u8 *respbuf,
8680 				       t_u32 respbuflen)
8681 {
8682 	int ret = 0;
8683 
8684 	ENTER();
8685 	ret = woal_enter_usb_suspend(priv->phandle);
8686 	moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
8687 	ret = sizeof(int);
8688 
8689 	LEAVE();
8690 	return ret;
8691 }
8692 
8693 /**
8694  *  @brief This function makes USB device to resume.
8695  *
8696  *  @param priv         A pointer to moal_private structure
8697  *  @param respbuf      A pointer to response buffer
8698  *  @param respbuflen   Available length of response buffer
8699  *
8700  *  @return             Number of bytes written, negative for failure.
8701  */
woal_priv_exit_usb_suspend(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8702 static int woal_priv_exit_usb_suspend(moal_private *priv, t_u8 *respbuf,
8703 				      t_u32 respbuflen)
8704 {
8705 	int ret = 0;
8706 
8707 	ENTER();
8708 	ret = woal_exit_usb_suspend(priv->phandle);
8709 	moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
8710 	ret = sizeof(int);
8711 
8712 	LEAVE();
8713 	return ret;
8714 }
8715 #endif /* CONFIG_USB_SUSPEND */
8716 #endif
8717 
8718 #if defined(STA_SUPPORT) && defined(STA_WEXT)
8719 /**
8720  *  @brief SET/Get radio
8721  *
8722  *  @param priv         A pointer to moal_private structure
8723  *  @param respbuf      A pointer to response buffer
8724  *  @param respbuflen   Available length of response buffer
8725  *
8726  *  @return             Number of bytes written, negative for failure.
8727  */
woal_priv_radio_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8728 static int woal_priv_radio_ctrl(moal_private *priv, t_u8 *respbuf,
8729 				t_u32 respbuflen)
8730 {
8731 	int ret = 0, option = 0;
8732 	int user_data_len = 0, header_len = 0;
8733 	mlan_bss_info bss_info;
8734 
8735 	ENTER();
8736 
8737 	memset(&bss_info, 0, sizeof(bss_info));
8738 
8739 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RADIO_CTRL);
8740 
8741 	if ((int)strlen(respbuf) == header_len) {
8742 		/* GET operation */
8743 		user_data_len = 0;
8744 	} else {
8745 		/* SET operation */
8746 		parse_arguments(respbuf + header_len, &option, 1,
8747 				&user_data_len);
8748 	}
8749 
8750 	if (user_data_len > 1) {
8751 		PRINTM(MERROR, "Too many arguments\n");
8752 		ret = -EINVAL;
8753 		goto done;
8754 	}
8755 	if (user_data_len == 1) {
8756 		/* Set radio */
8757 		if (option < 0 || option > 1) {
8758 			PRINTM(MERROR, "Invalid arguments!\n");
8759 			ret = -EINVAL;
8760 			goto done;
8761 		}
8762 		if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8)option))
8763 			ret = -EFAULT;
8764 		goto done;
8765 	} else {
8766 		/* Get radio status */
8767 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
8768 		moal_memcpy_ext(priv->phandle, respbuf, &bss_info.radio_on,
8769 				sizeof(bss_info.radio_on), respbuflen);
8770 		ret = sizeof(bss_info.radio_on);
8771 	}
8772 done:
8773 	LEAVE();
8774 	return ret;
8775 }
8776 #endif
8777 
8778 /**
8779  *  @brief Implement WMM enable command
8780  *
8781  *  @param priv         A pointer to moal_private structure
8782  *  @param respbuf      A pointer to response buffer
8783  *  @param respbuflen   Available length of response buffer
8784  *
8785  *  @return             Number of bytes written, negative for failure.
8786  */
woal_priv_wmm_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8787 static int woal_priv_wmm_cfg(moal_private *priv, t_u8 *respbuf,
8788 			     t_u32 respbuflen)
8789 {
8790 	int data = 0;
8791 	mlan_ds_wmm_cfg *wmm = NULL;
8792 	mlan_ioctl_req *req = NULL;
8793 	int ret = 0;
8794 	int user_data_len = 0, header_len = 0;
8795 	mlan_status status = MLAN_STATUS_SUCCESS;
8796 
8797 	ENTER();
8798 
8799 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
8800 	if (req == NULL) {
8801 		ret = -ENOMEM;
8802 		goto done;
8803 	}
8804 
8805 	wmm = (mlan_ds_wmm_cfg *)req->pbuf;
8806 	wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
8807 	req->req_id = MLAN_IOCTL_WMM_CFG;
8808 
8809 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WMM_CFG);
8810 
8811 	if ((int)strlen(respbuf) == header_len) {
8812 		/* GET operation */
8813 		req->action = MLAN_ACT_GET;
8814 		user_data_len = 0;
8815 	} else {
8816 		/* SET operation */
8817 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8818 		if (user_data_len == 1) {
8819 			/* Set wmm */
8820 			if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
8821 				PRINTM(MERROR, "Invalid arguments!\n");
8822 				ret = -EINVAL;
8823 				goto done;
8824 			}
8825 			req->action = MLAN_ACT_SET;
8826 			if (data == CMD_DISABLED)
8827 				wmm->param.wmm_enable = MFALSE;
8828 			else
8829 				wmm->param.wmm_enable = MTRUE;
8830 		} else {
8831 			PRINTM(MERROR, "Too many arguments\n");
8832 			ret = -EINVAL;
8833 			goto done;
8834 		}
8835 	}
8836 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8837 	if (status != MLAN_STATUS_SUCCESS) {
8838 		ret = -EFAULT;
8839 		goto done;
8840 	}
8841 
8842 	moal_memcpy_ext(priv->phandle, respbuf, &wmm->param.wmm_enable,
8843 			sizeof(wmm->param.wmm_enable), respbuflen);
8844 	ret = sizeof(wmm->param.wmm_enable);
8845 
8846 done:
8847 	if (status != MLAN_STATUS_PENDING)
8848 		kfree(req);
8849 	LEAVE();
8850 	return ret;
8851 }
8852 
8853 /**
8854  *  @brief Implement Mininum BA Threshold cfg command
8855  *
8856  *  @param priv         A pointer to moal_private structure
8857  *  @param respbuf      A pointer to response buffer
8858  *  @param respbuflen   Available length of response buffer
8859  *
8860  *  @return             Number of bytes written, negative for failure.
8861  */
woal_priv_min_ba_threshold_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8862 static int woal_priv_min_ba_threshold_cfg(moal_private *priv, t_u8 *respbuf,
8863 					  t_u32 respbuflen)
8864 {
8865 	int data = 0;
8866 	mlan_ds_11n_cfg *cfg_11n = NULL;
8867 	mlan_ioctl_req *req = NULL;
8868 	int ret = 0;
8869 	int user_data_len = 0, header_len = 0;
8870 	mlan_status status = MLAN_STATUS_SUCCESS;
8871 
8872 	ENTER();
8873 
8874 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
8875 	if (req == NULL) {
8876 		ret = -ENOMEM;
8877 		goto done;
8878 	}
8879 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
8880 	cfg_11n->sub_command = MLAN_OID_11N_CFG_MIN_BA_THRESHOLD;
8881 	req->req_id = MLAN_IOCTL_11N_CFG;
8882 
8883 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIN_BA_THRESH_CFG);
8884 
8885 	if ((int)strlen(respbuf) == header_len) {
8886 		/* GET operation */
8887 		req->action = MLAN_ACT_GET;
8888 		user_data_len = 0;
8889 	} else {
8890 		/* SET operation */
8891 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8892 		if (user_data_len == 1) {
8893 			/* Set minimum BA Threshold */
8894 			if ((data < 0) || (data > 16)) {
8895 				PRINTM(MERROR,
8896 				       "Error: Valid minimum BA threshold range (0-16)!\n");
8897 				ret = -EINVAL;
8898 				goto done;
8899 			}
8900 			req->action = MLAN_ACT_SET;
8901 			cfg_11n->param.min_ba_threshold = data;
8902 		} else {
8903 			PRINTM(MERROR, "Too many arguments\n");
8904 			ret = -EINVAL;
8905 			goto done;
8906 		}
8907 	}
8908 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8909 	if (status != MLAN_STATUS_SUCCESS) {
8910 		ret = -EFAULT;
8911 		goto done;
8912 	}
8913 
8914 	moal_memcpy_ext(priv->phandle, respbuf,
8915 			&cfg_11n->param.min_ba_threshold,
8916 			sizeof(cfg_11n->param.min_ba_threshold), respbuflen);
8917 	ret = sizeof(cfg_11n->param.min_ba_threshold);
8918 
8919 done:
8920 	if (status != MLAN_STATUS_PENDING)
8921 		kfree(req);
8922 	LEAVE();
8923 	return ret;
8924 }
8925 
8926 #if defined(STA_SUPPORT)
8927 /**
8928  *  @brief Implement 802.11D enable command
8929  *
8930  *  @param priv         A pointer to moal_private structure
8931  *  @param respbuf      A pointer to response buffer
8932  *  @param respbuflen   Available length of response buffer
8933  *
8934  *  @return             Number of bytes written, negative for failure.
8935  */
woal_priv_11d_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8936 static int woal_priv_11d_cfg(moal_private *priv, t_u8 *respbuf,
8937 			     t_u32 respbuflen)
8938 {
8939 	int data = 0;
8940 	mlan_ds_11d_cfg *pcfg_11d = NULL;
8941 	mlan_ioctl_req *req = NULL;
8942 	int ret = 0;
8943 	int user_data_len = 0, header_len = 0;
8944 	mlan_status status = MLAN_STATUS_SUCCESS;
8945 
8946 	ENTER();
8947 
8948 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
8949 	if (req == NULL) {
8950 		ret = -ENOMEM;
8951 		goto done;
8952 	}
8953 
8954 	pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
8955 	pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
8956 	req->req_id = MLAN_IOCTL_11D_CFG;
8957 
8958 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CFG);
8959 
8960 	if ((int)strlen(respbuf) == header_len) {
8961 		/* GET operation */
8962 		req->action = MLAN_ACT_GET;
8963 		user_data_len = 0;
8964 	} else {
8965 		/* SET operation */
8966 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8967 		if (user_data_len == 1) {
8968 			if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
8969 				PRINTM(MERROR, "Invalid arguments!\n");
8970 				ret = -EINVAL;
8971 				goto done;
8972 			}
8973 			req->action = MLAN_ACT_SET;
8974 			if (data == CMD_DISABLED)
8975 				pcfg_11d->param.enable_11d = MFALSE;
8976 			else
8977 				pcfg_11d->param.enable_11d = MTRUE;
8978 		} else {
8979 			PRINTM(MERROR, "Too many arguments\n");
8980 			ret = -EINVAL;
8981 			goto done;
8982 		}
8983 	}
8984 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8985 	if (status != MLAN_STATUS_SUCCESS) {
8986 		ret = -EFAULT;
8987 		goto done;
8988 	}
8989 
8990 	moal_memcpy_ext(priv->phandle, respbuf, &pcfg_11d->param.enable_11d,
8991 			sizeof(pcfg_11d->param.enable_11d), respbuflen);
8992 	ret = sizeof(pcfg_11d->param.enable_11d);
8993 
8994 done:
8995 	if (status != MLAN_STATUS_PENDING)
8996 		kfree(req);
8997 	LEAVE();
8998 	return ret;
8999 }
9000 
9001 /**
9002  *  @brief Implement 802.11D clear chan table command
9003  *
9004  *  @param priv         A pointer to moal_private structure
9005  *  @param respbuf      A pointer to response buffer
9006  *  @param respbuflen   Available length of response buffer
9007  *
9008  *  @return             0 --success, otherwise fail
9009  */
woal_priv_11d_clr_chan_tbl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9010 static int woal_priv_11d_clr_chan_tbl(moal_private *priv, t_u8 *respbuf,
9011 				      t_u32 respbuflen)
9012 {
9013 	mlan_ds_11d_cfg *pcfg_11d = NULL;
9014 	mlan_ioctl_req *req = NULL;
9015 	int ret = 0;
9016 	int header_len = 0;
9017 	mlan_status status = MLAN_STATUS_SUCCESS;
9018 
9019 	ENTER();
9020 
9021 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
9022 	if (req == NULL) {
9023 		ret = -ENOMEM;
9024 		goto done;
9025 	}
9026 
9027 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CLR_TBL);
9028 
9029 	if ((int)strlen(respbuf) != header_len) {
9030 		PRINTM(MERROR, "Too many arguments\n");
9031 		ret = -EINVAL;
9032 		goto done;
9033 	}
9034 	pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
9035 	pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
9036 	req->req_id = MLAN_IOCTL_11D_CFG;
9037 	req->action = MLAN_ACT_SET;
9038 
9039 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9040 	if (status != MLAN_STATUS_SUCCESS) {
9041 		ret = -EFAULT;
9042 		goto done;
9043 	}
9044 
9045 done:
9046 	if (status != MLAN_STATUS_PENDING)
9047 		kfree(req);
9048 	LEAVE();
9049 	return ret;
9050 }
9051 #endif
9052 
9053 #ifndef OPCHAN
9054 /**
9055  *  @brief Set/Get WWS mode
9056  *
9057  *  @param priv         A pointer to moal_private structure
9058  *  @param respbuf      A pointer to response buffer
9059  *  @param respbuflen   Available length of response buffer
9060  *
9061  *  @return             Number of bytes written, negative for failure.
9062  */
woal_priv_wws_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9063 static int woal_priv_wws_cfg(moal_private *priv, t_u8 *respbuf,
9064 			     t_u32 respbuflen)
9065 {
9066 	int data = 0;
9067 	mlan_ds_misc_cfg *wws = NULL;
9068 	mlan_ioctl_req *req = NULL;
9069 	int ret = 0;
9070 	int user_data_len = 0, header_len = 0;
9071 	mlan_status status = MLAN_STATUS_SUCCESS;
9072 
9073 	ENTER();
9074 
9075 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
9076 	if (req == NULL) {
9077 		ret = -ENOMEM;
9078 		goto done;
9079 	}
9080 
9081 	wws = (mlan_ds_misc_cfg *)req->pbuf;
9082 	wws->sub_command = MLAN_OID_MISC_WWS;
9083 	req->req_id = MLAN_IOCTL_MISC_CFG;
9084 
9085 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WWS_CFG);
9086 
9087 	if ((int)strlen(respbuf) == header_len) {
9088 		/* GET operation */
9089 		req->action = MLAN_ACT_GET;
9090 		user_data_len = 0;
9091 	} else {
9092 		/* SET operation */
9093 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9094 		if (user_data_len == 1) {
9095 			if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
9096 				PRINTM(MERROR,
9097 				       "Invalid arguments, WWS config not changed!\n");
9098 				ret = -EINVAL;
9099 				goto done;
9100 			}
9101 			req->action = MLAN_ACT_SET;
9102 			wws->param.wws_cfg = (t_u16)data;
9103 		} else {
9104 			PRINTM(MERROR, "Too many arguments\n");
9105 			ret = -EINVAL;
9106 			goto done;
9107 		}
9108 	}
9109 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9110 	if (status != MLAN_STATUS_SUCCESS) {
9111 		ret = -EFAULT;
9112 		goto done;
9113 	}
9114 
9115 	moal_memcpy_ext(priv->phandle, respbuf, &wws->param.wws_cfg,
9116 			sizeof(wws->param.wws_cfg), respbuflen);
9117 	ret = sizeof(wws->param.wws_cfg);
9118 
9119 done:
9120 	if (status != MLAN_STATUS_PENDING)
9121 		kfree(req);
9122 	LEAVE();
9123 	return ret;
9124 }
9125 #endif
9126 
9127 #if defined(REASSOCIATION)
9128 /**
9129  *  @brief Set/Get reassociation settings
9130  *
9131  *  @param priv         A pointer to moal_private structure
9132  *  @param respbuf      A pointer to response buffer
9133  *  @param respbuflen   Available length of response buffer
9134  *
9135  *  @return             Number of bytes written, negative for failure.
9136  */
woal_priv_set_get_reassoc(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9137 static int woal_priv_set_get_reassoc(moal_private *priv, t_u8 *respbuf,
9138 				     t_u32 respbuflen)
9139 {
9140 	moal_handle *handle = priv->phandle;
9141 	int data = 0;
9142 	int ret = 0;
9143 	int user_data_len = 0, header_len = 0;
9144 
9145 	ENTER();
9146 
9147 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REASSOCTRL);
9148 
9149 	if ((int)strlen(respbuf) == header_len) {
9150 		/* GET operation */
9151 		user_data_len = 0;
9152 		data = (int)(priv->reassoc_on);
9153 		moal_memcpy_ext(handle, respbuf, &data, sizeof(data),
9154 				respbuflen);
9155 		ret = sizeof(data);
9156 	} else {
9157 		/* SET operation */
9158 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9159 		if (user_data_len == 1) {
9160 			if (data == 0) {
9161 				handle->reassoc_on &= ~MBIT(priv->bss_index);
9162 				priv->reassoc_on = MFALSE;
9163 				priv->reassoc_required = MFALSE;
9164 				if (!handle->reassoc_on &&
9165 				    handle->is_reassoc_timer_set == MTRUE) {
9166 					woal_cancel_timer(
9167 						&handle->reassoc_timer);
9168 					handle->is_reassoc_timer_set = MFALSE;
9169 				}
9170 			} else if (data == 1) {
9171 				handle->reassoc_on |= MBIT(priv->bss_index);
9172 				priv->reassoc_on = MTRUE;
9173 			} else {
9174 				PRINTM(MERROR, "Invalid arguments!\n");
9175 				ret = -EINVAL;
9176 			}
9177 		} else {
9178 			PRINTM(MERROR, "Too many arguments\n");
9179 			ret = -EINVAL;
9180 		}
9181 	}
9182 
9183 	LEAVE();
9184 	return ret;
9185 }
9186 #endif /* REASSOCIATION */
9187 
9188 /**
9189  *  @brief Get Transmit buffer size
9190  *
9191  *  @param priv         A pointer to moal_private structure
9192  *  @param respbuf      A pointer to response buffer
9193  *  @param respbuflen   Available length of response buffer
9194  *
9195  *  @return             Number of bytes written, negative for failure.
9196  */
woal_priv_txbuf_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9197 static int woal_priv_txbuf_cfg(moal_private *priv, t_u8 *respbuf,
9198 			       t_u32 respbuflen)
9199 {
9200 	mlan_ds_11n_cfg *cfg_11n = NULL;
9201 	mlan_ioctl_req *req = NULL;
9202 	int ret = 0;
9203 	int buf_size = 0, header_len = 0;
9204 	mlan_status status = MLAN_STATUS_SUCCESS;
9205 
9206 	ENTER();
9207 
9208 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
9209 	if (req == NULL) {
9210 		ret = -ENOMEM;
9211 		goto done;
9212 	}
9213 
9214 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
9215 	cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
9216 	req->req_id = MLAN_IOCTL_11N_CFG;
9217 
9218 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXBUF_CFG);
9219 
9220 	if ((int)strlen(respbuf) != header_len) {
9221 		PRINTM(MERROR,
9222 		       "Don't support set Tx buffer size after driver loaded!\n");
9223 		ret = -EINVAL;
9224 		goto done;
9225 	} else {
9226 		/* Get Tx buffer size from MLAN */
9227 		req->action = MLAN_ACT_GET;
9228 	}
9229 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9230 	if (status != MLAN_STATUS_SUCCESS) {
9231 		ret = -EFAULT;
9232 		goto done;
9233 	}
9234 
9235 	buf_size = cfg_11n->param.tx_buf_size;
9236 	moal_memcpy_ext(priv->phandle, respbuf, &buf_size, sizeof(buf_size),
9237 			respbuflen);
9238 	ret = sizeof(buf_size);
9239 
9240 done:
9241 	if (status != MLAN_STATUS_PENDING)
9242 		kfree(req);
9243 	LEAVE();
9244 	return ret;
9245 }
9246 
9247 #ifdef STA_SUPPORT
9248 /**
9249  *  @brief Set/Get auth type
9250  *
9251  *  @param priv         A pointer to moal_private structure
9252  *  @param respbuf      A pointer to response buffer
9253  *  @param respbuflen   Available length of response buffer
9254  *
9255  *  @return             Number of bytes written, negative for failure.
9256  */
woal_priv_auth_type(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9257 static int woal_priv_auth_type(moal_private *priv, t_u8 *respbuf,
9258 			       t_u32 respbuflen)
9259 {
9260 	int auth_type = 0;
9261 	t_u32 auth_mode;
9262 	int ret = 0;
9263 	int user_data_len = 0, header_len = 0;
9264 
9265 	ENTER();
9266 
9267 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTH_TYPE);
9268 
9269 	if ((int)strlen(respbuf) == header_len) {
9270 		/* GET operation */
9271 		if (MLAN_STATUS_SUCCESS !=
9272 		    woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
9273 			ret = -EFAULT;
9274 			goto done;
9275 		}
9276 		user_data_len = 0;
9277 		auth_type = auth_mode;
9278 		moal_memcpy_ext(priv->phandle, respbuf, &auth_type,
9279 				sizeof(auth_type), respbuflen);
9280 		ret = sizeof(auth_type);
9281 		goto done;
9282 	} else {
9283 		/* SET operation */
9284 		parse_arguments(respbuf + header_len, &auth_type, 1,
9285 				&user_data_len);
9286 		if (user_data_len == 1) {
9287 			PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
9288 			if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
9289 			     (auth_type > MLAN_AUTH_MODE_SAE)) &&
9290 			    (auth_type != MLAN_AUTH_MODE_AUTO)) {
9291 				ret = -EINVAL;
9292 				goto done;
9293 			}
9294 			auth_mode = auth_type;
9295 			if (MLAN_STATUS_SUCCESS !=
9296 			    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT,
9297 					       auth_mode)) {
9298 				ret = -EFAULT;
9299 				goto done;
9300 			}
9301 		} else {
9302 			PRINTM(MERROR, "Too many arguments\n");
9303 			ret = -EINVAL;
9304 		}
9305 	}
9306 
9307 done:
9308 	LEAVE();
9309 	return ret;
9310 }
9311 #endif
9312 
9313 /**
9314  *  @brief Set/get user provisioned local power constraint
9315  *
9316  *  @param priv         A pointer to moal_private structure
9317  *  @param respbuf      A pointer to response buffer
9318  *  @param respbuflen   Available length of response buffer
9319  *
9320  *  @return             Number of bytes written, negative for failure.
9321  */
woal_priv_11h_local_pwr_constraint(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9322 static int woal_priv_11h_local_pwr_constraint(moal_private *priv, t_u8 *respbuf,
9323 					      t_u32 respbuflen)
9324 {
9325 	int data = 0;
9326 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
9327 	mlan_ioctl_req *req = NULL;
9328 	int ret = 0;
9329 	int user_data_len = 0, header_len = 0;
9330 	mlan_status status = MLAN_STATUS_SUCCESS;
9331 
9332 	ENTER();
9333 
9334 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
9335 	if (req == NULL) {
9336 		ret = -ENOMEM;
9337 		goto done;
9338 	}
9339 
9340 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
9341 	ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
9342 	req->req_id = MLAN_IOCTL_11H_CFG;
9343 
9344 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_POWER_CONS);
9345 
9346 	if ((int)strlen(respbuf) == header_len) {
9347 		/* GET operation */
9348 		req->action = MLAN_ACT_GET;
9349 		user_data_len = 0;
9350 	} else {
9351 		/* SET operation */
9352 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9353 		if (user_data_len == 1) {
9354 			req->action = MLAN_ACT_SET;
9355 			ds_11hcfg->param.usr_local_power_constraint =
9356 				(t_s8)data;
9357 		} else {
9358 			PRINTM(MERROR, "Too many arguments\n");
9359 			ret = -EINVAL;
9360 			goto done;
9361 		}
9362 	}
9363 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9364 	if (status != MLAN_STATUS_SUCCESS) {
9365 		ret = -EFAULT;
9366 		goto done;
9367 	}
9368 
9369 	if (req->action == MLAN_ACT_GET) {
9370 		data = (int)ds_11hcfg->param.usr_local_power_constraint;
9371 		moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9372 				respbuflen);
9373 		ret = sizeof(data);
9374 	}
9375 
9376 done:
9377 	if (status != MLAN_STATUS_PENDING)
9378 		kfree(req);
9379 	LEAVE();
9380 	return ret;
9381 }
9382 
9383 /**
9384  *  @brief Set/get HT stream configurations
9385  *
9386  *  @param priv         A pointer to moal_private structure
9387  *  @param respbuf      A pointer to response buffer
9388  *  @param respbuflen   Available length of response buffer
9389  *
9390  *  @return             Number of bytes written, negative for failure.
9391  */
woal_priv_ht_stream_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9392 static int woal_priv_ht_stream_cfg(moal_private *priv, t_u8 *respbuf,
9393 				   t_u32 respbuflen)
9394 {
9395 	int data = 0;
9396 	mlan_ds_11n_cfg *cfg = NULL;
9397 	mlan_ioctl_req *req = NULL;
9398 	int ret = 0;
9399 	int user_data_len = 0, header_len = 0;
9400 	mlan_status status = MLAN_STATUS_SUCCESS;
9401 
9402 	ENTER();
9403 
9404 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
9405 	if (req == NULL) {
9406 		ret = -ENOMEM;
9407 		goto done;
9408 	}
9409 
9410 	cfg = (mlan_ds_11n_cfg *)req->pbuf;
9411 	cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
9412 	req->req_id = MLAN_IOCTL_11N_CFG;
9413 
9414 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HT_STREAM_CFG);
9415 
9416 	if ((int)strlen(respbuf) == header_len) {
9417 		/* GET operation */
9418 		req->action = MLAN_ACT_GET;
9419 		user_data_len = 0;
9420 	} else {
9421 		/* SET operation */
9422 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9423 		if (user_data_len == 1) {
9424 			if (data != HT_STREAM_MODE_1X1 &&
9425 			    data != HT_STREAM_MODE_2X2) {
9426 				PRINTM(MERROR, "Invalid arguments!\n");
9427 				ret = -EINVAL;
9428 				goto done;
9429 			}
9430 			req->action = MLAN_ACT_SET;
9431 			cfg->param.stream_cfg = data;
9432 		} else {
9433 			PRINTM(MERROR, "Too many arguments\n");
9434 			ret = -EINVAL;
9435 			goto done;
9436 		}
9437 	}
9438 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9439 	if (status != MLAN_STATUS_SUCCESS) {
9440 		ret = -EFAULT;
9441 		goto done;
9442 	}
9443 
9444 	data = ((mlan_ds_11n_cfg *)req->pbuf)->param.stream_cfg;
9445 	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9446 			respbuflen);
9447 	ret = sizeof(data);
9448 
9449 done:
9450 	if (status != MLAN_STATUS_PENDING)
9451 		kfree(req);
9452 	LEAVE();
9453 	return ret;
9454 }
9455 
9456 /**
9457  *  @brief Set mimo switch configurations
9458  *
9459  *  @param priv         A pointer to moal_private structure
9460  *  @param respbuf      A pointer to response buffer
9461  *  @param respbuflen   Available length of response buffer
9462  *
9463  *  @return             Number of bytes written, negative for failure.
9464  */
woal_priv_mimo_switch(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9465 static int woal_priv_mimo_switch(moal_private *priv, t_u8 *respbuf,
9466 				 t_u32 respbuflen)
9467 {
9468 	int data[2] = {0};
9469 	mlan_ds_radio_cfg *radio = NULL;
9470 	mlan_ioctl_req *req = NULL;
9471 	int ret = 0;
9472 	int user_data_len = 0, header_len = 0;
9473 	mlan_status status = MLAN_STATUS_SUCCESS;
9474 
9475 	ENTER();
9476 
9477 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
9478 	if (req == NULL) {
9479 		ret = -ENOMEM;
9480 		goto done;
9481 	}
9482 
9483 	radio = (mlan_ds_radio_cfg *)req->pbuf;
9484 	radio->sub_command = MLAN_OID_MIMO_SWITCH;
9485 	req->req_id = MLAN_IOCTL_RADIO_CFG;
9486 
9487 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIMO_SWITCH);
9488 
9489 	if ((int)strlen(respbuf) > header_len) {
9490 		/* SET operation */
9491 		req->action = MLAN_ACT_SET;
9492 		parse_arguments(respbuf + header_len, data, 2, &user_data_len);
9493 		if (user_data_len == 2) {
9494 			radio->param.mimo_switch_cfg.txpath_antmode = data[0];
9495 			radio->param.mimo_switch_cfg.rxpath_antmode = data[1];
9496 		} else {
9497 			PRINTM(MERROR, "Invalid arguments!\n");
9498 			ret = -EINVAL;
9499 			goto done;
9500 		}
9501 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9502 		if (status != MLAN_STATUS_SUCCESS) {
9503 			ret = -EFAULT;
9504 			goto done;
9505 		}
9506 	} else {
9507 		PRINTM(MERROR, "Invalid arguments!\n");
9508 		ret = -EINVAL;
9509 		goto done;
9510 	}
9511 
9512 done:
9513 	if (status != MLAN_STATUS_PENDING)
9514 		kfree(req);
9515 	LEAVE();
9516 	return ret;
9517 }
9518 
9519 /**
9520  *  @brief Get thermal reading
9521  *
9522  *  @param priv         A pointer to moal_private structure
9523  *  @param respbuf      A pointer to response buffer
9524  *  @param respbuflen   Available length of response buffer
9525  *
9526  *  @return             Number of bytes written, negative for failure.
9527  */
woal_priv_thermal(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9528 static int woal_priv_thermal(moal_private *priv, t_u8 *respbuf,
9529 			     t_u32 respbuflen)
9530 {
9531 	mlan_ds_misc_cfg *cfg = NULL;
9532 	mlan_ioctl_req *req = NULL;
9533 	int ret = 0, header_len = 0, data = 0;
9534 	mlan_status status = MLAN_STATUS_SUCCESS;
9535 
9536 	ENTER();
9537 
9538 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
9539 	if (req == NULL) {
9540 		ret = -ENOMEM;
9541 		goto done;
9542 	}
9543 
9544 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
9545 	cfg->sub_command = MLAN_OID_MISC_THERMAL;
9546 	req->req_id = MLAN_IOCTL_MISC_CFG;
9547 
9548 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_THERMAL);
9549 
9550 	if ((int)strlen(respbuf) != header_len) {
9551 		PRINTM(MERROR, "Set is not supported for this command\n");
9552 		ret = -EINVAL;
9553 		goto done;
9554 	}
9555 	req->action = MLAN_ACT_GET;
9556 
9557 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9558 	if (status != MLAN_STATUS_SUCCESS) {
9559 		ret = -EFAULT;
9560 		goto done;
9561 	}
9562 
9563 	data = (int)cfg->param.thermal;
9564 	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9565 			respbuflen);
9566 	ret = sizeof(data);
9567 
9568 done:
9569 	if (status != MLAN_STATUS_PENDING)
9570 		kfree(req);
9571 	LEAVE();
9572 	return ret;
9573 }
9574 
9575 /**
9576  *  @brief Set/Get beacon interval
9577  *
9578  *  @param priv         A pointer to moal_private structure
9579  *  @param respbuf      A pointer to response buffer
9580  *  @param respbuflen   Available length of response buffer
9581  *
9582  *  @return             Number of bytes written, negative for failure.
9583  */
woal_priv_beacon_interval(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9584 static int woal_priv_beacon_interval(moal_private *priv, t_u8 *respbuf,
9585 				     t_u32 respbuflen)
9586 {
9587 	int data = 0;
9588 	mlan_ds_bss *bss = NULL;
9589 	mlan_ioctl_req *req = NULL;
9590 	int ret = 0;
9591 	int user_data_len = 0, header_len = 0;
9592 	mlan_status status = MLAN_STATUS_SUCCESS;
9593 
9594 	ENTER();
9595 
9596 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
9597 	if (req == NULL) {
9598 		ret = -ENOMEM;
9599 		goto done;
9600 	}
9601 
9602 	bss = (mlan_ds_bss *)req->pbuf;
9603 	bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
9604 	req->req_id = MLAN_IOCTL_BSS;
9605 
9606 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCN_INTERVAL);
9607 
9608 	if ((int)strlen(respbuf) == header_len) {
9609 		/* GET operation */
9610 		req->action = MLAN_ACT_GET;
9611 		user_data_len = 0;
9612 	} else {
9613 		/* SET operation */
9614 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9615 		if (user_data_len == 1) {
9616 			if ((data < MLAN_MIN_BEACON_INTERVAL) ||
9617 			    (data > MLAN_MAX_BEACON_INTERVAL)) {
9618 				PRINTM(MERROR, "Invalid arguments!\n");
9619 				ret = -EINVAL;
9620 				goto done;
9621 			}
9622 			req->action = MLAN_ACT_SET;
9623 			bss->param.bcn_interval = data;
9624 		} else {
9625 			PRINTM(MERROR, "Too many arguments\n");
9626 			ret = -EINVAL;
9627 			goto done;
9628 		}
9629 	}
9630 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9631 	if (status != MLAN_STATUS_SUCCESS) {
9632 		ret = -EFAULT;
9633 		goto done;
9634 	}
9635 
9636 	data = ((mlan_ds_bss *)req->pbuf)->param.bcn_interval;
9637 	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9638 			respbuflen);
9639 	ret = sizeof(data);
9640 
9641 done:
9642 	if (status != MLAN_STATUS_PENDING)
9643 		kfree(req);
9644 	LEAVE();
9645 	return ret;
9646 }
9647 
9648 #ifdef STA_SUPPORT
9649 /**
9650  *  @brief Get signal
9651  *
9652  *  @param priv         A pointer to moal_private structure
9653  *  @param respbuf      A pointer to response buffer
9654  *  @param respbuflen   Available length of response buffer
9655  *
9656  *  @return             Number of bytes written, negative for failure.
9657  */
woal_priv_get_signal(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9658 static int woal_priv_get_signal(moal_private *priv, t_u8 *respbuf,
9659 				t_u32 respbuflen)
9660 {
9661 /** Input data size */
9662 #define IN_DATA_SIZE 2
9663 /** Output data size */
9664 #define OUT_DATA_SIZE 12
9665 	int ret = 0;
9666 	int in_data[IN_DATA_SIZE];
9667 	int out_data[OUT_DATA_SIZE];
9668 	mlan_ds_get_signal signal;
9669 	int data_length = 0;
9670 	int user_data_len = 0, header_len = 0;
9671 
9672 	ENTER();
9673 
9674 	memset(in_data, 0, sizeof(in_data));
9675 	memset(out_data, 0, sizeof(out_data));
9676 
9677 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL);
9678 
9679 	if ((int)strlen(respbuf) != header_len)
9680 		parse_arguments(respbuf + header_len, in_data, IN_DATA_SIZE,
9681 				&user_data_len);
9682 
9683 	if (priv->media_connected == MFALSE) {
9684 		PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
9685 		ret = -ENOTSUPP;
9686 		goto done;
9687 	}
9688 
9689 	if (user_data_len) {
9690 		if (user_data_len > IN_DATA_SIZE) {
9691 			PRINTM(MERROR, "Too many arguments\n");
9692 			ret = -EINVAL;
9693 			goto done;
9694 		}
9695 	}
9696 
9697 	switch (user_data_len) {
9698 	case 0: /* No checking, get everything */
9699 		break;
9700 	case 2: /* Check subtype range */
9701 		if (in_data[1] < 1 || in_data[1] > 4) {
9702 			ret = -EINVAL;
9703 			goto done;
9704 		}
9705 		/* Fall through */
9706 	case 1: /* Check type range */
9707 		if (in_data[0] < 1 || in_data[0] > 3) {
9708 			ret = -EINVAL;
9709 			goto done;
9710 		}
9711 		break;
9712 	default:
9713 		ret = -EINVAL;
9714 		goto done;
9715 	}
9716 
9717 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
9718 	if (MLAN_STATUS_SUCCESS !=
9719 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
9720 		ret = -EFAULT;
9721 		goto done;
9722 	}
9723 	PRINTM(MINFO, "RSSI Beacon Last   : %d\n", (int)signal.bcn_rssi_last);
9724 	PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int)signal.bcn_rssi_avg);
9725 	PRINTM(MINFO, "RSSI Data Last     : %d\n", (int)signal.data_rssi_last);
9726 	PRINTM(MINFO, "RSSI Data Average  : %d\n", (int)signal.data_rssi_avg);
9727 	PRINTM(MINFO, "SNR Beacon Last    : %d\n", (int)signal.bcn_snr_last);
9728 	PRINTM(MINFO, "SNR Beacon Average : %d\n", (int)signal.bcn_snr_avg);
9729 	PRINTM(MINFO, "SNR Data Last      : %d\n", (int)signal.data_snr_last);
9730 	PRINTM(MINFO, "SNR Data Average   : %d\n", (int)signal.data_snr_avg);
9731 	PRINTM(MINFO, "NF Beacon Last     : %d\n", (int)signal.bcn_nf_last);
9732 	PRINTM(MINFO, "NF Beacon Average  : %d\n", (int)signal.bcn_nf_avg);
9733 	PRINTM(MINFO, "NF Data Last       : %d\n", (int)signal.data_nf_last);
9734 	PRINTM(MINFO, "NF Data Average    : %d\n", (int)signal.data_nf_avg);
9735 
9736 	/* Check type */
9737 	switch (in_data[0]) {
9738 	case 0: /* Send everything */
9739 		out_data[data_length++] = signal.bcn_rssi_last;
9740 		out_data[data_length++] = signal.bcn_rssi_avg;
9741 		out_data[data_length++] = signal.data_rssi_last;
9742 		out_data[data_length++] = signal.data_rssi_avg;
9743 		out_data[data_length++] = signal.bcn_snr_last;
9744 		out_data[data_length++] = signal.bcn_snr_avg;
9745 		out_data[data_length++] = signal.data_snr_last;
9746 		out_data[data_length++] = signal.data_snr_avg;
9747 		out_data[data_length++] = signal.bcn_nf_last;
9748 		out_data[data_length++] = signal.bcn_nf_avg;
9749 		out_data[data_length++] = signal.data_nf_last;
9750 		out_data[data_length++] = signal.data_nf_avg;
9751 		break;
9752 	case 1: /* RSSI */
9753 		/* Check subtype */
9754 		switch (in_data[1]) {
9755 		case 0: /* Everything */
9756 			out_data[data_length++] = signal.bcn_rssi_last;
9757 			out_data[data_length++] = signal.bcn_rssi_avg;
9758 			out_data[data_length++] = signal.data_rssi_last;
9759 			out_data[data_length++] = signal.data_rssi_avg;
9760 			break;
9761 		case 1: /* bcn last */
9762 			out_data[data_length++] = signal.bcn_rssi_last;
9763 			break;
9764 		case 2: /* bcn avg */
9765 			out_data[data_length++] = signal.bcn_rssi_avg;
9766 			break;
9767 		case 3: /* data last */
9768 			out_data[data_length++] = signal.data_rssi_last;
9769 			break;
9770 		case 4: /* data avg */
9771 			out_data[data_length++] = signal.data_rssi_avg;
9772 			break;
9773 		default:
9774 			break;
9775 		}
9776 		break;
9777 	case 2: /* SNR */
9778 		/* Check subtype */
9779 		switch (in_data[1]) {
9780 		case 0: /* Everything */
9781 			out_data[data_length++] = signal.bcn_snr_last;
9782 			out_data[data_length++] = signal.bcn_snr_avg;
9783 			out_data[data_length++] = signal.data_snr_last;
9784 			out_data[data_length++] = signal.data_snr_avg;
9785 			break;
9786 		case 1: /* bcn last */
9787 			out_data[data_length++] = signal.bcn_snr_last;
9788 			break;
9789 		case 2: /* bcn avg */
9790 			out_data[data_length++] = signal.bcn_snr_avg;
9791 			break;
9792 		case 3: /* data last */
9793 			out_data[data_length++] = signal.data_snr_last;
9794 			break;
9795 		case 4: /* data avg */
9796 			out_data[data_length++] = signal.data_snr_avg;
9797 			break;
9798 		default:
9799 			break;
9800 		}
9801 		break;
9802 	case 3: /* NF */
9803 		/* Check subtype */
9804 		switch (in_data[1]) {
9805 		case 0: /* Everything */
9806 			out_data[data_length++] = signal.bcn_nf_last;
9807 			out_data[data_length++] = signal.bcn_nf_avg;
9808 			out_data[data_length++] = signal.data_nf_last;
9809 			out_data[data_length++] = signal.data_nf_avg;
9810 			break;
9811 		case 1: /* bcn last */
9812 			out_data[data_length++] = signal.bcn_nf_last;
9813 			break;
9814 		case 2: /* bcn avg */
9815 			out_data[data_length++] = signal.bcn_nf_avg;
9816 			break;
9817 		case 3: /* data last */
9818 			out_data[data_length++] = signal.data_nf_last;
9819 			break;
9820 		case 4: /* data avg */
9821 			out_data[data_length++] = signal.data_nf_avg;
9822 			break;
9823 		default:
9824 			break;
9825 		}
9826 		break;
9827 	default:
9828 		break;
9829 	}
9830 
9831 	moal_memcpy_ext(priv->phandle, respbuf, out_data,
9832 			(data_length * sizeof(int)), respbuflen);
9833 	ret = data_length * sizeof(int);
9834 
9835 done:
9836 	LEAVE();
9837 	return ret;
9838 }
9839 
woal_signal_ext_enable(moal_private * priv,t_u8 enable)9840 static int woal_signal_ext_enable(moal_private *priv, t_u8 enable)
9841 {
9842 	int ret = 0;
9843 	mlan_ioctl_req *req = NULL;
9844 	mlan_ds_snmp_mib *snmp = NULL;
9845 	mlan_status status = MLAN_STATUS_SUCCESS;
9846 
9847 	/* Allocate an IOCTL request buffer */
9848 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
9849 	if (req == NULL) {
9850 		ret = -ENOMEM;
9851 		goto done;
9852 	}
9853 
9854 	snmp = (mlan_ds_snmp_mib *)req->pbuf;
9855 	snmp->sub_command = MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE;
9856 	req->req_id = MLAN_IOCTL_SNMP_MIB;
9857 	req->action = MLAN_ACT_SET;
9858 	snmp->param.signalext_enable = enable;
9859 
9860 	/* Send IOCTL request to MLAN */
9861 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9862 	if (status != MLAN_STATUS_SUCCESS) {
9863 		ret = -EFAULT;
9864 		goto done;
9865 	}
9866 
9867 done:
9868 	if (status != MLAN_STATUS_PENDING)
9869 		kfree(req);
9870 	LEAVE();
9871 	return ret;
9872 }
9873 
9874 /**
9875  *  @brief Get signal
9876  *
9877  *  @param priv         A pointer to moal_private structure
9878  *  @param respbuf      A pointer to response buffer
9879  *  @param respbuflen   Available length of response buffer
9880  *
9881  *  @return             Number of bytes written, negative for failure.
9882  */
woal_priv_get_signal_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9883 static int woal_priv_get_signal_ext(moal_private *priv, t_u8 *respbuf,
9884 				    t_u32 respbuflen)
9885 {
9886 #define PATH_SIZE 13
9887 	int ret = 0;
9888 	int data = 0, path = 0, data_len = 0;
9889 	int user_data_len = 0, header_len = 0;
9890 	int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
9891 	mlan_ioctl_req *req = NULL;
9892 	mlan_ds_get_info *info = NULL;
9893 	mlan_ds_get_signal signal_get[MAX_PATH_NUM];
9894 	mlan_status status = MLAN_STATUS_SUCCESS;
9895 	int path_num;
9896 	t_u8 enable = 1;
9897 
9898 	ENTER();
9899 
9900 	if (priv->media_connected == MFALSE) {
9901 		PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
9902 		ret = -ENOTSUPP;
9903 		goto done;
9904 	}
9905 
9906 	/* Allocate an IOCTL request buffer */
9907 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
9908 	if (req == NULL) {
9909 		ret = -ENOMEM;
9910 		goto done;
9911 	}
9912 
9913 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT);
9914 
9915 	if ((int)strlen(respbuf) != header_len) {
9916 		parse_arguments(respbuf + header_len, &data,
9917 				sizeof(data) / sizeof(int), &user_data_len);
9918 	}
9919 
9920 	if (user_data_len > 1) {
9921 		PRINTM(MERROR, "Too many arguments\n");
9922 		ret = -EINVAL;
9923 		goto done;
9924 	}
9925 	if (data < PATH_ALL || data > PATH_AB) {
9926 		PRINTM(MERROR, "Wrong arguments\n");
9927 		ret = -EINVAL;
9928 		goto done;
9929 	}
9930 
9931 	/** Enable signalext feature in firmware */
9932 	if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
9933 		ret = -EFAULT;
9934 		goto done;
9935 	}
9936 	woal_sched_timeout(1000);
9937 	enable = 0;
9938 
9939 	/* Fill request buffer */
9940 	info = (mlan_ds_get_info *)req->pbuf;
9941 	info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
9942 	req->req_id = MLAN_IOCTL_GET_INFO;
9943 	req->action = MLAN_ACT_GET;
9944 	info->param.path_id = (t_u16)data;
9945 
9946 	/* Send IOCTL request to MLAN */
9947 	if (MLAN_STATUS_SUCCESS !=
9948 	    woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
9949 		woal_signal_ext_enable(priv, enable);
9950 		ret = -EFAULT;
9951 		goto done;
9952 	}
9953 	if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
9954 		ret = -EFAULT;
9955 		goto done;
9956 	}
9957 	path_num = 1;
9958 	if (data == PATH_ALL) {
9959 		moal_memcpy_ext(priv->phandle, signal_get,
9960 				info->param.signal_ext, sizeof(signal_get),
9961 				sizeof(signal_get));
9962 		path_num = MAX_PATH_NUM;
9963 	} else
9964 		moal_memcpy_ext(priv->phandle, signal_get,
9965 				info->param.signal_ext,
9966 				sizeof(mlan_ds_get_signal), sizeof(signal_get));
9967 
9968 	for (path = 0; path < path_num; path++) {
9969 		if (signal_get[path].selector == PATH_AB)
9970 			PRINTM(MINFO, "PATH A+B:\n");
9971 		else if (signal_get[path].selector == PATH_A)
9972 			PRINTM(MINFO, "PATH A:\n");
9973 		else if (signal_get[path].selector == PATH_B)
9974 			PRINTM(MINFO, "PATH B:\n");
9975 		PRINTM(MINFO, "RSSI Beacon Last   : %d\n",
9976 		       (int)signal_get[path].bcn_rssi_last);
9977 		PRINTM(MINFO, "RSSI Beacon Average: %d\n",
9978 		       (int)signal_get[path].bcn_rssi_avg);
9979 		PRINTM(MINFO, "RSSI Data Last     : %d\n",
9980 		       (int)signal_get[path].data_rssi_last);
9981 		PRINTM(MINFO, "RSSI Data Average  : %d\n",
9982 		       (int)signal_get[path].data_rssi_avg);
9983 		PRINTM(MINFO, "SNR Beacon Last    : %d\n",
9984 		       (int)signal_get[path].bcn_snr_last);
9985 		PRINTM(MINFO, "SNR Beacon Average : %d\n",
9986 		       (int)signal_get[path].bcn_snr_avg);
9987 		PRINTM(MINFO, "SNR Data Last      : %d\n",
9988 		       (int)signal_get[path].data_snr_last);
9989 		PRINTM(MINFO, "SNR Data Average   : %d\n",
9990 		       (int)signal_get[path].data_snr_avg);
9991 		PRINTM(MINFO, "NF Beacon Last     : %d\n",
9992 		       (int)signal_get[path].bcn_nf_last);
9993 		PRINTM(MINFO, "NF Beacon Average  : %d\n",
9994 		       (int)signal_get[path].bcn_nf_avg);
9995 		PRINTM(MINFO, "NF Data Last       : %d\n",
9996 		       (int)signal_get[path].data_nf_last);
9997 		PRINTM(MINFO, "NF Data Average    : %d\n",
9998 		       (int)signal_get[path].data_nf_avg);
9999 		out_data[data_len++] = (int)signal_get[path].selector;
10000 		out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
10001 		out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
10002 		out_data[data_len++] = (int)signal_get[path].data_rssi_last;
10003 		out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
10004 		out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
10005 		out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
10006 		out_data[data_len++] = (int)signal_get[path].data_snr_last;
10007 		out_data[data_len++] = (int)signal_get[path].data_snr_avg;
10008 		out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
10009 		out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
10010 		out_data[data_len++] = (int)signal_get[path].data_nf_last;
10011 		out_data[data_len++] = (int)signal_get[path].data_nf_avg;
10012 	}
10013 	moal_memcpy_ext(
10014 		priv->phandle, respbuf, out_data,
10015 		(MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
10016 		respbuflen);
10017 	ret = data_len * sizeof(int);
10018 done:
10019 	if (status != MLAN_STATUS_PENDING)
10020 		kfree(req);
10021 	LEAVE();
10022 	return ret;
10023 }
10024 
10025 /**
10026  *  @brief Get signalext v2
10027  *
10028  *  @param priv         A pointer to moal_private structure
10029  *  @param respbuf      A pointer to response buffer
10030  *  @param respbuflen   Available length of response buffer
10031  *
10032  *  @return             Number of bytes written, negative for failure.
10033  */
woal_priv_get_signal_ext_v2(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10034 static int woal_priv_get_signal_ext_v2(moal_private *priv, t_u8 *respbuf,
10035 				       t_u32 respbuflen)
10036 {
10037 #define PATH_SIZE 13
10038 	int ret = 0;
10039 	int data = 0, path = 0, data_len = 0;
10040 	int user_data_len = 0, header_len = 0;
10041 	int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
10042 	mlan_ioctl_req *req = NULL;
10043 	mlan_ds_get_info *info = NULL;
10044 	mlan_ds_get_signal signal_get[MAX_PATH_NUM];
10045 	mlan_status status = MLAN_STATUS_SUCCESS;
10046 	int path_num;
10047 
10048 	ENTER();
10049 
10050 	if (priv->media_connected == MFALSE) {
10051 		PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
10052 		ret = -ENOTSUPP;
10053 		goto done;
10054 	}
10055 
10056 	/* Allocate an IOCTL request buffer */
10057 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
10058 	if (req == NULL) {
10059 		ret = -ENOMEM;
10060 		goto done;
10061 	}
10062 
10063 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT_V2);
10064 	if ((int)strlen(respbuf) != header_len) {
10065 		parse_arguments(respbuf + header_len, &data,
10066 				sizeof(data) / sizeof(int), &user_data_len);
10067 	}
10068 
10069 	if (user_data_len > 1) {
10070 		PRINTM(MERROR, "Too many arguments\n");
10071 		ret = -EINVAL;
10072 		goto done;
10073 	}
10074 	if (data < PATH_ALL || data > PATH_AB) {
10075 		PRINTM(MERROR, "Wrong arguments\n");
10076 		ret = -EINVAL;
10077 		goto done;
10078 	}
10079 
10080 	/* Fill request buffer */
10081 	info = (mlan_ds_get_info *)req->pbuf;
10082 	info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
10083 	req->req_id = MLAN_IOCTL_GET_INFO;
10084 	req->action = MLAN_ACT_GET;
10085 	info->param.path_id = (t_u16)data;
10086 
10087 	/* Send IOCTL request to MLAN */
10088 	if (MLAN_STATUS_SUCCESS !=
10089 	    woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
10090 		PRINTM(MERROR,
10091 		       "Enable signalextcfg: mlanutl mlanX signalextcfg 1"
10092 		       " before issuing this command\n");
10093 		ret = -EFAULT;
10094 		goto done;
10095 	}
10096 	path_num = 1;
10097 
10098 	if (data == PATH_ALL) {
10099 		moal_memcpy_ext(priv->phandle, signal_get,
10100 				info->param.signal_ext, sizeof(signal_get),
10101 				sizeof(signal_get));
10102 		path_num = MAX_PATH_NUM;
10103 	} else
10104 		moal_memcpy_ext(priv->phandle, signal_get,
10105 				info->param.signal_ext,
10106 				sizeof(mlan_ds_get_signal), sizeof(signal_get));
10107 
10108 	PRINTM(MMSG, "data=%d path_num=%d\n", data, path_num);
10109 
10110 	for (path = 0; path < path_num; path++) {
10111 		if (signal_get[path].selector == PATH_AB)
10112 			PRINTM(MINFO, "PATH A+B:\n");
10113 		else if (signal_get[path].selector == PATH_A)
10114 			PRINTM(MINFO, "PATH A:\n");
10115 		else if (signal_get[path].selector == PATH_B)
10116 			PRINTM(MINFO, "PATH B:\n");
10117 		PRINTM(MINFO, "RSSI Beacon Last   : %d\n",
10118 		       (int)signal_get[path].bcn_rssi_last);
10119 		PRINTM(MINFO, "RSSI Beacon Average: %d\n",
10120 		       (int)signal_get[path].bcn_rssi_avg);
10121 		PRINTM(MINFO, "RSSI Data Last     : %d\n",
10122 		       (int)signal_get[path].data_rssi_last);
10123 		PRINTM(MINFO, "RSSI Data Average  : %d\n",
10124 		       (int)signal_get[path].data_rssi_avg);
10125 		PRINTM(MINFO, "SNR Beacon Last    : %d\n",
10126 		       (int)signal_get[path].bcn_snr_last);
10127 		PRINTM(MINFO, "SNR Beacon Average : %d\n",
10128 		       (int)signal_get[path].bcn_snr_avg);
10129 		PRINTM(MINFO, "SNR Data Last      : %d\n",
10130 		       (int)signal_get[path].data_snr_last);
10131 		PRINTM(MINFO, "SNR Data Average   : %d\n",
10132 		       (int)signal_get[path].data_snr_avg);
10133 		PRINTM(MINFO, "NF Beacon Last     : %d\n",
10134 		       (int)signal_get[path].bcn_nf_last);
10135 		PRINTM(MINFO, "NF Beacon Average  : %d\n",
10136 		       (int)signal_get[path].bcn_nf_avg);
10137 		PRINTM(MINFO, "NF Data Last       : %d\n",
10138 		       (int)signal_get[path].data_nf_last);
10139 		PRINTM(MINFO, "NF Data Average    : %d\n",
10140 		       (int)signal_get[path].data_nf_avg);
10141 		out_data[data_len++] = (int)signal_get[path].selector;
10142 		out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
10143 		out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
10144 		out_data[data_len++] = (int)signal_get[path].data_rssi_last;
10145 		out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
10146 		out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
10147 		out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
10148 		out_data[data_len++] = (int)signal_get[path].data_snr_last;
10149 		out_data[data_len++] = (int)signal_get[path].data_snr_avg;
10150 		out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
10151 		out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
10152 		out_data[data_len++] = (int)signal_get[path].data_nf_last;
10153 		out_data[data_len++] = (int)signal_get[path].data_nf_avg;
10154 	}
10155 	moal_memcpy_ext(
10156 		priv->phandle, respbuf, out_data,
10157 		(MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
10158 		respbuflen);
10159 	ret = data_len * sizeof(int);
10160 done:
10161 	if (status != MLAN_STATUS_PENDING)
10162 		kfree(req);
10163 	LEAVE();
10164 	return ret;
10165 }
10166 
10167 /**
10168  *  @brief Set signalext cfg
10169  *
10170  *  @param priv         A pointer to moal_private structure
10171  *  @param respbuf      A pointer to response buffer
10172  *  @param respbuflen   Available length of response buffer
10173  *
10174  *  @return             The result of this processing.
10175  */
woal_priv_signalext_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10176 static int woal_priv_signalext_cfg(moal_private *priv, t_u8 *respbuf,
10177 				   t_u32 respbuflen)
10178 {
10179 	int enable = 0;
10180 	int ret = 0;
10181 	int user_data_len = 0, header_len = 0;
10182 	ENTER();
10183 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SIGNALEXT_CFG);
10184 	if ((int)strlen(respbuf) == header_len) {
10185 		PRINTM(MERROR, "Invalid arguments!\n");
10186 		ret = -EINVAL;
10187 		goto done;
10188 	} else {
10189 		/* SET operation */
10190 		parse_arguments(respbuf + header_len, &enable, 1,
10191 				&user_data_len);
10192 		if (user_data_len == 1) {
10193 			if (enable != 0x0 && enable != 0x1) {
10194 				PRINTM(MERROR, "Invalid arguments!\n");
10195 				ret = -EINVAL;
10196 				goto done;
10197 			}
10198 			ret = woal_signal_ext_enable(priv, enable);
10199 		} else {
10200 			PRINTM(MERROR, "Too many arguments\n");
10201 			ret = -EINVAL;
10202 			goto done;
10203 		}
10204 	}
10205 done:
10206 	LEAVE();
10207 	return ret;
10208 }
10209 #endif /* #ifdef STA_SUPPORT */
10210 
10211 #if defined(STA_SUPPORT)
10212 /**
10213  * @brief               Make PMF bit required/optional
10214  * @param priv          Pointer to moal_private structure
10215  * @param respbuf       Pointer to response buffer
10216  * @param resplen       Response buffer length
10217  *
10218  * @return              0 -- success, otherwise fail
10219  */
woal_priv_set_get_pmfcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10220 static int woal_priv_set_get_pmfcfg(moal_private *priv, t_u8 *respbuf,
10221 				    t_u32 respbuflen)
10222 {
10223 	int data[2] = {0, 0};
10224 	mlan_ioctl_req *req = NULL;
10225 	mlan_ds_misc_cfg *cfg = NULL;
10226 	mlan_ds_misc_pmfcfg *pmfcfg;
10227 	int ret = 0;
10228 	int user_data_len = 0, header_len = 0;
10229 	mlan_status status = MLAN_STATUS_SUCCESS;
10230 
10231 	ENTER();
10232 
10233 	if (!priv->phandle->card_info->embedded_supp) {
10234 		PRINTM(MERROR, "Not supported cmd on this card\n");
10235 		ret = -EOPNOTSUPP;
10236 		goto done;
10237 	}
10238 
10239 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PMFCFG);
10240 	if ((int)strlen(respbuf) == header_len) {
10241 		/* GET operation */
10242 		user_data_len = 0;
10243 	} else {
10244 		/* SET operation */
10245 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10246 				&user_data_len);
10247 	}
10248 
10249 	if (user_data_len > 2) {
10250 		PRINTM(MERROR, "Invalid number of arguments\n");
10251 		ret = -EINVAL;
10252 		goto done;
10253 	}
10254 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
10255 	if (req == NULL) {
10256 		ret = -ENOMEM;
10257 		goto done;
10258 	}
10259 
10260 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
10261 	pmfcfg = (mlan_ds_misc_pmfcfg *)&cfg->param.pmfcfg;
10262 	cfg->sub_command = MLAN_OID_MISC_PMFCFG;
10263 	req->req_id = MLAN_IOCTL_MISC_CFG;
10264 
10265 	if (user_data_len == 0)
10266 		req->action = MLAN_ACT_GET;
10267 	else {
10268 		pmfcfg->mfpc = (t_u8)data[0];
10269 		pmfcfg->mfpr = (t_u8)data[1];
10270 		req->action = MLAN_ACT_SET;
10271 	}
10272 
10273 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10274 	if (status != MLAN_STATUS_SUCCESS) {
10275 		ret = -EFAULT;
10276 		goto done;
10277 	}
10278 
10279 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.pmfcfg,
10280 			sizeof(mlan_ds_misc_pmfcfg), respbuflen);
10281 	ret = sizeof(mlan_ds_misc_pmfcfg);
10282 
10283 done:
10284 	if (status != MLAN_STATUS_PENDING)
10285 		kfree(req);
10286 	LEAVE();
10287 	return ret;
10288 }
10289 #endif
10290 
10291 /**
10292  * @brief               Get/Set inactivity timeout extend
10293  * @param priv          Pointer to moal_private structure
10294  * @param respbuf       Pointer to response buffer
10295  * @param resplen       Response buffer length
10296  *
10297  *  @return             Number of bytes written, negative for failure.
10298  */
woal_priv_inactivity_timeout_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10299 static int woal_priv_inactivity_timeout_ext(moal_private *priv, t_u8 *respbuf,
10300 					    t_u32 respbuflen)
10301 {
10302 	int data[4];
10303 	mlan_ioctl_req *req = NULL;
10304 	mlan_ds_pm_cfg *pmcfg = NULL;
10305 	pmlan_ds_inactivity_to inac_to = NULL;
10306 	int ret = 0;
10307 	int user_data_len = 0, header_len = 0;
10308 	mlan_status status = MLAN_STATUS_SUCCESS;
10309 
10310 	ENTER();
10311 
10312 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_INACTIVITYTO);
10313 	memset(data, 0, sizeof(data));
10314 	if ((int)strlen(respbuf) == header_len) {
10315 		/* GET operation */
10316 		user_data_len = 0;
10317 	} else {
10318 		/* SET operation */
10319 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10320 				&user_data_len);
10321 	}
10322 
10323 	if (user_data_len != 0 && user_data_len != 3 && user_data_len != 4) {
10324 		PRINTM(MERROR, "Invalid number of parameters\n");
10325 		ret = -EINVAL;
10326 		goto done;
10327 	}
10328 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
10329 	if (req == NULL) {
10330 		ret = -ENOMEM;
10331 		goto done;
10332 	}
10333 
10334 	pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
10335 	inac_to = &pmcfg->param.inactivity_to;
10336 	pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
10337 	req->req_id = MLAN_IOCTL_PM_CFG;
10338 	req->action = MLAN_ACT_GET;
10339 
10340 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10341 	if (status != MLAN_STATUS_SUCCESS) {
10342 		ret = -EFAULT;
10343 		goto done;
10344 	}
10345 
10346 	if (user_data_len) {
10347 		inac_to->timeout_unit = data[0];
10348 		inac_to->unicast_timeout = data[1];
10349 		inac_to->mcast_timeout = data[2];
10350 		if (user_data_len == 4)
10351 			inac_to->ps_entry_timeout = data[3];
10352 		req->action = MLAN_ACT_SET;
10353 
10354 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10355 		if (status != MLAN_STATUS_SUCCESS) {
10356 			ret = -EFAULT;
10357 			goto done;
10358 		}
10359 	} else {
10360 		data[0] = inac_to->timeout_unit;
10361 		data[1] = inac_to->unicast_timeout;
10362 		data[2] = inac_to->mcast_timeout;
10363 		data[3] = inac_to->ps_entry_timeout;
10364 
10365 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
10366 				sizeof(data), respbuflen);
10367 		ret = sizeof(data);
10368 	}
10369 
10370 done:
10371 	if (status != MLAN_STATUS_PENDING)
10372 		kfree(req);
10373 	LEAVE();
10374 	return ret;
10375 }
10376 
10377 /**
10378  * @brief               Enable/Disable amsdu_aggr_ctrl
10379  *
10380  * @param priv          Pointer to moal_private structure
10381  * @param respbuf       Pointer to response buffer
10382  * @param resplen       Response buffer length
10383  *
10384  * @return             Number of bytes written, negative for failure.
10385  */
woal_priv_11n_amsdu_aggr_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10386 static int woal_priv_11n_amsdu_aggr_ctrl(moal_private *priv, t_u8 *respbuf,
10387 					 t_u32 respbuflen)
10388 {
10389 	mlan_ioctl_req *req = NULL;
10390 	mlan_ds_11n_cfg *cfg_11n = NULL;
10391 	int ret = 0, data[2] = {0};
10392 	int user_data_len = 0, header_len = 0;
10393 	mlan_status status = MLAN_STATUS_SUCCESS;
10394 
10395 	ENTER();
10396 
10397 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AMSDU_AGGR_CTRL);
10398 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
10399 	if (req == NULL) {
10400 		ret = -ENOMEM;
10401 		goto done;
10402 	}
10403 
10404 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
10405 	cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
10406 	req->req_id = MLAN_IOCTL_11N_CFG;
10407 
10408 	if ((int)strlen(respbuf) == header_len) {
10409 		/* GET operation */
10410 		user_data_len = 0;
10411 		req->action = MLAN_ACT_GET;
10412 	} else {
10413 		/* SET operation */
10414 		parse_arguments(respbuf + header_len, data, 1, &user_data_len);
10415 
10416 		if (user_data_len != 1) {
10417 			PRINTM(MERROR, "Invalid number of parameters\n");
10418 			ret = -EINVAL;
10419 			goto done;
10420 		}
10421 		req->action = MLAN_ACT_SET;
10422 		cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
10423 	}
10424 
10425 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10426 	if (status != MLAN_STATUS_SUCCESS) {
10427 		ret = -EFAULT;
10428 		goto done;
10429 	}
10430 
10431 	data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
10432 	data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
10433 
10434 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
10435 			respbuflen);
10436 	ret = sizeof(data);
10437 
10438 done:
10439 	if (status != MLAN_STATUS_PENDING)
10440 		kfree(req);
10441 	LEAVE();
10442 	return ret;
10443 }
10444 
10445 /**
10446  * @brief               Set/Get Transmit beamforming capabilities
10447  *
10448  * @param priv          Pointer to moal_private structure
10449  * @param respbuf       Pointer to response buffer
10450  * @param resplen       Response buffer length
10451  *
10452  * @return             Number of bytes written, negative for failure.
10453  */
woal_priv_tx_bf_cap_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10454 static int woal_priv_tx_bf_cap_ioctl(moal_private *priv, t_u8 *respbuf,
10455 				     t_u32 respbuflen)
10456 {
10457 	mlan_ioctl_req *req = NULL;
10458 	mlan_ds_11n_cfg *bf_cfg = NULL;
10459 	int ret = 0, bf_cap = 0;
10460 	int user_data_len = 0, header_len = 0;
10461 	mlan_status status = MLAN_STATUS_SUCCESS;
10462 
10463 	ENTER();
10464 
10465 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CAP);
10466 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
10467 	if (req == NULL) {
10468 		ret = -ENOMEM;
10469 		goto done;
10470 	}
10471 
10472 	bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
10473 	bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
10474 	req->req_id = MLAN_IOCTL_11N_CFG;
10475 
10476 	if ((int)strlen(respbuf) == header_len) {
10477 		/* GET operation */
10478 		user_data_len = 0;
10479 		req->action = MLAN_ACT_GET;
10480 	} else {
10481 		/* SET operation */
10482 		parse_arguments(respbuf + header_len, &bf_cap, 1,
10483 				&user_data_len);
10484 
10485 		if (user_data_len != 1) {
10486 			PRINTM(MERROR, "Invalid number of parameters\n");
10487 			ret = -EINVAL;
10488 			goto done;
10489 		}
10490 		req->action = MLAN_ACT_SET;
10491 		bf_cfg->param.tx_bf_cap = bf_cap;
10492 	}
10493 
10494 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10495 	if (status != MLAN_STATUS_SUCCESS) {
10496 		ret = -EFAULT;
10497 		goto done;
10498 	}
10499 
10500 	bf_cap = bf_cfg->param.tx_bf_cap;
10501 
10502 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&bf_cap, sizeof(bf_cap),
10503 			respbuflen);
10504 	ret = sizeof(bf_cap);
10505 
10506 done:
10507 	if (status != MLAN_STATUS_PENDING)
10508 		kfree(req);
10509 	LEAVE();
10510 	return ret;
10511 }
10512 
10513 #ifdef SDIO
10514 /**
10515  * @brief               Turn on/off the sdio clock
10516  *
10517  * @param priv          Pointer to moal_private structure
10518  * @param respbuf       Pointer to response buffer
10519  * @param resplen       Response buffer length
10520  *
10521  * @return              Number of bytes written, negative for failure.
10522  */
woal_priv_sdio_clock_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10523 static int woal_priv_sdio_clock_ioctl(moal_private *priv, t_u8 *respbuf,
10524 				      t_u32 respbuflen)
10525 {
10526 	int ret = 0;
10527 	int data = 2;
10528 	int user_data_len = 0, header_len = 0;
10529 	/* Initialize the clock state as on */
10530 	static int clock_state = 1;
10531 
10532 	ENTER();
10533 
10534 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDIO_CLOCK);
10535 	if ((int)strlen(respbuf) == header_len) {
10536 		/* GET operation */
10537 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&clock_state,
10538 				sizeof(clock_state), respbuflen);
10539 		ret = sizeof(clock_state);
10540 		goto done;
10541 	} else {
10542 		/* SET operation */
10543 		parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
10544 
10545 		if (user_data_len != 1) {
10546 			PRINTM(MERROR, "Invalid number of parameters\n");
10547 			ret = -EINVAL;
10548 			goto done;
10549 		}
10550 	}
10551 	switch (data) {
10552 	case CMD_DISABLED:
10553 		PRINTM(MINFO, "SDIO clock is turned off\n");
10554 		ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
10555 		clock_state = data;
10556 		break;
10557 	case CMD_ENABLED:
10558 		PRINTM(MINFO, "SDIO clock is turned on\n");
10559 		ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
10560 		clock_state = data;
10561 		break;
10562 	default:
10563 		ret = -EINVAL;
10564 		PRINTM(MINFO, "sdioclock: wrong parameter\n");
10565 		break;
10566 	}
10567 done:
10568 	LEAVE();
10569 	return ret;
10570 }
10571 #endif
10572 
10573 #ifdef SDIO
10574 /**
10575  * @brief               Set SDIO Multi-point aggregation control parameters
10576  *
10577  * @param priv          Pointer to moal_private structure
10578  * @param respbuf       Pointer to response buffer
10579  * @param resplen       Response buffer length
10580  *
10581  * @return             Number of bytes written, negative for failure.
10582  */
woal_priv_sdio_mpa_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10583 static int woal_priv_sdio_mpa_ctrl(moal_private *priv, t_u8 *respbuf,
10584 				   t_u32 respbuflen)
10585 {
10586 	mlan_ioctl_req *req = NULL;
10587 	mlan_ds_misc_cfg *misc = NULL;
10588 	int ret = 0, data[6];
10589 	int user_data_len = 0, header_len = 0;
10590 	mlan_status status = MLAN_STATUS_SUCCESS;
10591 
10592 	ENTER();
10593 
10594 	memset(data, 0, sizeof(data));
10595 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MPA_CTRL);
10596 	if ((int)strlen(respbuf) == header_len) {
10597 		/* GET operation */
10598 		user_data_len = 0;
10599 	} else {
10600 		/* SET operation */
10601 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10602 				&user_data_len);
10603 
10604 		if (user_data_len > 6) {
10605 			PRINTM(MERROR, "Invalid number of parameters\n");
10606 			ret = -EINVAL;
10607 			goto done;
10608 		}
10609 	}
10610 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
10611 	if (req == NULL) {
10612 		ret = -ENOMEM;
10613 		goto done;
10614 	}
10615 
10616 	misc = (mlan_ds_misc_cfg *)req->pbuf;
10617 	misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
10618 	req->req_id = MLAN_IOCTL_MISC_CFG;
10619 	req->action = MLAN_ACT_GET;
10620 	/* Get the values first, then modify these values if
10621 	 * user had modified them */
10622 
10623 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10624 	if (status != MLAN_STATUS_SUCCESS) {
10625 		PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
10626 		ret = -EFAULT;
10627 		goto done;
10628 	}
10629 
10630 	if (user_data_len == 0) {
10631 		data[0] = misc->param.mpa_ctrl.tx_enable;
10632 		data[1] = misc->param.mpa_ctrl.rx_enable;
10633 		data[2] = misc->param.mpa_ctrl.tx_buf_size;
10634 		data[3] = misc->param.mpa_ctrl.rx_buf_size;
10635 		data[4] = misc->param.mpa_ctrl.tx_max_ports;
10636 		data[5] = misc->param.mpa_ctrl.rx_max_ports;
10637 
10638 		PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0],
10639 		       data[1], data[2], data[3], data[4], data[5]);
10640 
10641 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
10642 				sizeof(data), respbuflen);
10643 		ret = sizeof(data);
10644 		goto done;
10645 	}
10646 
10647 	switch (user_data_len) {
10648 	case 6:
10649 		misc->param.mpa_ctrl.rx_max_ports = data[5];
10650 		/* fall through */
10651 	case 5:
10652 		misc->param.mpa_ctrl.tx_max_ports = data[4];
10653 		/* fall through */
10654 	case 4:
10655 		misc->param.mpa_ctrl.rx_buf_size = data[3];
10656 		/* fall through */
10657 	case 3:
10658 		misc->param.mpa_ctrl.tx_buf_size = data[2];
10659 		/* fall through */
10660 	case 2:
10661 		misc->param.mpa_ctrl.rx_enable = data[1];
10662 		/* fall through */
10663 	case 1:
10664 		/* Set cmd */
10665 		req->action = MLAN_ACT_SET;
10666 
10667 		PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0],
10668 		       data[1], data[2], data[3], data[4], data[5]);
10669 
10670 		misc->param.mpa_ctrl.tx_enable = data[0];
10671 		break;
10672 	default:
10673 		PRINTM(MERROR, "Default case error\n");
10674 		ret = -EINVAL;
10675 		goto done;
10676 	}
10677 
10678 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10679 	if (status != MLAN_STATUS_SUCCESS) {
10680 		ret = -EFAULT;
10681 		goto done;
10682 	}
10683 
10684 done:
10685 	if (status != MLAN_STATUS_PENDING)
10686 		kfree(req);
10687 	LEAVE();
10688 	return ret;
10689 }
10690 #endif
10691 
10692 /**
10693  * @brief               Configure sleep parameters
10694  *
10695  * @param priv          Pointer to moal_private structure
10696  * @param respbuf       Pointer to response buffer
10697  * @param resplen       Response buffer length
10698  *
10699  * @return             Number of bytes written, negative for failure.
10700  */
woal_priv_sleep_params_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10701 static int woal_priv_sleep_params_ioctl(moal_private *priv, t_u8 *respbuf,
10702 					t_u32 respbuflen)
10703 {
10704 	int ret = 0;
10705 	mlan_ioctl_req *req = NULL;
10706 	mlan_ds_pm_cfg *pm = NULL;
10707 	mlan_ds_sleep_params *psleep_params = NULL;
10708 	int data[6] = {0}, i;
10709 	int user_data_len = 0, header_len = 0;
10710 #ifdef DEBUG_LEVEL1
10711 	char err_str[][36] = {{"sleep clock error in ppm"},
10712 			      {"wakeup offset in usec"},
10713 			      {"clock stabilization time in usec"},
10714 			      {"control periodic calibration(0-2)"},
10715 			      {"control of external sleepClock(0-2)"},
10716 			      {"value of reserved for debug"}};
10717 #endif
10718 	mlan_status status = MLAN_STATUS_SUCCESS;
10719 
10720 	ENTER();
10721 
10722 	memset(data, 0, sizeof(data));
10723 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
10724 	if (req == NULL) {
10725 		ret = -ENOMEM;
10726 		goto done;
10727 	}
10728 	pm = (mlan_ds_pm_cfg *)req->pbuf;
10729 	pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
10730 	req->req_id = MLAN_IOCTL_PM_CFG;
10731 	psleep_params = (pmlan_ds_sleep_params)&pm->param.sleep_params;
10732 
10733 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEP_PARAMS);
10734 	if ((int)strlen(respbuf) == header_len) {
10735 		/* GET operation */
10736 		user_data_len = 0;
10737 		req->action = MLAN_ACT_GET;
10738 	} else {
10739 		/* SET operation */
10740 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10741 				&user_data_len);
10742 		if (user_data_len != 6) {
10743 			PRINTM(MERROR, "Invalid number of parameters\n");
10744 			ret = -EINVAL;
10745 			goto done;
10746 		}
10747 #define MIN_VAL 0x0000
10748 #define MAX_VAL 0xFFFF
10749 		for (i = 0; i < 6; i++) {
10750 			if ((i == 3) || (i == 4)) {
10751 				/* These two cases are handled below the loop */
10752 				continue;
10753 			}
10754 			if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
10755 				PRINTM(MERROR, "Invalid %s (0-65535)!\n",
10756 				       err_str[i]);
10757 				ret = -EINVAL;
10758 				goto done;
10759 			}
10760 		}
10761 		if (data[3] < 0 || data[3] > 2) {
10762 			PRINTM(MERROR,
10763 			       "Invalid control periodic calibration (0-2)!\n");
10764 			ret = -EINVAL;
10765 			goto done;
10766 		}
10767 		if (data[4] < 0 || data[4] > 2) {
10768 			PRINTM(MERROR,
10769 			       "Invalid control of external sleep clock (0-2)!\n");
10770 			ret = -EINVAL;
10771 			goto done;
10772 		}
10773 		req->action = MLAN_ACT_SET;
10774 		psleep_params->error = data[0];
10775 		psleep_params->offset = data[1];
10776 		psleep_params->stable_time = data[2];
10777 		psleep_params->cal_control = data[3];
10778 		psleep_params->ext_sleep_clk = data[4];
10779 		psleep_params->reserved = data[5];
10780 	}
10781 
10782 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10783 	if (status != MLAN_STATUS_SUCCESS) {
10784 		ret = -EFAULT;
10785 		goto done;
10786 	}
10787 
10788 	data[0] = psleep_params->error;
10789 	data[1] = psleep_params->offset;
10790 	data[2] = psleep_params->stable_time;
10791 	data[3] = psleep_params->cal_control;
10792 	data[4] = psleep_params->ext_sleep_clk;
10793 	data[5] = psleep_params->reserved;
10794 
10795 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
10796 			respbuflen);
10797 	ret = sizeof(data);
10798 
10799 done:
10800 	if (status != MLAN_STATUS_PENDING)
10801 		kfree(req);
10802 
10803 	LEAVE();
10804 	return ret;
10805 }
10806 
10807 #ifdef UAP_SUPPORT
10808 /**
10809  * @brief               Set/Get network monitor configurations
10810  *
10811  * @param priv          Pointer to moal_private structure
10812  * @param respbuf       Pointer to response buffer
10813  * @param resplen       Response buffer length
10814  *
10815  * @return             Number of bytes written, negative for failure.
10816  */
woal_priv_net_monitor_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10817 static int woal_priv_net_monitor_ioctl(moal_private *priv, t_u8 *respbuf,
10818 				       t_u32 respbuflen)
10819 {
10820 	int user_data_len = 0, header_len = 0;
10821 	int data_length = 0;
10822 	int data[5] = {0};
10823 	int ret = 0;
10824 	mlan_ioctl_req *req = NULL;
10825 	mlan_ds_misc_cfg *misc = NULL;
10826 	mlan_ds_misc_net_monitor *net_mon = NULL;
10827 	mlan_status status = MLAN_STATUS_SUCCESS;
10828 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10829 	moal_handle *handle = priv->phandle;
10830 	monitor_iface *mon_if = NULL;
10831 	struct net_device *ndev = NULL;
10832 #endif
10833 
10834 	ENTER();
10835 
10836 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_NET_MON);
10837 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
10838 	if (req == NULL) {
10839 		LEAVE();
10840 		return -ENOMEM;
10841 	}
10842 	misc = (mlan_ds_misc_cfg *)req->pbuf;
10843 	net_mon = (mlan_ds_misc_net_monitor *)&misc->param.net_mon;
10844 	misc->sub_command = MLAN_OID_MISC_NET_MONITOR;
10845 	req->req_id = MLAN_IOCTL_MISC_CFG;
10846 	if ((int)strlen(respbuf) == header_len) {
10847 		/* GET operation */
10848 		user_data_len = 0;
10849 		req->action = MLAN_ACT_GET;
10850 	} else {
10851 		/* SET operation */
10852 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10853 				&user_data_len);
10854 		if (user_data_len == 1 || user_data_len == 4 ||
10855 		    user_data_len == 5) {
10856 			if (data[0] != MFALSE &&
10857 			    data[0] != CHANNEL_SPEC_SNIFFER_MODE) {
10858 				PRINTM(MERROR,
10859 				       "NET_MON: Activity should be enable(=1/2)/disable(=0)\n");
10860 				ret = -EINVAL;
10861 				goto done;
10862 			}
10863 			if ((data[0] == MFALSE && user_data_len != 1) ||
10864 			    (data[0] == CHANNEL_SPEC_SNIFFER_MODE &&
10865 			     (user_data_len != 4 && user_data_len != 5))) {
10866 				PRINTM(MERROR,
10867 				       "NET_MON: Sniffer activity not match with user_data_len\n");
10868 				ret = -EINVAL;
10869 				goto done;
10870 			}
10871 			net_mon->enable_net_mon = data[0];
10872 			if (data[0] == CHANNEL_SPEC_SNIFFER_MODE) {
10873 				int i;
10874 				if (user_data_len != 4 && user_data_len != 5) {
10875 					PRINTM(MERROR,
10876 					       "NET_MON: Invalid number of args!\n");
10877 					ret = -EINVAL;
10878 					goto done;
10879 				}
10880 				/* Supported filter flags */
10881 				if (!data[1] ||
10882 				    data[1] & ~(MLAN_NETMON_DATA_FRAME |
10883 						MLAN_NETMON_MANAGEMENT_FRAME |
10884 						MLAN_NETMON_CONTROL_FRAME)) {
10885 					PRINTM(MERROR,
10886 					       "NET_MON: Invalid filter flag\n");
10887 					ret = -EINVAL;
10888 					goto done;
10889 				}
10890 
10891 				if (user_data_len > 2) {
10892 					/* Supported bands */
10893 
10894 					for (i = 0;
10895 					     i <
10896 					     (int)(sizeof(SupportedInfraBand) /
10897 						   sizeof(SupportedInfraBand[0]));
10898 					     i++)
10899 						if (data[2] ==
10900 						    SupportedInfraBand[i])
10901 							break;
10902 					if (i == sizeof(SupportedInfraBand)) {
10903 						PRINTM(MERROR,
10904 						       "NET_MON: Invalid band\n");
10905 						ret = -EINVAL;
10906 						goto done;
10907 					}
10908 				}
10909 				/* Supported channel */
10910 				if (user_data_len > 3 &&
10911 				    (data[3] < 1 ||
10912 				     data[3] > MLAN_MAX_CHANNEL)) {
10913 					PRINTM(MERROR,
10914 					       "NET_MON: Invalid channel number\n");
10915 					ret = -EINVAL;
10916 					goto done;
10917 				}
10918 				if (user_data_len == 5) {
10919 					/* Secondary channel offset */
10920 					if (!(data[2] & (BAND_GN | BAND_AN))) {
10921 						PRINTM(MERROR,
10922 						       "No 11n in band, can not set "
10923 						       "secondary channel offset\n");
10924 						ret = -EINVAL;
10925 						goto done;
10926 					}
10927 					if ((data[4] != CHANNEL_BW_20MHZ) &&
10928 					    (data[4] !=
10929 					     CHANNEL_BW_40MHZ_ABOVE) &&
10930 					    (data[4] !=
10931 					     CHANNEL_BW_40MHZ_BELOW) &&
10932 					    (data[4] != CHANNEL_BW_80MHZ)) {
10933 						PRINTM(MERROR,
10934 						       "Invalid secondary channel bandwidth, "
10935 						       "only allowed 0, 1, 3 or 4\n");
10936 						ret = -EINVAL;
10937 						goto done;
10938 					}
10939 					net_mon->chan_bandwidth = data[4];
10940 				}
10941 
10942 				net_mon->filter_flag = data[1];
10943 				net_mon->band = data[2];
10944 				net_mon->channel = data[3];
10945 			}
10946 			req->action = MLAN_ACT_SET;
10947 		} else {
10948 			PRINTM(MERROR, "NET_MON: Invalid number of args!\n");
10949 			ret = -EINVAL;
10950 			goto done;
10951 		}
10952 	}
10953 
10954 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10955 	if (status != MLAN_STATUS_SUCCESS) {
10956 		PRINTM(MERROR, "NET_MON: woal_request_ioctl fail\n");
10957 		ret = -EFAULT;
10958 		goto done;
10959 	}
10960 
10961 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10962 	if (req->action == MLAN_ACT_SET) {
10963 		if (data[0]) { /** Enable sniffer mode: 1/2 */
10964 			if (!handle->mon_if) {
10965 				mon_if = woal_prepare_mon_if(priv, "rtap", 0,
10966 							     data[0]);
10967 				if (!mon_if) {
10968 					PRINTM(MFATAL,
10969 					       "Prepare mon_if fail.\n");
10970 					ret = -EFAULT;
10971 					goto done;
10972 				}
10973 				ndev = mon_if->mon_ndev;
10974 				ret = register_netdevice(ndev);
10975 				if (ret) {
10976 					PRINTM(MFATAL,
10977 					       "register net_device failed, ret=%d\n",
10978 					       ret);
10979 					free_netdev(ndev);
10980 					ret = -EFAULT;
10981 					goto done;
10982 				}
10983 				handle->mon_if = mon_if;
10984 			}
10985 			/* Save band channel config */
10986 			handle->mon_if->band_chan_cfg.band = net_mon->band;
10987 			handle->mon_if->band_chan_cfg.channel =
10988 				net_mon->channel;
10989 			handle->mon_if->band_chan_cfg.chan_bandwidth =
10990 				net_mon->chan_bandwidth;
10991 		} else { /** Disable sniffer mode: 0 */
10992 			if (handle->mon_if) {
10993 				ndev = handle->mon_if->mon_ndev;
10994 				handle->mon_if = NULL;
10995 				unregister_netdevice(ndev);
10996 			}
10997 		}
10998 	}
10999 #endif
11000 
11001 	data[0] = net_mon->enable_net_mon;
11002 	data[1] = net_mon->filter_flag;
11003 	data[2] = net_mon->band;
11004 	data[3] = net_mon->channel;
11005 	data[4] = net_mon->chan_bandwidth;
11006 	data_length = 5;
11007 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
11008 			sizeof(int) * data_length, respbuflen);
11009 	ret = sizeof(int) * data_length;
11010 
11011 done:
11012 	if (status != MLAN_STATUS_PENDING)
11013 		kfree(req);
11014 
11015 	LEAVE();
11016 	return ret;
11017 }
11018 #endif
11019 
11020 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
11021 /**
11022  * @brief Set/Get monitor mode
11023  *
11024  * @param priv         A pointer to moal_private structure
11025  * @param respbuf      A pointer to response buffer
11026  * @param respbuflen   Available length of response buffer
11027  *
11028  * @return         0 --success, otherwise fail
11029  */
woal_priv_set_get_monitor_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11030 static int woal_priv_set_get_monitor_mode(moal_private *priv, t_u8 *respbuf,
11031 					  t_u32 respbuflen)
11032 {
11033 	int ret = 0;
11034 	int data = 0;
11035 	int user_data_len = 0, header_len = 0;
11036 	t_u32 action = MLAN_ACT_GET;
11037 
11038 	ENTER();
11039 
11040 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MONITOR_MODE);
11041 
11042 	if ((int)strlen(respbuf) == header_len) {
11043 		/* GET operation */
11044 		user_data_len = 0;
11045 		action = MLAN_ACT_GET;
11046 	} else {
11047 		/* SET operation */
11048 		parse_arguments(respbuf + header_len, &data,
11049 				sizeof(data) / sizeof(int), &user_data_len);
11050 		action = MLAN_ACT_SET;
11051 	}
11052 
11053 	if (sizeof(int) * user_data_len > sizeof(data)) {
11054 		PRINTM(MERROR, "Too many arguments\n");
11055 		ret = -EINVAL;
11056 		goto done;
11057 	}
11058 
11059 	if (action == MLAN_ACT_SET) {
11060 		if (data == 1) {
11061 			priv->phandle->wiphy->interface_modes |=
11062 				MBIT(NL80211_IFTYPE_MONITOR);
11063 		} else if (data == 0) {
11064 			priv->phandle->wiphy->interface_modes &=
11065 				~(MBIT(NL80211_IFTYPE_MONITOR));
11066 		} else {
11067 			PRINTM(MERROR, "Invalid input arguments\n");
11068 			ret = -EINVAL;
11069 			goto done;
11070 		}
11071 	}
11072 	data = !!(priv->phandle->wiphy->interface_modes &
11073 		  MBIT(NL80211_IFTYPE_MONITOR));
11074 
11075 	ret = sprintf(respbuf, "Monitor mode: %d\n", data) + 1;
11076 
11077 done:
11078 	LEAVE();
11079 	return ret;
11080 }
11081 #endif
11082 
11083 /**
11084  *  @brief This function get nop list.
11085  *
11086  *  @param priv         A pointer to moal_private structure
11087  *  @param respbuf      A pointer to response buffer
11088  *  @param respbuflen   Available length of response buffer
11089  *
11090  *  @return             Number of bytes written, negative for failure.
11091  */
woal_priv_nop_list(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11092 static int woal_priv_nop_list(moal_private *priv, t_u8 *respbuf,
11093 			      t_u32 respbuflen)
11094 {
11095 	mlan_ioctl_req *req = NULL;
11096 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
11097 
11098 	int ret = 0;
11099 	mlan_status status = MLAN_STATUS_SUCCESS;
11100 
11101 	ENTER();
11102 
11103 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11104 	if (req == NULL) {
11105 		ret = -ENOMEM;
11106 		goto done;
11107 	}
11108 
11109 	req->req_id = MLAN_IOCTL_11H_CFG;
11110 	req->action = MLAN_ACT_GET;
11111 
11112 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11113 	ds_11hcfg->sub_command = MLAN_OID_11H_NOP_CHAN_LIST;
11114 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11115 	if (status == MLAN_STATUS_FAILURE) {
11116 		ret = -EFAULT;
11117 		goto done;
11118 	}
11119 	moal_memcpy_ext(priv->phandle, respbuf,
11120 			(t_u8 *)&ds_11hcfg->param.nop_chan_list,
11121 			sizeof(mlan_ds_11h_nop_chan_list), respbuflen);
11122 	ret = sizeof(mlan_ds_11h_nop_chan_list);
11123 done:
11124 	if (status != MLAN_STATUS_PENDING)
11125 		kfree(req);
11126 	LEAVE();
11127 	return ret;
11128 }
11129 
11130 /**
11131  *  @brief clear NOP list
11132  *
11133  *  @param priv             A pointer to moal_private structure
11134  *  @return                 0 --success, otherwise fail
11135  */
woal_uap_clear_nop(moal_private * priv)11136 static int woal_uap_clear_nop(moal_private *priv)
11137 {
11138 	mlan_ioctl_req *req = NULL;
11139 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
11140 
11141 	int ret = 0;
11142 	mlan_status status = MLAN_STATUS_SUCCESS;
11143 
11144 	ENTER();
11145 
11146 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11147 	if (req == NULL) {
11148 		ret = -ENOMEM;
11149 		goto done;
11150 	}
11151 
11152 	req->req_id = MLAN_IOCTL_11H_CFG;
11153 	req->action = MLAN_ACT_CLEAR;
11154 
11155 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11156 	ds_11hcfg->sub_command = MLAN_OID_11H_CHAN_NOP_INFO;
11157 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11158 	if (status == MLAN_STATUS_FAILURE) {
11159 		ret = -EFAULT;
11160 		goto done;
11161 	}
11162 done:
11163 	if (status != MLAN_STATUS_PENDING)
11164 		kfree(req);
11165 	LEAVE();
11166 	return ret;
11167 }
11168 
11169 /**
11170  *  @brief This function clear nop flags.
11171  *
11172  *  @param priv         A pointer to moal_private structure
11173  *  @param respbuf      A pointer to response buffer
11174  *  @param respbuflen   Available length of response buffer
11175  *
11176  *  @return             Number of bytes written, negative for failure.
11177  */
woal_priv_clear_nop(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11178 static int woal_priv_clear_nop(moal_private *priv, t_u8 *respbuf,
11179 			       t_u32 respbuflen)
11180 {
11181 	int ret = 0;
11182 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11183 	struct wiphy *wiphy = priv->phandle->wiphy;
11184 #endif
11185 
11186 	ENTER();
11187 	PRINTM(MCMND, "clear nop\n");
11188 	ret = woal_uap_clear_nop(priv);
11189 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11190 	if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext)) {
11191 		if (wiphy)
11192 			woal_clear_wiphy_dfs_state(wiphy);
11193 	}
11194 #endif
11195 	ret = sizeof(int);
11196 	LEAVE();
11197 	return ret;
11198 }
11199 
11200 /**
11201  *  @brief This function detects fake RADAR.
11202  *
11203  *  @param priv         A pointer to moal_private structure
11204  *  @param respbuf      A pointer to response buffer
11205  *  @param respbuflen   Available length of response buffer
11206  *
11207  *  @return             positive for success, negative for failure.
11208  */
woal_priv_fake_radar(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11209 static int woal_priv_fake_radar(moal_private *priv, t_u8 *respbuf,
11210 				t_u32 respbuflen)
11211 {
11212 	mlan_ioctl_req *ioctl_req = NULL;
11213 	mlan_ds_snmp_mib *snmp = NULL;
11214 	int ret = 0;
11215 	mlan_status status = MLAN_STATUS_SUCCESS;
11216 	ENTER();
11217 #ifdef UAP_CFG80211
11218 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
11219 	if (priv && priv->chan.chan &&
11220 	    !(priv->chan.chan->flags & IEEE80211_CHAN_RADAR)) {
11221 		PRINTM(MERROR, "Current op channel NOT DFS\n");
11222 		LEAVE();
11223 		return -EINVAL;
11224 	}
11225 #endif
11226 #endif
11227 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
11228 	if (ioctl_req == NULL) {
11229 		LEAVE();
11230 		return -ENOMEM;
11231 	}
11232 	snmp = (mlan_ds_snmp_mib *)ioctl_req->pbuf;
11233 	ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
11234 	snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H_FAKERADAR;
11235 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
11236 	if (status != MLAN_STATUS_SUCCESS) {
11237 		ret = -EFAULT;
11238 		goto done;
11239 	}
11240 done:
11241 	if (status != MLAN_STATUS_PENDING)
11242 		kfree(ioctl_req);
11243 	LEAVE();
11244 	return ret;
11245 }
11246 
11247 /**
11248  * @brief               Set/Get DFS Testing settings
11249  *
11250  * @param priv          Pointer to moal_private structure
11251  * @param respbuf       Pointer to response buffer
11252  * @param resplen       Response buffer length
11253  *
11254  * @return             Number of bytes written, negative for failure.
11255  */
woal_priv_dfs_testing(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11256 static int woal_priv_dfs_testing(moal_private *priv, t_u8 *respbuf,
11257 				 t_u32 respbuflen)
11258 {
11259 	mlan_ioctl_req *req = NULL;
11260 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
11261 	int ret = 0;
11262 	int data[5] = {0};
11263 	int user_data_len = 0, header_len = 0;
11264 	mlan_status status = MLAN_STATUS_SUCCESS;
11265 
11266 	ENTER();
11267 
11268 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_TESTING);
11269 	/* Allocate an IOCTL request buffer */
11270 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11271 	if (req == NULL) {
11272 		ret = -ENOMEM;
11273 		goto done;
11274 	}
11275 
11276 	/* Fill request buffer */
11277 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11278 	ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
11279 	req->req_id = MLAN_IOCTL_11H_CFG;
11280 
11281 	if ((int)strlen(respbuf) == header_len) {
11282 		/* GET operation */
11283 		user_data_len = 0;
11284 		req->action = MLAN_ACT_GET;
11285 	} else {
11286 		/* SET operation */
11287 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
11288 				&user_data_len);
11289 		if (user_data_len != 5) {
11290 			PRINTM(MERROR, "Invalid number of args!\n");
11291 			ret = -EINVAL;
11292 			goto done;
11293 		}
11294 		if ((unsigned)data[0] > 1800) {
11295 			PRINTM(MERROR,
11296 			       "The maximum user CAC is 1800 seconds (30 mins).\n");
11297 			ret = -EINVAL;
11298 			goto done;
11299 		}
11300 		if ((unsigned)data[1] > 0xFFFF) {
11301 			PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
11302 			ret = -EINVAL;
11303 			goto done;
11304 		}
11305 		if ((unsigned)data[3] > 0xFF) {
11306 			PRINTM(MERROR,
11307 			       "The maximum user fixed channel is 255.\n");
11308 			ret = -EINVAL;
11309 			goto done;
11310 		}
11311 		if ((unsigned)data[4] != 0 && ((unsigned)data[4] != 1)) {
11312 			PRINTM(MERROR, "CAC restart should be 0/1\n");
11313 			ret = -EINVAL;
11314 			goto done;
11315 		}
11316 
11317 		ds_11hcfg->param.dfs_testing.usr_cac_period_msec =
11318 			(t_u32)data[0] * 1000;
11319 		ds_11hcfg->param.dfs_testing.usr_nop_period_sec =
11320 			(t_u16)data[1];
11321 		ds_11hcfg->param.dfs_testing.usr_no_chan_change =
11322 			data[2] ? 1 : 0;
11323 		ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8)data[3];
11324 		ds_11hcfg->param.dfs_testing.usr_cac_restart = (t_u8)data[4];
11325 		priv->phandle->cac_restart = (t_u8)data[4];
11326 		priv->phandle->cac_period_jiffies = (t_u32)data[0] * HZ;
11327 		priv->phandle->usr_nop_period_sec = (t_u16)data[1];
11328 		req->action = MLAN_ACT_SET;
11329 #ifdef UAP_SUPPORT
11330 		priv->user_cac_period_msec =
11331 			ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
11332 #endif
11333 	}
11334 
11335 	/* Send IOCTL request to MLAN */
11336 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11337 	if (status != MLAN_STATUS_SUCCESS) {
11338 		ret = -EFAULT;
11339 		goto done;
11340 	}
11341 
11342 	if (!user_data_len) {
11343 		data[0] =
11344 			ds_11hcfg->param.dfs_testing.usr_cac_period_msec / 1000;
11345 		data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
11346 		data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
11347 		data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
11348 		data[4] = ds_11hcfg->param.dfs_testing.usr_cac_restart;
11349 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
11350 				sizeof(data), respbuflen);
11351 		ret = sizeof(data);
11352 	}
11353 
11354 done:
11355 	if (status != MLAN_STATUS_PENDING)
11356 		kfree(req);
11357 
11358 	LEAVE();
11359 	return ret;
11360 }
11361 
11362 /**
11363  * @brief               Set/Get DFS W53 settings
11364  *
11365  * @param priv          Pointer to moal_private structure
11366  * @param respbuf       Pointer to response buffer
11367  * @param resplen       Response buffer length
11368  *
11369  * @return             Number of bytes written, negative for failure.
11370  */
woal_priv_dfs53cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11371 static int woal_priv_dfs53cfg(moal_private *priv, t_u8 *respbuf,
11372 			      t_u32 respbuflen)
11373 {
11374 	mlan_ioctl_req *req = NULL;
11375 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
11376 	int ret = 0;
11377 	int data = 0;
11378 	int user_data_len = 0, header_len = 0;
11379 	mlan_status status = MLAN_STATUS_SUCCESS;
11380 
11381 	ENTER();
11382 
11383 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS53_CFG);
11384 	/* Allocate an IOCTL request buffer */
11385 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11386 	if (req == NULL) {
11387 		ret = -ENOMEM;
11388 		goto done;
11389 	}
11390 
11391 	/* Fill request buffer */
11392 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11393 	ds_11hcfg->sub_command = MLAN_OID_11H_DFS_W53_CFG;
11394 	req->req_id = MLAN_IOCTL_11H_CFG;
11395 
11396 	if ((int)strlen(respbuf) == header_len) {
11397 		/* GET operation */
11398 		user_data_len = 0;
11399 		req->action = MLAN_ACT_GET;
11400 	} else {
11401 		/* SET operation */
11402 		parse_arguments(respbuf + header_len, &data,
11403 				sizeof(data) / sizeof(int), &user_data_len);
11404 		if (user_data_len != 1) {
11405 			PRINTM(MERROR, "Invalid number of args !\n");
11406 			ret = -EINVAL;
11407 			goto done;
11408 		}
11409 		if (data > DFS_W53_OLD) {
11410 			PRINTM(MERROR, "Invalid config !\n");
11411 			ret = -EINVAL;
11412 			goto done;
11413 		}
11414 
11415 		ds_11hcfg->param.dfs_w53_cfg.dfs53cfg = (t_u8)data;
11416 		req->action = MLAN_ACT_SET;
11417 	}
11418 
11419 	/* Send IOCTL request to MLAN */
11420 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11421 	if (status != MLAN_STATUS_SUCCESS) {
11422 		ret = -EFAULT;
11423 		goto done;
11424 	}
11425 
11426 	if (!user_data_len) {
11427 		moal_memcpy_ext(priv->phandle, respbuf,
11428 				(t_u8 *)&ds_11hcfg->param.dfs_w53_cfg.dfs53cfg,
11429 				sizeof(ds_11hcfg->param.dfs_w53_cfg.dfs53cfg),
11430 				respbuflen);
11431 		ret = sizeof(t_u8);
11432 	}
11433 
11434 	PRINTM(MIOCTL, "dfs w53 cfg %d\n",
11435 	       ds_11hcfg->param.dfs_w53_cfg.dfs53cfg);
11436 
11437 done:
11438 	if (status != MLAN_STATUS_PENDING)
11439 		kfree(req);
11440 
11441 	LEAVE();
11442 	return ret;
11443 }
11444 
11445 /**
11446  * @brief               Set/Get DFS mode settings
11447  *
11448  * @param priv          Pointer to moal_private structure
11449  * @param respbuf       Pointer to response buffer
11450  * @param resplen       Response buffer length
11451  *
11452  * @return             Number of bytes written, negative for failure.
11453  */
woal_priv_dfs_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11454 static int woal_priv_dfs_mode(moal_private *priv, t_u8 *respbuf,
11455 			      t_u32 respbuflen)
11456 {
11457 	mlan_ioctl_req *req = NULL;
11458 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
11459 	int ret = 0;
11460 	int data = 0;
11461 	int user_data_len = 0, header_len = 0;
11462 	mlan_status status = MLAN_STATUS_SUCCESS;
11463 
11464 	ENTER();
11465 
11466 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_MODE);
11467 	/* Allocate an IOCTL request buffer */
11468 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11469 	if (req == NULL) {
11470 		ret = -ENOMEM;
11471 		goto done;
11472 	}
11473 
11474 	/* Fill request buffer */
11475 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11476 	ds_11hcfg->sub_command = MLAN_OID_11H_DFS_MODE;
11477 	req->req_id = MLAN_IOCTL_11H_CFG;
11478 
11479 	if ((int)strlen(respbuf) == header_len) {
11480 		/* GET operation */
11481 		user_data_len = 0;
11482 		req->action = MLAN_ACT_GET;
11483 	} else {
11484 		/* SET operation */
11485 		parse_arguments(respbuf + header_len, &data,
11486 				sizeof(data) / sizeof(int), &user_data_len);
11487 		if (user_data_len != 1) {
11488 			PRINTM(MERROR, "Invalid number of args !\n");
11489 			ret = -EINVAL;
11490 			goto done;
11491 		}
11492 		if (data > DFS_MODE_ENH) {
11493 			PRINTM(MERROR, "Invalid config for dfs_mode!\n");
11494 			ret = -EINVAL;
11495 			goto done;
11496 		}
11497 
11498 		ds_11hcfg->param.dfs_mode = (t_u8)data;
11499 		req->action = MLAN_ACT_SET;
11500 	}
11501 
11502 	/* Send IOCTL request to MLAN */
11503 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11504 	if (status != MLAN_STATUS_SUCCESS) {
11505 		ret = -EFAULT;
11506 		goto done;
11507 	}
11508 
11509 	if (!user_data_len) {
11510 		moal_memcpy_ext(priv->phandle, respbuf,
11511 				(t_u8 *)&ds_11hcfg->param.dfs_mode,
11512 				sizeof(ds_11hcfg->param.dfs_mode), respbuflen);
11513 		ret = sizeof(t_u8);
11514 	}
11515 
11516 	PRINTM(MIOCTL, "dfs_mode %d\n", ds_11hcfg->param.dfs_mode);
11517 
11518 done:
11519 	if (status != MLAN_STATUS_PENDING)
11520 		kfree(req);
11521 
11522 	LEAVE();
11523 	return ret;
11524 }
11525 
11526 #ifdef UAP_SUPPORT
11527 /**
11528  *  @brief determine the center frquency center index for bandwidth
11529  *         of 80 MHz and 160 MHz
11530  *
11531  ** @param priv          Pointer to moal_private structure
11532  *  @param band         band
11533  *  @param pri_chan     primary channel
11534  *  @param chan_bw      channel bandwidth
11535  *
11536  *  @return             channel center frequency center, if found; O, otherwise
11537  */
11538 
woal_get_center_freq_idx(moal_private * priv,t_u16 band,t_u32 pri_chan,t_u8 chan_bw)11539 static t_u8 woal_get_center_freq_idx(moal_private *priv, t_u16 band,
11540 				     t_u32 pri_chan, t_u8 chan_bw)
11541 {
11542 	t_u8 center_freq_idx = 0;
11543 
11544 	if (band & BAND_AAC) {
11545 		switch (pri_chan) {
11546 		case 36:
11547 		case 40:
11548 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11549 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11550 				center_freq_idx = 38;
11551 				break;
11552 			}
11553 			/* fall through */
11554 		case 44:
11555 		case 48:
11556 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11557 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11558 				center_freq_idx = 46;
11559 				break;
11560 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11561 				center_freq_idx = 42;
11562 				break;
11563 			}
11564 			/* fall through */
11565 		case 52:
11566 		case 56:
11567 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11568 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11569 				center_freq_idx = 54;
11570 				break;
11571 			}
11572 			/* fall through */
11573 		case 60:
11574 		case 64:
11575 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11576 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11577 				center_freq_idx = 62;
11578 				break;
11579 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11580 				center_freq_idx = 58;
11581 				break;
11582 			} else if (chan_bw == CHANNEL_BW_160MHZ) {
11583 				center_freq_idx = 50;
11584 				break;
11585 			}
11586 			/* fall through */
11587 		case 68:
11588 		case 72:
11589 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11590 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11591 				center_freq_idx = 70;
11592 				break;
11593 			}
11594 			/* fall through */
11595 		case 76:
11596 		case 80:
11597 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11598 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11599 				center_freq_idx = 78;
11600 				break;
11601 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11602 				center_freq_idx = 74;
11603 				break;
11604 			}
11605 			/* fall through */
11606 		case 84:
11607 		case 88:
11608 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11609 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11610 				center_freq_idx = 86;
11611 				break;
11612 			}
11613 			/* fall through */
11614 		case 92:
11615 		case 96:
11616 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11617 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11618 				center_freq_idx = 94;
11619 				break;
11620 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11621 				center_freq_idx = 90;
11622 				break;
11623 			}
11624 			/* fall through */
11625 		case 100:
11626 		case 104:
11627 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11628 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11629 				center_freq_idx = 102;
11630 				break;
11631 			}
11632 			/* fall through */
11633 		case 108:
11634 		case 112:
11635 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11636 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11637 				center_freq_idx = 110;
11638 				break;
11639 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11640 				center_freq_idx = 106;
11641 				break;
11642 			}
11643 			/* fall through */
11644 		case 116:
11645 		case 120:
11646 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11647 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11648 				center_freq_idx = 118;
11649 				break;
11650 			}
11651 			/* fall through */
11652 		case 124:
11653 		case 128:
11654 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11655 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11656 				center_freq_idx = 126;
11657 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11658 				center_freq_idx = 122;
11659 			} else if (chan_bw == CHANNEL_BW_160MHZ) {
11660 				center_freq_idx = 114;
11661 			}
11662 			break;
11663 		case 132:
11664 		case 136:
11665 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11666 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11667 				center_freq_idx = 134;
11668 				break;
11669 			}
11670 			/* fall through */
11671 		case 140:
11672 		case 144:
11673 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11674 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11675 				center_freq_idx = 126;
11676 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11677 				center_freq_idx = 138;
11678 			}
11679 			break;
11680 		case 149:
11681 		case 153:
11682 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11683 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11684 				center_freq_idx = 151;
11685 				break;
11686 			}
11687 			/* fall through */
11688 		case 157:
11689 		case 161:
11690 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11691 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11692 				center_freq_idx = 159;
11693 				break;
11694 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11695 				center_freq_idx = 155;
11696 				break;
11697 			}
11698 			/* fall through */
11699 		case 165:
11700 		case 169:
11701 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11702 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11703 				center_freq_idx = 167;
11704 				break;
11705 			}
11706 			/* fall through */
11707 		case 173:
11708 		case 177:
11709 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11710 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11711 				center_freq_idx = 175;
11712 				break;
11713 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11714 				center_freq_idx = 171;
11715 				break;
11716 			}
11717 			/* fall through */
11718 		case 184:
11719 		case 188:
11720 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11721 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11722 				center_freq_idx = 186;
11723 				break;
11724 			}
11725 			/* fall through */
11726 		case 192:
11727 		case 196:
11728 			if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11729 			    chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11730 				center_freq_idx = 194;
11731 				break;
11732 			} else if (chan_bw == CHANNEL_BW_80MHZ) {
11733 				center_freq_idx = 190;
11734 				break;
11735 			}
11736 			/* fall through */
11737 		default: /* error. go to the default */
11738 			center_freq_idx = 42;
11739 		}
11740 	}
11741 	return center_freq_idx;
11742 }
11743 #endif
11744 
11745 #if defined(UAP_SUPPORT)
11746 /**
11747  *  @brief This function handles channel switch with CSA/ECSA IE.
11748  *
11749  ** @param priv          Pointer to moal_private structure
11750  *  @param block_tx      0-no need block traffic 1- need block traffic
11751  *  @param oper_class    oper_class
11752  *  @param channel       channel
11753  *  @param switch count  how many csa/ecsa beacon will send out
11754  *  @param band_width    1-40Mhz above, 3-40Mhz below, 4-80Mhz, 5-160Mhz
11755  *  @param ecsa          MTRUE/MFALSE;
11756  *
11757  *  @return             channel center frequency center, if found; O, otherwise
11758  */
woal_channel_switch(moal_private * priv,t_u8 block_tx,t_u8 oper_class,t_u8 channel,t_u8 switch_count,t_u8 band_width,t_u8 ecsa)11759 static int woal_channel_switch(moal_private *priv, t_u8 block_tx,
11760 			       t_u8 oper_class, t_u8 channel, t_u8 switch_count,
11761 			       t_u8 band_width, t_u8 ecsa)
11762 {
11763 	IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
11764 	IEEEtypes_ChanSwitchAnn_t *chan_switch = NULL;
11765 	custom_ie *pcust_chansw_ie = NULL;
11766 	t_u8 center_freq_idx = 0;
11767 	IEEEtypes_Header_t *pChanSwWrap_ie = NULL;
11768 	IEEEtypes_WideBWChanSwitch_t *pbwchansw_ie = NULL;
11769 	IEEEtypes_VhtTpcEnvelope_t *pvhttpcEnv_ie = NULL;
11770 	mlan_ioctl_req *ioctl_req = NULL;
11771 	mlan_ds_misc_cfg *misc = NULL;
11772 	mlan_status status = MLAN_STATUS_SUCCESS;
11773 	t_u8 bw;
11774 	t_u8 new_oper_class = oper_class;
11775 	int ret = 0;
11776 
11777 	ENTER();
11778 
11779 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
11780 	if (ioctl_req == NULL) {
11781 		ret = -ENOMEM;
11782 		goto done;
11783 	}
11784 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
11785 	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
11786 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
11787 	ioctl_req->action = MLAN_ACT_SET;
11788 	misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
11789 	misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
11790 
11791 	pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
11792 	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
11793 	pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
11794 	pcust_chansw_ie->mgmt_subtype_mask =
11795 		MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
11796 							    BEACON/probe resp*/
11797 	chan_switch = (IEEEtypes_ChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
11798 	chan_switch->element_id = CHANNEL_SWITCH_ANN;
11799 	chan_switch->len = 3;
11800 	chan_switch->chan_switch_mode = block_tx;
11801 	chan_switch->new_channel_num = channel;
11802 	chan_switch->chan_switch_count = switch_count;
11803 	DBG_HEXDUMP(MCMD_D, "CSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer,
11804 		    pcust_chansw_ie->ie_length);
11805 	switch (band_width) {
11806 	case CHANNEL_BW_40MHZ_ABOVE:
11807 	case CHANNEL_BW_40MHZ_BELOW:
11808 		bw = 40;
11809 		break;
11810 	case CHANNEL_BW_80MHZ:
11811 		bw = 80;
11812 		break;
11813 	case CHANNEL_BW_160MHZ:
11814 		bw = 160;
11815 		break;
11816 	default:
11817 		bw = 20;
11818 		break;
11819 	}
11820 	if (!new_oper_class && ecsa)
11821 		woal_priv_get_nonglobal_operclass_by_bw_channel(
11822 			priv, bw, channel, &new_oper_class);
11823 	if (new_oper_class) {
11824 		pcust_chansw_ie->ie_length +=
11825 			sizeof(IEEEtypes_ExtChanSwitchAnn_t);
11826 		ext_chan_switch =
11827 			(IEEEtypes_ExtChanSwitchAnn_t
11828 				 *)(pcust_chansw_ie->ie_buffer +
11829 				    sizeof(IEEEtypes_ChanSwitchAnn_t));
11830 		ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
11831 		ext_chan_switch->len = 4;
11832 		ext_chan_switch->chan_switch_mode = block_tx;
11833 		ext_chan_switch->new_oper_class = new_oper_class;
11834 		ext_chan_switch->new_channel_num = channel;
11835 		ext_chan_switch->chan_switch_count = switch_count;
11836 		DBG_HEXDUMP(MCMD_D, "ECSA IE",
11837 			    (t_u8 *)(pcust_chansw_ie->ie_buffer +
11838 				     sizeof(IEEEtypes_ChanSwitchAnn_t)),
11839 			    pcust_chansw_ie->ie_length -
11840 				    sizeof(IEEEtypes_ChanSwitchAnn_t));
11841 	}
11842 	/* bandwidth 40/80/160 should set channel switch wrapper ie for 11ac 5G
11843 	 * channel*/
11844 	if (band_width && channel > 14) {
11845 		pChanSwWrap_ie =
11846 			(IEEEtypes_Header_t *)(pcust_chansw_ie->ie_buffer +
11847 					       pcust_chansw_ie->ie_length);
11848 		pChanSwWrap_ie->element_id = EXT_POWER_CONSTR;
11849 		pChanSwWrap_ie->len = sizeof(IEEEtypes_WideBWChanSwitch_t);
11850 
11851 		pbwchansw_ie = (IEEEtypes_WideBWChanSwitch_t
11852 					*)((t_u8 *)pChanSwWrap_ie +
11853 					   sizeof(IEEEtypes_Header_t));
11854 		pbwchansw_ie->ieee_hdr.element_id = BW_CHANNEL_SWITCH;
11855 		pbwchansw_ie->ieee_hdr.len =
11856 			sizeof(IEEEtypes_WideBWChanSwitch_t) -
11857 			sizeof(IEEEtypes_Header_t);
11858 
11859 		center_freq_idx = woal_get_center_freq_idx(priv, BAND_AAC,
11860 							   channel, band_width);
11861 		if (band_width == CHANNEL_BW_40MHZ_ABOVE ||
11862 		    band_width == CHANNEL_BW_40MHZ_BELOW) {
11863 			pbwchansw_ie->new_channel_width = 0;
11864 			pbwchansw_ie->new_channel_center_freq0 =
11865 				center_freq_idx;
11866 		} else if (band_width == CHANNEL_BW_80MHZ) {
11867 			pbwchansw_ie->new_channel_width = 1;
11868 			pbwchansw_ie->new_channel_center_freq0 =
11869 				center_freq_idx - 4;
11870 			pbwchansw_ie->new_channel_center_freq1 =
11871 				center_freq_idx + 4;
11872 		} else if (band_width == CHANNEL_BW_160MHZ) {
11873 			pbwchansw_ie->new_channel_width = 2;
11874 			pbwchansw_ie->new_channel_center_freq0 =
11875 				center_freq_idx - 8;
11876 			pbwchansw_ie->new_channel_center_freq1 =
11877 				center_freq_idx + 8;
11878 		} else
11879 			PRINTM(MERROR,
11880 			       "Invalid bandwidth.Support value 1/3/4/5 for 40+/40-/80/160MHZ\n");
11881 
11882 		/*prepare the VHT Transmit Power Envelope IE*/
11883 		pvhttpcEnv_ie =
11884 			(IEEEtypes_VhtTpcEnvelope_t
11885 				 *)((t_u8 *)pChanSwWrap_ie +
11886 				    sizeof(IEEEtypes_Header_t) +
11887 				    sizeof(IEEEtypes_WideBWChanSwitch_t));
11888 		pvhttpcEnv_ie->ieee_hdr.element_id = VHT_TX_POWER_ENV;
11889 		pvhttpcEnv_ie->ieee_hdr.len =
11890 			sizeof(IEEEtypes_VhtTpcEnvelope_t) -
11891 			sizeof(IEEEtypes_Header_t);
11892 		/* Local Max TX Power Count= 3,
11893 		 * Local TX Power Unit Inter=EIP(0) */
11894 		pvhttpcEnv_ie->tpc_info = 3;
11895 		pvhttpcEnv_ie->local_max_tp_20mhz = 0xff;
11896 		pvhttpcEnv_ie->local_max_tp_40mhz = 0xff;
11897 		pvhttpcEnv_ie->local_max_tp_80mhz = 0xff;
11898 		pvhttpcEnv_ie->local_max_tp_160mhz_80_80mhz = 0xff;
11899 		pChanSwWrap_ie->len += sizeof(IEEEtypes_VhtTpcEnvelope_t);
11900 		pcust_chansw_ie->ie_length +=
11901 			pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t);
11902 		DBG_HEXDUMP(MCMD_D, "Channel switch wrapper IE",
11903 			    (t_u8 *)pChanSwWrap_ie,
11904 			    pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t));
11905 	}
11906 	if (block_tx) {
11907 		if (netif_carrier_ok(priv->netdev))
11908 			netif_carrier_off(priv->netdev);
11909 		woal_stop_queue(priv->netdev);
11910 		priv->uap_tx_blocked = MTRUE;
11911 	}
11912 
11913 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
11914 	if (status != MLAN_STATUS_SUCCESS) {
11915 		PRINTM(MERROR, "Failed to set ECSA IE\n");
11916 		ret = -EFAULT;
11917 		goto done;
11918 	}
11919 
11920 	priv->phandle->chsw_wait_q_woken = MFALSE;
11921 	/* wait for channel switch to complete  */
11922 	wait_event_interruptible_timeout(
11923 		priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
11924 		(u32)HZ * (switch_count + 2) * 110 / 1000);
11925 
11926 	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
11927 	pcust_chansw_ie->mgmt_subtype_mask = 0;
11928 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
11929 	if (status != MLAN_STATUS_SUCCESS) {
11930 		PRINTM(MERROR, "Failed to clear ECSA IE\n");
11931 	}
11932 done:
11933 	if (status != MLAN_STATUS_PENDING)
11934 		kfree(ioctl_req);
11935 
11936 	LEAVE();
11937 	return ret;
11938 }
11939 #endif
11940 
11941 #ifdef UAP_SUPPORT
11942 /**
11943  * @brief Given bandwidth and channel, create Band_Config
11944  *
11945  * @param priv         A pointer to moal_private
11946  * @param bandcfg         A pointer to Band_Config_t structure
11947  * @param channel         A pointer to cfg80211_chan_def structure
11948  * @param bandwidth       0/1/3/4
11949  *
11950  * @return                N/A
11951  */
woal_convert_chanbw_to_bandconfig(moal_private * priv,Band_Config_t * bandcfg,t_u8 channel,t_u8 bandwidth)11952 static void woal_convert_chanbw_to_bandconfig(moal_private *priv,
11953 					      Band_Config_t *bandcfg,
11954 					      t_u8 channel, t_u8 bandwidth)
11955 {
11956 	ENTER();
11957 
11958 	if (channel <= MAX_BG_CHANNEL)
11959 		bandcfg->chanBand = BAND_2GHZ;
11960 	else
11961 		bandcfg->chanBand = BAND_5GHZ;
11962 	switch (bandwidth) {
11963 	case CHANNEL_BW_40MHZ_ABOVE:
11964 		bandcfg->chanWidth = CHAN_BW_40MHZ;
11965 		bandcfg->chan2Offset = SEC_CHAN_ABOVE;
11966 		break;
11967 	case CHANNEL_BW_40MHZ_BELOW:
11968 		bandcfg->chanWidth = CHAN_BW_40MHZ;
11969 		bandcfg->chan2Offset = SEC_CHAN_BELOW;
11970 		break;
11971 	case CHANNEL_BW_80MHZ:
11972 		bandcfg->chanWidth = CHAN_BW_80MHZ;
11973 		bandcfg->chan2Offset =
11974 			woal_get_second_channel_offset(priv, channel);
11975 		break;
11976 	case CHANNEL_BW_20MHZ:
11977 	default:
11978 		bandcfg->chanWidth = CHAN_BW_20MHZ;
11979 		break;
11980 	}
11981 	LEAVE();
11982 	return;
11983 }
11984 
11985 /**
11986  * @brief Get DFS channel list
11987  *
11988  * @param priv         A pointer to moal_private
11989  *
11990  * @return                N/A
11991  */
woal_get_dfs_chan_list(moal_private * priv)11992 static void woal_get_dfs_chan_list(moal_private *priv)
11993 {
11994 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11995 	struct wiphy *wiphy = priv->phandle->wiphy;
11996 	struct ieee80211_supported_band *sband;
11997 #endif
11998 	int i;
11999 	mlan_ioctl_req *req = NULL;
12000 	mlan_ds_misc_cfg *cfp_misc = NULL;
12001 	mlan_status status = MLAN_STATUS_SUCCESS;
12002 
12003 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
12004 	if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext) &&
12005 	    wiphy) {
12006 		sband = wiphy->bands[NL80211_BAND_5GHZ];
12007 		if (sband) {
12008 			for (i = 0; i < sband->n_channels; i++) {
12009 				if (sband->channels[i].flags &
12010 				    IEEE80211_CHAN_RADAR) {
12011 					priv->auto_dfs_cfg.dfs_chan_list
12012 						[priv->auto_dfs_cfg.num_of_chan] =
12013 						sband->channels[i].hw_value;
12014 					priv->auto_dfs_cfg.num_of_chan++;
12015 				}
12016 			}
12017 			return;
12018 		}
12019 	}
12020 #endif
12021 	/* Allocate an IOCTL request buffer */
12022 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12023 	if (req == NULL)
12024 		goto done;
12025 
12026 	/* Fill request buffer */
12027 	cfp_misc = (mlan_ds_misc_cfg *)req->pbuf;
12028 	cfp_misc->sub_command = MLAN_OID_MISC_CFP_TABLE;
12029 	req->req_id = MLAN_IOCTL_MISC_CFG;
12030 	req->action = MLAN_ACT_GET;
12031 	cfp_misc->param.cfp.band = BAND_A;
12032 
12033 	/* Send IOCTL request to MLAN */
12034 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
12035 	if (status != MLAN_STATUS_SUCCESS)
12036 		goto done;
12037 
12038 	for (i = 0; i < cfp_misc->param.cfp.num_chan; i++) {
12039 		if (cfp_misc->param.cfp.cfp_tbl[i].dynamic.flags &
12040 		    NXP_CHANNEL_DISABLED)
12041 			continue;
12042 		if (cfp_misc->param.cfp.cfp_tbl[i].passive_scan_or_radar_detect) {
12043 			priv->auto_dfs_cfg
12044 				.dfs_chan_list[priv->auto_dfs_cfg.num_of_chan] =
12045 				cfp_misc->param.cfp.cfp_tbl[i].channel;
12046 			priv->auto_dfs_cfg.num_of_chan++;
12047 		}
12048 	}
12049 done:
12050 	if (status != MLAN_STATUS_PENDING)
12051 		kfree(req);
12052 
12053 	LEAVE();
12054 	return;
12055 }
12056 
12057 /**
12058  * @brief               Process dfs cac command
12059  *
12060  * @param priv          a pointer to moal_private structure
12061  * @param ch_rpt_req    a pointer to mlan_ds_11h_chan_rep_req structure
12062  *
12063  * @return              MLAN_STATUS_FAILRUE or MLAN_STATUS_SUCCESS
12064  */
woal_do_dfs_cac(moal_private * priv,mlan_ds_11h_chan_rep_req * ch_rpt_req)12065 mlan_status woal_do_dfs_cac(moal_private *priv,
12066 			    mlan_ds_11h_chan_rep_req *ch_rpt_req)
12067 {
12068 	mlan_ioctl_req *req = NULL;
12069 	mlan_ds_11h_cfg *p11h_cfg = NULL;
12070 	mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
12071 	mlan_status status = MLAN_STATUS_SUCCESS;
12072 
12073 	ENTER();
12074 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
12075 	if (NULL == req) {
12076 		LEAVE();
12077 		return MLAN_STATUS_FAILURE;
12078 	}
12079 	p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
12080 	pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;
12081 
12082 	moal_memcpy_ext(priv->phandle, pchan_rpt_req, ch_rpt_req,
12083 			sizeof(mlan_ds_11h_chan_rep_req),
12084 			sizeof(mlan_ds_11h_chan_rep_req));
12085 
12086 	if (priv->bss_type == MLAN_BSS_TYPE_DFS)
12087 		p11h_cfg->sub_command = MLAN_OID_11H_CHAN_REPORT_REQUEST;
12088 	else
12089 		p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
12090 
12091 	req->req_id = MLAN_IOCTL_11H_CFG;
12092 
12093 	req->action = MLAN_ACT_SET;
12094 	/* Send Channel Check command and wait until the report is ready */
12095 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
12096 	if (status != MLAN_STATUS_PENDING)
12097 		kfree(req);
12098 	LEAVE();
12099 	return status;
12100 }
12101 
12102 /**
12103  * @brief               Get Next DFS channel from dfs_chan_list
12104  *
12105  * @param priv          a pointer to moal_private structure
12106  *
12107  * @return              N/A
12108  *
12109  */
woal_get_next_dfs_chan(moal_private * priv)12110 static t_u8 woal_get_next_dfs_chan(moal_private *priv)
12111 {
12112 	int i;
12113 	int idx = priv->curr_cac_idx;
12114 	mlan_ds_11h_chan_dfs_state ch_dfs_state;
12115 	t_u8 chan = 0;
12116 	ENTER();
12117 	idx++;
12118 	if (idx >= priv->auto_dfs_cfg.num_of_chan)
12119 		idx = 0;
12120 	for (i = 0; i < priv->auto_dfs_cfg.num_of_chan; i++) {
12121 		if (priv->chan_rpt_req.chanNum !=
12122 		    priv->auto_dfs_cfg.dfs_chan_list[idx]) {
12123 			memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12124 			ch_dfs_state.channel =
12125 				priv->auto_dfs_cfg.dfs_chan_list[idx];
12126 			if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12127 						    &ch_dfs_state)) {
12128 				PRINTM(MERROR,
12129 				       "%s: woal_11h_chan_dfs_state failed \n",
12130 				       __func__);
12131 				continue;
12132 			}
12133 			if (ch_dfs_state.dfs_state != DFS_UNAVAILABLE) {
12134 				chan = priv->auto_dfs_cfg.dfs_chan_list[idx];
12135 				priv->curr_cac_idx = idx;
12136 				break;
12137 			}
12138 		}
12139 		idx++;
12140 		if (idx >= priv->auto_dfs_cfg.num_of_chan)
12141 			idx = 0;
12142 	}
12143 	LEAVE();
12144 	return chan;
12145 }
12146 
12147 /**
12148  * @brief               Process auto dfs cac
12149  *
12150  * @param priv          a pointer to moal_private structure
12151  *
12152  * @return              N/A
12153  *
12154  */
woal_do_auto_dfs(moal_private * priv)12155 static void woal_do_auto_dfs(moal_private *priv)
12156 {
12157 	mlan_ds_11h_chan_rep_req chan_rpt_req;
12158 	ENTER();
12159 	if (priv->auto_dfs_cfg.multi_chan_dfs &&
12160 	    priv->auto_dfs_cfg.num_of_chan) {
12161 		memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12162 		chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12163 		chan_rpt_req.chanNum = woal_get_next_dfs_chan(priv);
12164 		if (priv->chan_rpt_req.chanNum) {
12165 			if (woal_11h_cancel_chan_report_ioctl(priv,
12166 							      MOAL_IOCTL_WAIT))
12167 				PRINTM(MERROR,
12168 				       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12169 				       __func__);
12170 			memset(&priv->chan_rpt_req, 0,
12171 			       sizeof(mlan_ds_11h_chan_rep_req));
12172 		}
12173 		if (chan_rpt_req.chanNum) {
12174 			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12175 			chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
12176 			chan_rpt_req.millisec_dwell_time =
12177 				priv->auto_dfs_cfg.cac_timer;
12178 			moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12179 					&chan_rpt_req,
12180 					sizeof(mlan_ds_11h_chan_rep_req),
12181 					sizeof(mlan_ds_11h_chan_rep_req));
12182 			PRINTM(MCMND,
12183 			       "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12184 			       chan_rpt_req.chanNum,
12185 			       (int)(chan_rpt_req.bandcfg.chanWidth),
12186 			       chan_rpt_req.millisec_dwell_time);
12187 			if (MLAN_STATUS_SUCCESS !=
12188 			    woal_do_dfs_cac(priv, &chan_rpt_req))
12189 				PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
12190 				       __func__);
12191 		}
12192 	}
12193 	LEAVE();
12194 	return;
12195 }
12196 
12197 /*
12198  * @brief  prepare and send WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
12199  *
12200  * @param priv           A pointer moal_private structure
12201  * @param type 			 WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
12202  * @param channel 		 channel
12203  * @param radar          MTRUE/MFALSE
12204  *
12205  * @return          N/A
12206  */
woal_chan_event(moal_private * priv,t_u8 type,t_u8 channel,t_u8 radar)12207 void woal_chan_event(moal_private *priv, t_u8 type, t_u8 channel, t_u8 radar)
12208 {
12209 	struct woal_event *evt;
12210 	unsigned long flags;
12211 	moal_handle *handle = priv->phandle;
12212 
12213 	evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
12214 	if (!evt) {
12215 		PRINTM(MERROR, "Fail to alloc memory for deauth event\n");
12216 		LEAVE();
12217 		return;
12218 	}
12219 	evt->priv = priv;
12220 	evt->type = type;
12221 	evt->radar_info.channel = channel;
12222 	evt->radar_info.radar = radar;
12223 	INIT_LIST_HEAD(&evt->link);
12224 	spin_lock_irqsave(&handle->evt_lock, flags);
12225 	list_add_tail(&evt->link, &handle->evt_queue);
12226 	spin_unlock_irqrestore(&handle->evt_lock, flags);
12227 	queue_work(handle->evt_workqueue, &handle->evt_work);
12228 }
12229 
12230 /**
12231  * @brief               Get active UAP handler
12232  *
12233  * @param handle        a pointer to moal_handle structure
12234  *
12235  * @return              N/A
12236  *
12237  */
woal_get_active_uap_interface(moal_handle * handle)12238 static moal_private *woal_get_active_uap_interface(moal_handle *handle)
12239 {
12240 	int i;
12241 	moal_private *priv = NULL;
12242 	for (i = 0; i < handle->priv_num; i++) {
12243 		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
12244 			if (handle->priv[i]->bss_started == MTRUE) {
12245 				priv = handle->priv[i];
12246 				break;
12247 			}
12248 		}
12249 	}
12250 	return priv;
12251 }
12252 
12253 /**
12254  * @brief               handle auto uap channel switch
12255  *
12256  * @param priv          a pointer to moal_private structure
12257  * @param channel       channel
12258  *
12259  * @return              N/A
12260  *
12261  */
woal_auto_uap_channel_switch(moal_private * priv,t_u8 channel)12262 static void woal_auto_uap_channel_switch(moal_private *priv, t_u8 channel)
12263 {
12264 	moal_private *pmpriv = NULL;
12265 	chan_band_info chaninfo;
12266 	moal_handle *ref_handle;
12267 	t_u8 band_width = CHANNEL_BW_20MHZ;
12268 
12269 	pmpriv = woal_get_active_uap_interface(priv->phandle);
12270 	if (!pmpriv) {
12271 		ref_handle = (moal_handle *)priv->phandle->pref_mac;
12272 		pmpriv = woal_get_active_uap_interface(ref_handle);
12273 	}
12274 	if (pmpriv) {
12275 		if (MLAN_STATUS_SUCCESS !=
12276 		    woal_set_get_ap_channel(pmpriv, MLAN_ACT_GET,
12277 					    MOAL_IOCTL_WAIT, &chaninfo)) {
12278 			PRINTM(MERROR, "Fail to get ap channel \n");
12279 			return;
12280 		}
12281 		if (chaninfo.channel != channel) {
12282 			switch (chaninfo.bandcfg.chanWidth) {
12283 			case CHAN_BW_40MHZ:
12284 				if (chaninfo.bandcfg.chan2Offset ==
12285 				    SEC_CHAN_BELOW)
12286 					band_width = CHANNEL_BW_40MHZ_BELOW;
12287 				else if (chaninfo.bandcfg.chan2Offset ==
12288 					 SEC_CHAN_ABOVE)
12289 					band_width = CHANNEL_BW_40MHZ_ABOVE;
12290 				break;
12291 			case CHAN_BW_80MHZ:
12292 				band_width = CHANNEL_BW_80MHZ;
12293 				break;
12294 			default:
12295 				band_width = CHANNEL_BW_20MHZ;
12296 				break;
12297 			}
12298 #define DEF_SWITCH_COUNT 10
12299 			woal_channel_switch(pmpriv, MTRUE, 0, channel,
12300 					    DEF_SWITCH_COUNT, band_width,
12301 					    MTRUE);
12302 		}
12303 	}
12304 }
12305 
12306 /**
12307  * @brief               Process channel event
12308  *
12309  * @param priv          a pointer to moal_private structure
12310  * @param type 			WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
12311  * @param channel       channel
12312  * @param radar         radar
12313  *
12314  * @return              N/A
12315  *
12316  */
woal_process_chan_event(moal_private * priv,t_u8 type,t_u8 channel,t_u8 radar)12317 void woal_process_chan_event(moal_private *priv, t_u8 type, t_u8 channel,
12318 			     t_u8 radar)
12319 {
12320 	mlan_ds_11h_chan_rep_req chan_rpt_req;
12321 
12322 	if (!priv->auto_dfs_cfg.start_auto_zero_dfs)
12323 		return;
12324 	if (type == WOAL_EVENT_CHAN_RPT) {
12325 		if (priv->auto_dfs_cfg.uap_chan_switch && !radar) {
12326 			priv->auto_dfs_cfg.uap_chan_switch = MFALSE;
12327 			PRINTM(MCMND, "Trying uap_chan_switch to %d\n",
12328 			       channel);
12329 			woal_auto_uap_channel_switch(priv, channel);
12330 		}
12331 		woal_do_auto_dfs(priv);
12332 	} else if (type == WOAL_EVENT_RADAR) {
12333 		memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12334 		chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12335 		chan_rpt_req.chanNum = woal_get_next_dfs_chan(priv);
12336 		if (priv->chan_rpt_req.chanNum) {
12337 			if (woal_11h_cancel_chan_report_ioctl(priv,
12338 							      MOAL_IOCTL_WAIT))
12339 				PRINTM(MERROR,
12340 				       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12341 				       __func__);
12342 			memset(&priv->chan_rpt_req, 0,
12343 			       sizeof(mlan_ds_11h_chan_rep_req));
12344 		}
12345 		if (chan_rpt_req.chanNum) {
12346 			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12347 			chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
12348 			chan_rpt_req.millisec_dwell_time =
12349 				priv->auto_dfs_cfg.cac_timer;
12350 			moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12351 					&chan_rpt_req,
12352 					sizeof(mlan_ds_11h_chan_rep_req),
12353 					sizeof(mlan_ds_11h_chan_rep_req));
12354 			PRINTM(MCMND,
12355 			       "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12356 			       chan_rpt_req.chanNum,
12357 			       (int)(chan_rpt_req.bandcfg.chanWidth),
12358 			       chan_rpt_req.millisec_dwell_time);
12359 			if (MLAN_STATUS_SUCCESS !=
12360 			    woal_do_dfs_cac(priv, &chan_rpt_req))
12361 				PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
12362 				       __func__);
12363 		}
12364 	}
12365 }
12366 
12367 /**
12368  * @brief               check if channel under nop
12369  *
12370  * @param priv          a pointer to moal_private structure
12371  * @param channel       WIFI channel
12372  *
12373  * @return              length
12374  */
woal_is_channel_under_nop(moal_private * priv,t_u8 channel)12375 static t_u8 woal_is_channel_under_nop(moal_private *priv, t_u8 channel)
12376 {
12377 	mlan_ds_11h_chan_nop_info chan_nop_info;
12378 	t_u8 ret = MFALSE;
12379 	ENTER();
12380 	memset(&chan_nop_info, 0, sizeof(chan_nop_info));
12381 	chan_nop_info.curr_chan = channel;
12382 	woal_uap_get_channel_nop_info(priv, MOAL_IOCTL_WAIT, &chan_nop_info);
12383 	if (chan_nop_info.chan_under_nop)
12384 		ret = MTRUE;
12385 	LEAVE();
12386 	return ret;
12387 }
12388 
12389 /**
12390  * @brief               Process dfs cac command
12391  *
12392  * @param priv          a pointer to moal_private structure
12393  * @param respbuf       respbuf buffer
12394  * @param respbuflen    respbuf length
12395  *
12396  * @return              length
12397  */
woal_priv_do_dfs_cac(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12398 static int woal_priv_do_dfs_cac(moal_private *priv, t_u8 *respbuf,
12399 				t_u32 respbuflen)
12400 {
12401 	int ret = 0;
12402 	int data[3] = {0};
12403 	int user_data_len = 0, header_len = 0;
12404 	mlan_ds_11h_chan_rep_req chan_rpt_req;
12405 	mlan_status status = MLAN_STATUS_SUCCESS;
12406 	mlan_ds_11h_chan_dfs_state ch_dfs_state;
12407 
12408 	ENTER();
12409 
12410 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_CAC);
12411 
12412 	if ((int)strlen(respbuf) >= header_len) {
12413 		memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12414 		/* SET operation */
12415 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
12416 				&user_data_len);
12417 		if (user_data_len >= 1) {
12418 			if (!data[0] ||
12419 			    (priv->chan_rpt_req.chanNum &&
12420 			     (priv->chan_rpt_req.chanNum != data[0]))) {
12421 				if (priv->chan_rpt_pending ||
12422 				    (priv->bss_type == MLAN_BSS_TYPE_DFS)) {
12423 					if (woal_11h_cancel_chan_report_ioctl(
12424 						    priv, MOAL_IOCTL_WAIT)) {
12425 						PRINTM(MERROR,
12426 						       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12427 						       __func__);
12428 						LEAVE();
12429 						return -EFAULT;
12430 					}
12431 					priv->chan_rpt_pending = MFALSE;
12432 				}
12433 				memset(&priv->chan_rpt_req, 0,
12434 				       sizeof(mlan_ds_11h_chan_rep_req));
12435 				PRINTM(MCMND, "DFS: Stop Radar detect\n");
12436 				if (!data[0]) {
12437 					if (priv->bss_type == MLAN_BSS_TYPE_UAP)
12438 						woal_uap_11h_ctrl(priv, MFALSE);
12439 					LEAVE();
12440 					return ret;
12441 				}
12442 			}
12443 			if (data[0] == priv->chan_rpt_req.chanNum &&
12444 			    priv->bss_type == MLAN_BSS_TYPE_UAP)
12445 				woal_uap_11h_ctrl(priv, MFALSE);
12446 			memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12447 			ch_dfs_state.channel = data[0];
12448 			if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12449 						    &ch_dfs_state)) {
12450 				PRINTM(MERROR,
12451 				       "%s: woal_11h_chan_dfs_state failed \n",
12452 				       __func__);
12453 				LEAVE();
12454 				return -EFAULT;
12455 			}
12456 			if (!ch_dfs_state.dfs_required ||
12457 			    ch_dfs_state.dfs_state == DFS_UNAVAILABLE) {
12458 				PRINTM(MCMND,
12459 				       "DFS: This channel=%d under NOP or not DFS channel\n",
12460 				       data[0]);
12461 				LEAVE();
12462 				return -EINVAL;
12463 			}
12464 			if (woal_is_channel_under_nop(priv, data[0])) {
12465 				PRINTM(MCMND,
12466 				       "DFS: This channel=%d under NOP\n",
12467 				       data[0]);
12468 				LEAVE();
12469 				return -EINVAL;
12470 			}
12471 			chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12472 			chan_rpt_req.chanNum = data[0];
12473 			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12474 			chan_rpt_req.bandcfg.chanWidth = CHAN_BW_20MHZ;
12475 			chan_rpt_req.millisec_dwell_time = DEF_CAC_DWELL_TIME;
12476 			chan_rpt_req.host_based = MTRUE;
12477 		}
12478 		if (user_data_len >= 2) {
12479 			if (data[1] < 0 || data[1] > CHANNEL_BW_80MHZ) {
12480 				PRINTM(MERROR, "Inavalid bandwidth %d\n",
12481 				       data[1]);
12482 				LEAVE();
12483 				return -EINVAL;
12484 			}
12485 			woal_convert_chanbw_to_bandconfig(priv,
12486 							  &chan_rpt_req.bandcfg,
12487 							  chan_rpt_req.chanNum,
12488 							  data[1]);
12489 		}
12490 		if (user_data_len >= 3)
12491 			chan_rpt_req.millisec_dwell_time =
12492 				MIN(MAX_CAC_DWELL_TIME, data[2] * 1000);
12493 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
12494 		else {
12495 			if ((woal_is_etsi_country(
12496 				     priv->phandle->country_code) == MTRUE)) {
12497 				if (chan_rpt_req.chanNum == 120 ||
12498 				    chan_rpt_req.chanNum == 124 ||
12499 				    chan_rpt_req.chanNum == 128) {
12500 					chan_rpt_req.millisec_dwell_time =
12501 						DEF_CAC_DWELL_TIME * 10;
12502 				}
12503 				if (chan_rpt_req.chanNum == 116 &&
12504 				    user_data_len >= 2 && data[1] > 0)
12505 					chan_rpt_req.millisec_dwell_time =
12506 						DEF_CAC_DWELL_TIME * 10;
12507 			}
12508 		}
12509 #endif
12510 		moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12511 				&chan_rpt_req, sizeof(mlan_ds_11h_chan_rep_req),
12512 				sizeof(mlan_ds_11h_chan_rep_req));
12513 		PRINTM(MCMND,
12514 		       "DFS: Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12515 		       chan_rpt_req.chanNum,
12516 		       (int)(chan_rpt_req.bandcfg.chanWidth),
12517 		       chan_rpt_req.millisec_dwell_time);
12518 		status = woal_do_dfs_cac(priv, &chan_rpt_req);
12519 		if (status != MLAN_STATUS_SUCCESS)
12520 			ret = -EFAULT;
12521 		else
12522 			priv->chan_rpt_pending = MTRUE;
12523 	}
12524 	LEAVE();
12525 	return ret;
12526 }
12527 
12528 /**
12529  * @brief               Set Auto Zero DFS configure
12530  *
12531  * @param priv          Pointer to moal_private structure
12532  * @param respbuf       Pointer to response buffer
12533  * @param resplen       Response buffer length
12534  *
12535  * @return              0 --success, otherwise fail
12536  */
woal_priv_auto_dfs_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12537 static int woal_priv_auto_dfs_cfg(moal_private *priv, t_u8 *respbuf,
12538 				  t_u32 respbuflen)
12539 {
12540 	int ret = 0;
12541 	int header_len = 0;
12542 	auto_zero_dfs_cfg *auto_dfs_cfg = NULL;
12543 	int i;
12544 	int idx = 0;
12545 	mlan_ds_11h_chan_dfs_state ch_dfs_state;
12546 	mlan_ds_11h_chan_rep_req chan_rpt_req;
12547 
12548 	ENTER();
12549 	if (priv->bss_type != MLAN_BSS_TYPE_DFS) {
12550 		PRINTM(MWARN, "Invalid BSS type\n");
12551 		ret = -EINVAL;
12552 		goto done;
12553 	}
12554 
12555 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTODFS);
12556 	auto_dfs_cfg = (auto_zero_dfs_cfg *)(respbuf + header_len);
12557 	/** Auto DFS is enabled and save config to moal_private structure */
12558 	if (auto_dfs_cfg->start_auto_zero_dfs) {
12559 		if (priv->auto_dfs_cfg.start_auto_zero_dfs ||
12560 		    priv->chan_rpt_req.chanNum) {
12561 			if (woal_11h_cancel_chan_report_ioctl(
12562 				    priv, MOAL_IOCTL_WAIT)) {
12563 				PRINTM(MERROR,
12564 				       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12565 				       __func__);
12566 				ret = -EFAULT;
12567 				goto done;
12568 			}
12569 			memset(&priv->chan_rpt_req, 0,
12570 			       sizeof(mlan_ds_11h_chan_rep_req));
12571 		}
12572 		memset(&priv->auto_dfs_cfg, 0, sizeof(auto_zero_dfs_cfg));
12573 		if (auto_dfs_cfg->cac_start_chan) {
12574 			memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12575 			ch_dfs_state.channel = auto_dfs_cfg->cac_start_chan;
12576 			if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12577 						    &ch_dfs_state)) {
12578 				PRINTM(MERROR,
12579 				       "%s: woal_11h_chan_dfs_state failed \n",
12580 				       __func__);
12581 				ret = -EFAULT;
12582 				goto done;
12583 			}
12584 			if (!ch_dfs_state.dfs_required ||
12585 			    ch_dfs_state.dfs_state == DFS_UNAVAILABLE) {
12586 				PRINTM(MCMND,
12587 				       "ZeroDFS: This channel=%d under NOP or not DFS channel\n",
12588 				       auto_dfs_cfg->cac_start_chan);
12589 				LEAVE();
12590 				return -EINVAL;
12591 			}
12592 		}
12593 		priv->auto_dfs_cfg.cac_start_chan =
12594 			auto_dfs_cfg->cac_start_chan;
12595 		if (auto_dfs_cfg->cac_timer)
12596 			priv->auto_dfs_cfg.cac_timer =
12597 				MIN(MAX_CAC_DWELL_TIME,
12598 				    auto_dfs_cfg->cac_timer * 1000);
12599 		else
12600 			priv->auto_dfs_cfg.cac_timer = DEF_CAC_DWELL_TIME;
12601 		if ((auto_dfs_cfg->bw != CHANNEL_BW_20MHZ) &&
12602 		    (auto_dfs_cfg->bw != CHANNEL_BW_40MHZ_ABOVE) &&
12603 		    (auto_dfs_cfg->bw != CHANNEL_BW_40MHZ_BELOW) &&
12604 		    (auto_dfs_cfg->bw != CHANNEL_BW_80MHZ)) {
12605 			PRINTM(MERROR, "ZeroDFS: Invalid bw = %d\n",
12606 			       auto_dfs_cfg->bw);
12607 			LEAVE();
12608 			return -EINVAL;
12609 		}
12610 		priv->auto_dfs_cfg.bw = auto_dfs_cfg->bw;
12611 		priv->auto_dfs_cfg.uap_chan_switch =
12612 			auto_dfs_cfg->uap_chan_switch;
12613 		priv->auto_dfs_cfg.multi_chan_dfs =
12614 			auto_dfs_cfg->multi_chan_dfs;
12615 		if (auto_dfs_cfg->num_of_chan) {
12616 			for (i = 0; i < auto_dfs_cfg->num_of_chan; i++) {
12617 				memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12618 				ch_dfs_state.channel =
12619 					auto_dfs_cfg->dfs_chan_list[i];
12620 				if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12621 							    &ch_dfs_state)) {
12622 					PRINTM(MERROR,
12623 					       "%s: woal_11h_chan_dfs_state failed \n",
12624 					       __func__);
12625 					ret = -EFAULT;
12626 					goto done;
12627 				}
12628 				if (!ch_dfs_state.dfs_required)
12629 					continue;
12630 				priv->auto_dfs_cfg.dfs_chan_list[idx] =
12631 					auto_dfs_cfg->dfs_chan_list[i];
12632 				idx++;
12633 			}
12634 			priv->auto_dfs_cfg.num_of_chan = idx;
12635 		}
12636 		if (!priv->auto_dfs_cfg.num_of_chan)
12637 			woal_get_dfs_chan_list(priv);
12638 		priv->curr_cac_idx = -1;
12639 		if (!priv->auto_dfs_cfg.cac_start_chan)
12640 			priv->auto_dfs_cfg.cac_start_chan =
12641 				woal_get_next_dfs_chan(priv);
12642 		PRINTM(MCMND, "Start Auto ZeroDFS\n");
12643 		PRINTM(MCMND, "cac_start_chan=%d\n",
12644 		       priv->auto_dfs_cfg.cac_start_chan);
12645 		PRINTM(MCMND, "cac_timer=%d\n", priv->auto_dfs_cfg.cac_timer);
12646 		PRINTM(MCMND, "bw=%d\n", priv->auto_dfs_cfg.bw);
12647 		PRINTM(MCMND, "uap_chan_switch=%d\n",
12648 		       priv->auto_dfs_cfg.uap_chan_switch);
12649 		PRINTM(MCMND, "multi_chan_dfs=%d\n",
12650 		       priv->auto_dfs_cfg.multi_chan_dfs);
12651 		PRINTM(MCMND, "num of chan=%d\n",
12652 		       priv->auto_dfs_cfg.num_of_chan);
12653 		DBG_HEXDUMP(MCMD_D, "dfs chan list",
12654 			    priv->auto_dfs_cfg.dfs_chan_list,
12655 			    priv->auto_dfs_cfg.num_of_chan);
12656 		if (priv->auto_dfs_cfg.cac_start_chan) {
12657 			priv->auto_dfs_cfg.start_auto_zero_dfs = MTRUE;
12658 			memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12659 			chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12660 			chan_rpt_req.chanNum =
12661 				priv->auto_dfs_cfg.cac_start_chan;
12662 			chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12663 			chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
12664 			chan_rpt_req.millisec_dwell_time =
12665 				priv->auto_dfs_cfg.cac_timer;
12666 			moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12667 					&chan_rpt_req,
12668 					sizeof(mlan_ds_11h_chan_rep_req),
12669 					sizeof(mlan_ds_11h_chan_rep_req));
12670 			PRINTM(MCMND,
12671 			       "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12672 			       chan_rpt_req.chanNum,
12673 			       (int)(chan_rpt_req.bandcfg.chanWidth),
12674 			       chan_rpt_req.millisec_dwell_time);
12675 			if (MLAN_STATUS_SUCCESS !=
12676 			    woal_do_dfs_cac(priv, &chan_rpt_req)) {
12677 				PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
12678 				       __func__);
12679 				ret = -EFAULT;
12680 			}
12681 		}
12682 	} else {
12683 		PRINTM(MCMND, "Stop Auto ZeroDFS\n");
12684 		if (woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT))
12685 			PRINTM(MERROR,
12686 			       "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12687 			       __func__);
12688 		memset(&priv->chan_rpt_req, 0,
12689 		       sizeof(mlan_ds_11h_chan_rep_req));
12690 		memset(&priv->auto_dfs_cfg, 0, sizeof(auto_zero_dfs_cfg));
12691 	}
12692 done:
12693 	LEAVE();
12694 	return ret;
12695 }
12696 #endif
12697 
12698 /**
12699  * @brief               Set/Get CFP table codes
12700  *
12701  * @param priv          Pointer to moal_private structure
12702  * @param respbuf       Pointer to response buffer
12703  * @param resplen       Response buffer length
12704  *
12705  * @return             Number of bytes written, negative for failure.
12706  */
woal_priv_cfp_code(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12707 static int woal_priv_cfp_code(moal_private *priv, t_u8 *respbuf,
12708 			      t_u32 respbuflen)
12709 {
12710 	int ret = 0;
12711 	int user_data_len = 0, header_len = 0;
12712 	int data[2] = {0};
12713 	mlan_ioctl_req *req = NULL;
12714 	mlan_ds_misc_cfg *misc_cfg = NULL;
12715 	mlan_ds_misc_cfp_code *cfp_code = NULL;
12716 	mlan_status status = MLAN_STATUS_SUCCESS;
12717 
12718 	ENTER();
12719 
12720 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFP_CODE);
12721 
12722 	/* Allocate an IOCTL request buffer */
12723 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12724 	if (req == NULL) {
12725 		ret = -ENOMEM;
12726 		goto done;
12727 	}
12728 
12729 	/* Fill request buffer */
12730 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
12731 	cfp_code = &misc_cfg->param.cfp_code;
12732 	misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
12733 	req->req_id = MLAN_IOCTL_MISC_CFG;
12734 
12735 	if ((int)strlen(respbuf) == header_len) {
12736 		/* GET operation */
12737 		user_data_len = 0;
12738 		req->action = MLAN_ACT_GET;
12739 	} else {
12740 		/* SET operation */
12741 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
12742 				&user_data_len);
12743 		if (user_data_len > 2) {
12744 			PRINTM(MERROR, "Invalid number of args!\n");
12745 			ret = -EINVAL;
12746 			goto done;
12747 		}
12748 		cfp_code->cfp_code_bg = data[0];
12749 		if (user_data_len == 2)
12750 			cfp_code->cfp_code_a = data[1];
12751 		req->action = MLAN_ACT_SET;
12752 	}
12753 
12754 	/* Send IOCTL request to MLAN */
12755 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
12756 	if (status != MLAN_STATUS_SUCCESS) {
12757 		ret = -EFAULT;
12758 		goto done;
12759 	}
12760 
12761 	if (!user_data_len) {
12762 		data[0] = cfp_code->cfp_code_bg;
12763 		data[1] = cfp_code->cfp_code_a;
12764 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
12765 				sizeof(data), respbuflen);
12766 		ret = sizeof(data);
12767 	}
12768 
12769 done:
12770 	if (status != MLAN_STATUS_PENDING)
12771 		kfree(req);
12772 
12773 	LEAVE();
12774 	return ret;
12775 }
12776 
12777 /**
12778  * @brief               mcast aggr group configure
12779  *
12780  * @param priv          Pointer to moal_private structure
12781  * @param respbuf       Pointer to response buffer
12782  * @param resplen       Response buffer length
12783  *
12784  * @return              0 --success, otherwise fail
12785  */
woal_priv_mcast_aggr_group_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12786 static int woal_priv_mcast_aggr_group_cfg(moal_private *priv, t_u8 *respbuf,
12787 					  t_u32 respbuflen)
12788 {
12789 	int ret = 0;
12790 	int header_len = 0;
12791 	mcast_aggr_group *mcast_cfg = NULL;
12792 	int index = 0;
12793 	struct mcast_node *node = NULL;
12794 	unsigned long flags;
12795 
12796 	ENTER();
12797 
12798 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MCAST_AGGR_GROUP);
12799 	mcast_cfg = (mcast_aggr_group *)(respbuf + header_len);
12800 	if (mcast_cfg->action == ACTION_ADD) {
12801 		if (priv->num_mcast_addr >= MLAN_MAX_MULTICAST_LIST_SIZE) {
12802 			PRINTM(MERROR, "mcast_aggr_group already full!\n");
12803 			ret = -EINVAL;
12804 			goto done;
12805 		}
12806 		woal_add_mcast_node(priv, mcast_cfg->mcast_addr);
12807 	} else if (mcast_cfg->action == ACTION_REMOVE) {
12808 		woal_remove_mcast_node(priv, mcast_cfg->mcast_addr);
12809 	}
12810 	memset(mcast_cfg, 0, sizeof(mcast_aggr_group));
12811 
12812 	spin_lock_irqsave(&priv->mcast_lock, flags);
12813 	list_for_each_entry (node, &priv->mcast_list, link) {
12814 		moal_memcpy_ext(priv->phandle, &mcast_cfg->mac_list[index],
12815 				node->mcast_addr, ETH_ALEN, ETH_ALEN);
12816 		index++;
12817 	}
12818 	spin_unlock_irqrestore(&priv->mcast_lock, flags);
12819 	mcast_cfg->num_mcast_addr = index;
12820 	priv->num_mcast_addr = index;
12821 	ret = header_len + sizeof(mcast_aggr_group);
12822 done:
12823 	LEAVE();
12824 	return ret;
12825 }
12826 
12827 /**
12828  * @brief               mcast aggr configure
12829  *
12830  * @param priv          Pointer to moal_private structure
12831  * @param respbuf       Pointer to response buffer
12832  * @param resplen       Response buffer length
12833  *
12834  * @return              0 --success, otherwise fail
12835  */
woal_priv_mc_aggr_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12836 static int woal_priv_mc_aggr_cfg(moal_private *priv, t_u8 *respbuf,
12837 				 t_u32 respbuflen)
12838 {
12839 	mlan_ioctl_req *ioctl_req = NULL;
12840 	mlan_ds_misc_cfg *misc = NULL;
12841 	mlan_status status = MLAN_STATUS_SUCCESS;
12842 	mlan_ds_mc_aggr_cfg *mc_cfg;
12843 	int ret = 0;
12844 	int header_len = 0;
12845 
12846 	ENTER();
12847 
12848 	if (!priv || !priv->phandle) {
12849 		PRINTM(MERROR, "priv or handle is null\n");
12850 		ret = -EFAULT;
12851 		goto done;
12852 	}
12853 
12854 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12855 	if (ioctl_req == NULL) {
12856 		ret = -ENOMEM;
12857 		goto done;
12858 	}
12859 
12860 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
12861 	misc->sub_command = MLAN_OID_MISC_MC_AGGR_CFG;
12862 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
12863 
12864 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MC_AGGR_CFG);
12865 	mc_cfg = (mlan_ds_mc_aggr_cfg *)(respbuf + header_len);
12866 	ioctl_req->action = mc_cfg->action;
12867 	misc->param.mc_aggr_cfg.enable_bitmap = mc_cfg->enable_bitmap;
12868 	misc->param.mc_aggr_cfg.mask_bitmap = mc_cfg->mask_bitmap;
12869 	misc->param.mc_aggr_cfg.cts2self_offset = mc_cfg->cts2self_offset;
12870 
12871 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
12872 	if (status != MLAN_STATUS_SUCCESS) {
12873 		ret = -EFAULT;
12874 		goto done;
12875 	}
12876 
12877 	mc_cfg->enable_bitmap = misc->param.mc_aggr_cfg.enable_bitmap;
12878 	mc_cfg->mask_bitmap = misc->param.mc_aggr_cfg.mask_bitmap;
12879 	mc_cfg->cts2self_offset = misc->param.mc_aggr_cfg.cts2self_offset;
12880 	ret = header_len + sizeof(misc->param.mc_aggr_cfg);
12881 
12882 	if (mc_cfg->mask_bitmap & MC_AGGR_CTRL) {
12883 		if (mc_cfg->enable_bitmap & MC_AGGR_CTRL)
12884 			priv->enable_mc_aggr = MTRUE;
12885 		else
12886 			priv->enable_mc_aggr = MFALSE;
12887 	}
12888 done:
12889 	if (status != MLAN_STATUS_PENDING)
12890 		kfree(ioctl_req);
12891 
12892 	LEAVE();
12893 	return ret;
12894 }
12895 
12896 /**
12897  * @brief               per peer stats configure
12898  *
12899  * @param priv          Pointer to moal_private structure
12900  * @param respbuf       Pointer to response buffer
12901  * @param resplen       Response buffer length
12902  *
12903  * @return              0 --success, otherwise fail
12904  */
woal_priv_stats(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12905 static int woal_priv_stats(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
12906 {
12907 	mlan_ioctl_req *ioctl_req = NULL;
12908 	mlan_ds_misc_cfg *misc = NULL;
12909 	mlan_ds_stats *stats;
12910 	mlan_status status = MLAN_STATUS_SUCCESS;
12911 	int ret = 0;
12912 	int header_len = 0;
12913 
12914 	ENTER();
12915 
12916 	if (!priv || !priv->phandle) {
12917 		PRINTM(MERROR, "priv or handle is null\n");
12918 		ret = -EFAULT;
12919 		goto done;
12920 	}
12921 
12922 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12923 	if (ioctl_req == NULL) {
12924 		ret = -ENOMEM;
12925 		goto done;
12926 	}
12927 
12928 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
12929 	misc->sub_command = MLAN_OID_MISC_STATS;
12930 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
12931 
12932 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_STATS);
12933 	stats = (mlan_ds_stats *)(respbuf + header_len);
12934 	ioctl_req->action = stats->action;
12935 
12936 	moal_memcpy_ext(priv->phandle, &misc->param.stats, stats,
12937 			sizeof(mlan_ds_stats) + stats->tlv_len - 1,
12938 			sizeof(mlan_ds_stats) + stats->tlv_len - 1);
12939 
12940 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
12941 	if (status != MLAN_STATUS_SUCCESS) {
12942 		ret = -EFAULT;
12943 		goto done;
12944 	}
12945 
12946 	moal_memcpy_ext(priv->phandle, respbuf + header_len,
12947 			(mlan_ds_stats *)&misc->param.stats, ioctl_req->buf_len,
12948 			respbuflen - header_len);
12949 	ret = header_len + ioctl_req->buf_len;
12950 
12951 done:
12952 	LEAVE();
12953 	return ret;
12954 }
12955 /**
12956  * @brief               get channel load results
12957  *
12958  * @param priv          Pointer to moal_private structure
12959  * @param respbuf       Pointer to response buffer
12960  * @param resplen       Response buffer length
12961  *
12962  * @return              0 --success, otherwise fail
12963  */
woal_priv_get_ch_load_results(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12964 static int woal_priv_get_ch_load_results(moal_private *priv, t_u8 *respbuf,
12965 					 t_u32 respbuflen)
12966 {
12967 	mlan_ioctl_req *ioctl_req = NULL;
12968 	mlan_ds_misc_cfg *misc = NULL;
12969 	mlan_status status = MLAN_STATUS_SUCCESS;
12970 	mlan_ds_ch_load *cl_cfg;
12971 	int ret = 0;
12972 	int header_len = 0;
12973 
12974 	ENTER();
12975 
12976 	if (!priv || !priv->phandle) {
12977 		PRINTM(MERROR, "priv or handle is null\n");
12978 		ret = -EFAULT;
12979 		goto done;
12980 	}
12981 
12982 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12983 	if (ioctl_req == NULL) {
12984 		ret = -ENOMEM;
12985 		goto done;
12986 	}
12987 
12988 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
12989 	misc->sub_command = MLAN_OID_MISC_CH_LOAD_RESULTS;
12990 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
12991 
12992 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CH_LOAD_RESULTS);
12993 	cl_cfg = (mlan_ds_ch_load *)(respbuf + header_len);
12994 	ioctl_req->action = cl_cfg->action;
12995 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
12996 	if (status != MLAN_STATUS_SUCCESS) {
12997 		ret = -EAGAIN;
12998 		goto done;
12999 	}
13000 
13001 	cl_cfg->ch_load_param = misc->param.ch_load.ch_load_param;
13002 	cl_cfg->noise = misc->param.ch_load.noise;
13003 	cl_cfg->rx_quality = misc->param.ch_load.rx_quality;
13004 	ret = header_len + sizeof(misc->param.ch_load);
13005 
13006 done:
13007 	if (status != MLAN_STATUS_PENDING)
13008 		kfree(ioctl_req);
13009 
13010 	LEAVE();
13011 	return ret;
13012 }
13013 
13014 /**
13015  * @brief               get channel load
13016  *
13017  * @param priv          Pointer to moal_private structure
13018  * @param respbuf       Pointer to response buffer
13019  * @param resplen       Response buffer length
13020  *
13021  * @return              0 --success, otherwise fail
13022  */
woal_priv_get_ch_load(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13023 static int woal_priv_get_ch_load(moal_private *priv, t_u8 *respbuf,
13024 				 t_u32 respbuflen)
13025 {
13026 	mlan_ioctl_req *ioctl_req = NULL;
13027 	mlan_ds_misc_cfg *misc = NULL;
13028 	mlan_status status = MLAN_STATUS_SUCCESS;
13029 	mlan_ds_ch_load *cl_cfg;
13030 	int ret = 0;
13031 	int header_len = 0;
13032 
13033 	ENTER();
13034 
13035 	if (!priv || !priv->phandle) {
13036 		PRINTM(MERROR, "priv or handle is null\n");
13037 		ret = -EFAULT;
13038 		goto done;
13039 	}
13040 
13041 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13042 	if (ioctl_req == NULL) {
13043 		ret = -ENOMEM;
13044 		goto done;
13045 	}
13046 
13047 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
13048 	misc->sub_command = MLAN_OID_MISC_CH_LOAD;
13049 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
13050 
13051 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CH_LOAD);
13052 	cl_cfg = (mlan_ds_ch_load *)(respbuf + header_len);
13053 	ioctl_req->action = cl_cfg->action;
13054 	misc->param.ch_load.ch_load_param = cl_cfg->ch_load_param;
13055 	misc->param.ch_load.noise = cl_cfg->noise;
13056 	misc->param.ch_load.rx_quality = cl_cfg->rx_quality;
13057 	misc->param.ch_load.duration = cl_cfg->duration;
13058 	status = woal_request_ioctl(priv, ioctl_req, MOAL_NO_WAIT);
13059 	if (status != MLAN_STATUS_SUCCESS && status != MLAN_STATUS_PENDING) {
13060 		ret = -EFAULT;
13061 		goto done;
13062 	}
13063 
13064 	ret = header_len + sizeof(misc->param.ch_load);
13065 
13066 done:
13067 	if (status != MLAN_STATUS_PENDING)
13068 		kfree(ioctl_req);
13069 
13070 	LEAVE();
13071 	return ret;
13072 }
13073 
13074 /**
13075  * @brief               Set/Get Tx/Rx antenna
13076  *
13077  * @param priv          Pointer to moal_private structure
13078  * @param respbuf       Pointer to response buffer
13079  * @param resplen       Response buffer length
13080  *
13081  * @return             Number of bytes written, negative for failure.
13082  */
woal_priv_set_get_tx_rx_ant(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13083 static int woal_priv_set_get_tx_rx_ant(moal_private *priv, t_u8 *respbuf,
13084 				       t_u32 respbuflen)
13085 {
13086 	int ret = 0;
13087 	int user_data_len = 0, header_len = 0;
13088 	mlan_ds_radio_cfg *radio = NULL;
13089 	mlan_ioctl_req *req = NULL;
13090 	int data[3] = {0};
13091 	mlan_status status = MLAN_STATUS_SUCCESS;
13092 
13093 	ENTER();
13094 
13095 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ANT_CFG);
13096 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
13097 	if (req == NULL) {
13098 		ret = -ENOMEM;
13099 		goto done;
13100 	}
13101 	radio = (mlan_ds_radio_cfg *)req->pbuf;
13102 	radio->sub_command = MLAN_OID_ANT_CFG;
13103 	req->req_id = MLAN_IOCTL_RADIO_CFG;
13104 
13105 	if ((int)strlen(respbuf) == header_len) {
13106 		/* GET operation */
13107 		user_data_len = 0;
13108 		req->action = MLAN_ACT_GET;
13109 	} else {
13110 		/* SET operation */
13111 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
13112 				&user_data_len);
13113 		if (user_data_len > 2) {
13114 			PRINTM(MERROR, "Invalid number of args!\n");
13115 			ret = -EINVAL;
13116 			goto done;
13117 		}
13118 		if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
13119 			radio->param.ant_cfg.tx_antenna = data[0];
13120 			radio->param.ant_cfg.rx_antenna = data[0];
13121 			if (user_data_len == 2)
13122 				radio->param.ant_cfg.rx_antenna = data[1];
13123 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
13124 			if (IS_CARD9098(priv->phandle->card_type) ||
13125 			    IS_CARD9097(priv->phandle->card_type)) {
13126 				woal_cfg80211_notify_antcfg(
13127 					priv, priv->phandle->wiphy, radio);
13128 			}
13129 #endif
13130 		} else {
13131 			radio->param.ant_cfg_1x1.antenna = data[0];
13132 			if (user_data_len == 2)
13133 				radio->param.ant_cfg_1x1.evaluate_time =
13134 					data[1];
13135 		}
13136 		req->action = MLAN_ACT_SET;
13137 	}
13138 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13139 	if (status != MLAN_STATUS_SUCCESS) {
13140 		ret = -EFAULT;
13141 		goto done;
13142 	}
13143 	if (!user_data_len) {
13144 		if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
13145 			data[0] = radio->param.ant_cfg.tx_antenna;
13146 			data[1] = radio->param.ant_cfg.rx_antenna;
13147 			if (data[0] && data[1])
13148 				ret = sizeof(int) * 2;
13149 			else
13150 				ret = sizeof(int) * 1;
13151 			moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
13152 					sizeof(data), respbuflen);
13153 		} else {
13154 			data[0] = (int)radio->param.ant_cfg_1x1.antenna;
13155 			data[1] = (int)radio->param.ant_cfg_1x1.evaluate_time;
13156 			data[2] = (int)radio->param.ant_cfg_1x1.current_antenna;
13157 			moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
13158 					sizeof(data), respbuflen);
13159 			ret = sizeof(data);
13160 		}
13161 	}
13162 done:
13163 	if (status != MLAN_STATUS_PENDING)
13164 		kfree(req);
13165 	LEAVE();
13166 	return ret;
13167 }
13168 
13169 /*
13170  * @brief               Set/Get CWMode
13171  *
13172  * @param priv          Pointer to moal_private structure
13173  * @param respbuf       Pointer to response buffer
13174  * @param resplen       Response buffer length
13175  *
13176  *  @return             Number of bytes written, negative for failure.
13177  */
woal_priv_set_get_cwmode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13178 static int woal_priv_set_get_cwmode(moal_private *priv, t_u8 *respbuf,
13179 				    t_u32 respbuflen)
13180 {
13181 	mlan_ioctl_req *ioctl_req = NULL;
13182 	mlan_ds_misc_cfg *misc = NULL;
13183 	mlan_status status = MLAN_STATUS_SUCCESS;
13184 	mlan_ds_cw_mode_ctrl *cwmode;
13185 	int ret = 0;
13186 	int header_len = 0;
13187 
13188 	ENTER();
13189 
13190 	if (!priv || !priv->phandle) {
13191 		PRINTM(MERROR, "priv or handle is null\n");
13192 		ret = -EFAULT;
13193 		goto done;
13194 	}
13195 
13196 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13197 	if (ioctl_req == NULL) {
13198 		ret = -ENOMEM;
13199 		goto done;
13200 	}
13201 
13202 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
13203 	misc->sub_command = MLAN_OID_MISC_CWMODE_CTRL;
13204 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
13205 
13206 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CWMODE);
13207 	if ((int)strlen(respbuf) == header_len) {
13208 		/* GET operation */
13209 		ioctl_req->action = MLAN_ACT_GET;
13210 	} else {
13211 		/* SET operation */
13212 		ioctl_req->action = MLAN_ACT_SET;
13213 
13214 		cwmode = (mlan_ds_cw_mode_ctrl *)(respbuf + header_len +
13215 						  sizeof(t_u8));
13216 		misc->param.cwmode.mode = cwmode->mode;
13217 		misc->param.cwmode.txPower = cwmode->txPower;
13218 		misc->param.cwmode.rateInfo = cwmode->rateInfo;
13219 		misc->param.cwmode.channel = cwmode->channel;
13220 		misc->param.cwmode.chanInfo = cwmode->chanInfo;
13221 		misc->param.cwmode.pktLength = cwmode->pktLength;
13222 	}
13223 
13224 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
13225 	if (status != MLAN_STATUS_SUCCESS) {
13226 		ret = -EFAULT;
13227 		goto done;
13228 	}
13229 
13230 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.cwmode,
13231 			sizeof(misc->param.cwmode), respbuflen);
13232 	ret = sizeof(misc->param.cwmode);
13233 
13234 done:
13235 	if (status != MLAN_STATUS_PENDING)
13236 		kfree(ioctl_req);
13237 
13238 	LEAVE();
13239 	return ret;
13240 }
13241 
13242 /**
13243  * @brief               Set/Get out band independent reset
13244  *
13245  * @param priv          Pointer to moal_private structure
13246  * @param respbuf       Pointer to response buffer
13247  * @param resplen       Response buffer length
13248  *
13249  * @return             Number of bytes written, negative for failure.
13250  */
woal_priv_ind_rst_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13251 static int woal_priv_ind_rst_cfg(moal_private *priv, t_u8 *respbuf,
13252 				 t_u32 respbuflen)
13253 {
13254 	int ret = 0;
13255 	int user_data_len = 0, header_len = 0;
13256 	mlan_ds_misc_cfg *misc = NULL;
13257 	mlan_ioctl_req *req = NULL;
13258 	int data[2] = {0};
13259 	mlan_status status = MLAN_STATUS_SUCCESS;
13260 
13261 	ENTER();
13262 
13263 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_IND_RST_CFG);
13264 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13265 	if (req == NULL) {
13266 		ret = -ENOMEM;
13267 		goto done;
13268 	}
13269 	misc = (mlan_ds_misc_cfg *)req->pbuf;
13270 	memset(misc, 0, sizeof(mlan_ds_misc_cfg));
13271 	misc->sub_command = MLAN_OID_MISC_IND_RST_CFG;
13272 	req->req_id = MLAN_IOCTL_MISC_CFG;
13273 
13274 	if ((int)strlen(respbuf) == header_len) {
13275 		/* GET operation */
13276 		user_data_len = 0;
13277 		req->action = MLAN_ACT_GET;
13278 	} else {
13279 		/* SET operation */
13280 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
13281 				&user_data_len);
13282 		if (user_data_len > 2) {
13283 			PRINTM(MERROR, "Invalid number of args!\n");
13284 			ret = -EINVAL;
13285 			goto done;
13286 		}
13287 
13288 		if ((user_data_len == 1) || (user_data_len == 2)) {
13289 			req->action = MLAN_ACT_SET;
13290 
13291 			/* ir_mode */
13292 			if (data[0] < 0 || data[0] > 2) {
13293 				PRINTM(MERROR, "Invalid ir mode parameter!\n");
13294 				ret = -EINVAL;
13295 				goto done;
13296 			}
13297 			misc->param.ind_rst_cfg.ir_mode = data[0];
13298 
13299 			/* gpio_pin */
13300 			if (user_data_len == 2) {
13301 				if ((data[1] != 0xFF) && (data[1] < 0)) {
13302 					PRINTM(MERROR,
13303 					       "Invalid gpio pin no!\n");
13304 					ret = -EINVAL;
13305 					goto done;
13306 				}
13307 				misc->param.ind_rst_cfg.gpio_pin = data[1];
13308 			}
13309 		}
13310 	}
13311 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13312 	if (status != MLAN_STATUS_SUCCESS) {
13313 		ret = -EFAULT;
13314 		goto done;
13315 	}
13316 
13317 	data[0] = (int)misc->param.ind_rst_cfg.ir_mode;
13318 	data[1] = (int)misc->param.ind_rst_cfg.gpio_pin;
13319 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
13320 			respbuflen);
13321 	ret = sizeof(data);
13322 
13323 done:
13324 	if (status != MLAN_STATUS_PENDING)
13325 		kfree(req);
13326 	LEAVE();
13327 	return ret;
13328 }
13329 
13330 /**
13331  * @brief               Get/Set system clock
13332  * @param priv          Pointer to moal_private structure
13333  * @param respbuf       Pointer to response buffer
13334  * @param resplen       Response buffer length
13335  *
13336  *  @return             Number of bytes written, negative for failure.
13337  */
woal_priv_sysclock(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13338 static int woal_priv_sysclock(moal_private *priv, t_u8 *respbuf,
13339 			      t_u32 respbuflen)
13340 {
13341 	int data[65];
13342 	mlan_ioctl_req *req = NULL;
13343 	mlan_ds_misc_cfg *cfg = NULL;
13344 	int ret = 0, i = 0;
13345 	int user_data_len = 0, header_len = 0;
13346 	int data_length = 0, length_index = 0;
13347 	mlan_status status = MLAN_STATUS_SUCCESS;
13348 
13349 	ENTER();
13350 
13351 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SYSCLOCK);
13352 	memset(data, 0, sizeof(data));
13353 	if ((int)strlen(respbuf) == header_len) {
13354 		/* GET operation */
13355 		user_data_len = 0;
13356 	} else {
13357 		/* SET operation */
13358 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
13359 				&user_data_len);
13360 	}
13361 
13362 	if (user_data_len > MLAN_MAX_CLK_NUM) {
13363 		PRINTM(MERROR, "Invalid number of parameters\n");
13364 		ret = -EINVAL;
13365 		goto done;
13366 	}
13367 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13368 	if (req == NULL) {
13369 		ret = -ENOMEM;
13370 		goto done;
13371 	}
13372 
13373 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
13374 	cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
13375 	req->req_id = MLAN_IOCTL_MISC_CFG;
13376 
13377 	if (user_data_len) {
13378 		/* SET operation */
13379 		req->action = MLAN_ACT_SET;
13380 
13381 		/* Set configurable clocks */
13382 		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
13383 		cfg->param.sys_clock.sys_clk_num =
13384 			MIN(MLAN_MAX_CLK_NUM, user_data_len);
13385 		for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++)
13386 			cfg->param.sys_clock.sys_clk[i] = (t_u16)data[i];
13387 
13388 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13389 		if (status != MLAN_STATUS_SUCCESS) {
13390 			ret = -EFAULT;
13391 			goto done;
13392 		}
13393 	} else {
13394 		/* GET operation */
13395 		req->action = MLAN_ACT_GET;
13396 
13397 		/* Get configurable clocks */
13398 		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
13399 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13400 		if (status != MLAN_STATUS_SUCCESS) {
13401 			ret = -EFAULT;
13402 			goto done;
13403 		}
13404 
13405 		/* Current system clock */
13406 		data[1] = (int)cfg->param.sys_clock.cur_sys_clk;
13407 		data_length = 1;
13408 
13409 		length_index =
13410 			MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
13411 
13412 		/* Configurable clocks */
13413 		for (i = 1; i <= length_index; i++)
13414 			data[i + data_length] =
13415 				(int)cfg->param.sys_clock.sys_clk[i - 1];
13416 
13417 		data_length += length_index;
13418 
13419 		/* Get supported clocks */
13420 		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
13421 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13422 		if (status != MLAN_STATUS_SUCCESS) {
13423 			ret = -EFAULT;
13424 			goto done;
13425 		}
13426 
13427 		length_index =
13428 			MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
13429 
13430 		/* Supported clocks */
13431 		for (i = 1; i <= length_index; i++)
13432 			data[i + data_length] =
13433 				(int)cfg->param.sys_clock.sys_clk[i - 1];
13434 
13435 		data_length += length_index;
13436 
13437 		/* Send length as first element */
13438 		data[0] = data_length;
13439 		data_length++;
13440 
13441 		moal_memcpy_ext(priv->phandle, respbuf, data,
13442 				sizeof(int) * data_length, respbuflen);
13443 		ret = data_length * sizeof(int);
13444 	}
13445 
13446 done:
13447 	if (status != MLAN_STATUS_PENDING)
13448 		kfree(req);
13449 	LEAVE();
13450 	return ret;
13451 }
13452 
13453 /**
13454  * @brief               Get GTK/PTK
13455  * @param priv          Pointer to moal_private structure
13456  * @param respbuf       Pointer to response buffer
13457  * @param resplen       Response buffer length
13458  *
13459  *  @return             Number of bytes written, negative for failure.
13460  */
woal_priv_get_key(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13461 static int woal_priv_get_key(moal_private *priv, t_u8 *respbuf,
13462 			     t_u32 respbuflen)
13463 {
13464 	int ret = 0, copy_len = 0;
13465 	int header_len = 0;
13466 	unsigned int i;
13467 	t_u8 key_ascii[256];
13468 	t_u8 *tmp;
13469 	mlan_ds_sec_cfg *sec = NULL;
13470 	mlan_ioctl_req *req = NULL;
13471 	mlan_status status = MLAN_STATUS_SUCCESS;
13472 
13473 	ENTER();
13474 
13475 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_KEY);
13476 	if ((int)strlen(respbuf) != header_len) {
13477 		PRINTM(MERROR, "Invalid number of parameters\n");
13478 		ret = -EINVAL;
13479 		goto done;
13480 	}
13481 	memset(key_ascii, 0x00, sizeof(key_ascii));
13482 	tmp = key_ascii;
13483 
13484 	if (priv->media_connected == MFALSE) {
13485 		PRINTM(MERROR, "Can't get key in un-associated state\n");
13486 		ret = -EFAULT;
13487 		goto done;
13488 	}
13489 
13490 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
13491 	if (req == NULL) {
13492 		ret = -ENOMEM;
13493 		goto done;
13494 	}
13495 
13496 	/* Get Unicast Key */
13497 	req->req_id = MLAN_IOCTL_SEC_CFG;
13498 	req->action = MLAN_ACT_GET;
13499 	sec = (mlan_ds_sec_cfg *)req->pbuf;
13500 	sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
13501 	sec->param.encrypt_key.key_index = 0;
13502 	sec->param.encrypt_key.key_flags = 0;
13503 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13504 	if (status != MLAN_STATUS_SUCCESS) {
13505 		ret = -EFAULT;
13506 		goto done;
13507 	}
13508 	if (sec->param.encrypt_key.key_len) {
13509 		sprintf((char *)tmp, "\n%s", "PTK: ");
13510 		tmp += 5;
13511 		for (i = 0; i < sec->param.encrypt_key.key_len; i++)
13512 			tmp += sprintf((char *)tmp, "%02x",
13513 				       sec->param.encrypt_key.key_material[i]);
13514 	}
13515 
13516 	/* Get Multicase Key */
13517 	req->req_id = MLAN_IOCTL_SEC_CFG;
13518 	req->action = MLAN_ACT_GET;
13519 	sec = (mlan_ds_sec_cfg *)req->pbuf;
13520 	sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
13521 	sec->param.encrypt_key.key_index = 0;
13522 	sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
13523 	memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
13524 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13525 	if (status != MLAN_STATUS_SUCCESS) {
13526 		ret = -EFAULT;
13527 		goto done;
13528 	}
13529 	if (sec->param.encrypt_key.key_len) {
13530 		sprintf((char *)tmp, "\n%s", "GTK: ");
13531 		tmp += 5;
13532 		for (i = 0; i < sec->param.encrypt_key.key_len; i++)
13533 			tmp += sprintf((char *)tmp, "%02x",
13534 				       sec->param.encrypt_key.key_material[i]);
13535 	}
13536 
13537 	/* Get IGTK Key */
13538 	req->req_id = MLAN_IOCTL_SEC_CFG;
13539 	req->action = MLAN_ACT_GET;
13540 	sec = (mlan_ds_sec_cfg *)req->pbuf;
13541 	sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
13542 	sec->param.encrypt_key.key_index = 0;
13543 	sec->param.encrypt_key.key_flags = KEY_FLAG_AES_MCAST_IGTK;
13544 	memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
13545 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13546 	if (status != MLAN_STATUS_SUCCESS) {
13547 		ret = -EFAULT;
13548 		goto done;
13549 	}
13550 	if (sec->param.encrypt_key.key_len) {
13551 		sprintf((char *)tmp, "\n%s", "IGTK: ");
13552 		tmp += 6;
13553 		for (i = 0; i < sec->param.encrypt_key.key_len; i++)
13554 			tmp += sprintf((char *)tmp, "%02x",
13555 				       sec->param.encrypt_key.key_material[i]);
13556 	}
13557 
13558 	copy_len = tmp - key_ascii;
13559 	moal_memcpy_ext(priv->phandle, respbuf, &key_ascii, copy_len,
13560 			respbuflen);
13561 	ret = copy_len;
13562 done:
13563 	if (status != MLAN_STATUS_PENDING)
13564 		kfree(req);
13565 
13566 	LEAVE();
13567 	return ret;
13568 }
13569 
13570 /**
13571  * @brief               Associate to a specific indexed entry in the ScanTable
13572  * @param priv          Pointer to moal_private structure
13573  * @param respbuf       Pointer to response buffer
13574  * @param resplen       Response buffer length
13575  *
13576  *  @return             Number of bytes written, negative for failure.
13577  */
woal_priv_associate_ssid_bssid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13578 static int woal_priv_associate_ssid_bssid(moal_private *priv, t_u8 *respbuf,
13579 					  t_u32 respbuflen)
13580 {
13581 	int ret = 0, copy_len = 0;
13582 	int header_len = 0;
13583 	mlan_ssid_bssid ssid_bssid;
13584 #ifdef REASSOCIATION
13585 	mlan_bss_info bss_info;
13586 #endif
13587 	char buf[64];
13588 	t_u8 buflen;
13589 	t_u8 mac_idx;
13590 	t_u8 i;
13591 
13592 	ENTER();
13593 
13594 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCIATE);
13595 	if ((int)strlen(respbuf) == header_len) {
13596 		PRINTM(MERROR, "Invalid number of parameters\n");
13597 		ret = -EINVAL;
13598 		goto done;
13599 	}
13600 	copy_len = strlen(respbuf) - header_len;
13601 	mac_idx = 0;
13602 	buflen = MIN(copy_len, (int)(sizeof(buf) - 1));
13603 	memset(buf, 0, sizeof(buf));
13604 	memset(&ssid_bssid, 0, sizeof(ssid_bssid));
13605 
13606 	if (buflen < (3 * ETH_ALEN) + 2) {
13607 		PRINTM(MERROR,
13608 		       "Associate: Insufficient length in IOCTL input\n");
13609 
13610 		/* buffer should be at least 3 characters per BSSID octet "00:"
13611 		**   plus a space separater and at least 1 char in the SSID
13612 		*/
13613 		ret = -EINVAL;
13614 		goto done;
13615 	}
13616 
13617 	moal_memcpy_ext(priv->phandle, buf, respbuf + header_len, buflen,
13618 			sizeof(buf));
13619 
13620 	/* Skip white space */
13621 	for (i = 0; (i < buflen) && (buf[i] == ' '); i++)
13622 		;
13623 
13624 	/* Copy/Convert the BSSID */
13625 	for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); i++) {
13626 		if (buf[i] == ':') {
13627 			mac_idx++;
13628 		} else {
13629 			ssid_bssid.bssid[mac_idx] = (t_u8)woal_atox(buf + i);
13630 
13631 			while (((i < buflen) && isxdigit(buf[i + 1])))
13632 				/* Skip entire hex value */
13633 				i++;
13634 		}
13635 	}
13636 
13637 	/* Skip one space between the BSSID and start of the SSID */
13638 	i++;
13639 
13640 	/* Copy the SSID */
13641 	ssid_bssid.ssid.ssid_len = buflen - i;
13642 	moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid, buf + i,
13643 			sizeof(ssid_bssid.ssid.ssid),
13644 			sizeof(ssid_bssid.ssid.ssid));
13645 
13646 	PRINTM(MCMND, "iwpriv assoc: AP=[" MACSTR "], ssid(%d)=[%s]\n",
13647 	       MAC2STR(ssid_bssid.bssid), (int)ssid_bssid.ssid.ssid_len,
13648 	       ssid_bssid.ssid.ssid);
13649 
13650 	if (MLAN_STATUS_SUCCESS !=
13651 	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
13652 		ret = -EFAULT;
13653 		goto done;
13654 	}
13655 
13656 #ifdef REASSOCIATION
13657 	memset(&bss_info, 0x00, sizeof(bss_info));
13658 	if (MLAN_STATUS_SUCCESS ==
13659 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
13660 		moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
13661 				&bss_info.ssid, sizeof(mlan_802_11_ssid),
13662 				sizeof(mlan_802_11_ssid));
13663 		moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
13664 				&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
13665 				sizeof(mlan_802_11_mac_addr));
13666 	}
13667 #endif /* REASSOCIATION */
13668 
13669 done:
13670 	LEAVE();
13671 	return ret;
13672 }
13673 
13674 /* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
13675 #define MAX_IN_OUT_CHAR 256
13676 /** Tx BF Global conf argument index */
13677 #define BF_ENABLE_PARAM 1
13678 #define SOUND_ENABLE_PARAM 2
13679 #define FB_TYPE_PARAM 3
13680 #define SNR_THRESHOLD_PARAM 4
13681 #define SOUND_INTVL_PARAM 5
13682 #define BF_MODE_PARAM 6
13683 #define BF_CFG_ACT_GET 0
13684 #define BF_CFG_ACT_SET 1
13685 
13686 /**
13687  * @brief               Set/Get Transmit beamforming configuration
13688  * @param priv          Pointer to moal_private structure
13689  * @param respbuf       Pointer to response buffer
13690  * @param resplen       Response buffer length
13691  *
13692  *  @return             Number of bytes written, negative for failure.
13693  */
woal_priv_tx_bf_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13694 static int woal_priv_tx_bf_cfg(moal_private *priv, t_u8 *respbuf,
13695 			       t_u32 respbuflen)
13696 {
13697 	int header_len = 0;
13698 	int ret = 0, copy_len = 0;
13699 	int bf_action = 0, interval = 0;
13700 	int snr = 0, i, tmp_val = 0;
13701 	t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
13702 	t_u8 *str, *token, *pos;
13703 	t_u16 action = 0;
13704 
13705 	mlan_ds_11n_tx_bf_cfg bf_cfg;
13706 	mlan_trigger_sound_args *bf_sound = NULL;
13707 	mlan_tx_bf_peer_args *tx_bf_peer = NULL;
13708 	mlan_snr_thr_args *bf_snr = NULL;
13709 	mlan_bf_periodicity_args *bf_periodicity = NULL;
13710 	mlan_bf_global_cfg_args *bf_global = NULL;
13711 
13712 	ENTER();
13713 
13714 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CFG);
13715 	if ((int)strlen(respbuf) == header_len) {
13716 		PRINTM(MERROR, "Invalid number of parameters\n");
13717 		ret = -EINVAL;
13718 		goto done;
13719 	}
13720 	memset(&bf_cfg, 0, sizeof(bf_cfg));
13721 	/* Pointer to corresponding buffer */
13722 	bf_sound = bf_cfg.body.bf_sound;
13723 	tx_bf_peer = bf_cfg.body.tx_bf_peer;
13724 	bf_snr = bf_cfg.body.bf_snr;
13725 	bf_periodicity = bf_cfg.body.bf_periodicity;
13726 	bf_global = &bf_cfg.body.bf_global_cfg;
13727 
13728 	/* Total characters in buffer */
13729 	char_count = strlen(respbuf) - header_len;
13730 	copy_len = char_count;
13731 	memset(buf, 0, sizeof(buf));
13732 	if (char_count) {
13733 		if (copy_len > (int)sizeof(buf)) {
13734 			PRINTM(MERROR, "Too many arguments\n");
13735 			ret = -EINVAL;
13736 			goto done;
13737 		}
13738 		moal_memcpy_ext(priv->phandle, buf, respbuf + header_len,
13739 				copy_len, sizeof(buf));
13740 
13741 		if (char_count > 1 && buf[1] != ';') {
13742 			PRINTM(MERROR,
13743 			       "No action argument. Separate with ';'\n");
13744 			ret = -EINVAL;
13745 			goto done;
13746 		}
13747 		/* Replace ';' with NULL in the string to separate args */
13748 		for (i = 0; i < char_count; i++) {
13749 			if (buf[i] == ';')
13750 				buf[i] = '\0';
13751 		}
13752 		/* The first byte represents the beamforming action */
13753 		if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
13754 			ret = -EINVAL;
13755 			goto done;
13756 		}
13757 		switch (bf_action) {
13758 		case BF_GLOBAL_CONFIGURATION:
13759 			if (char_count == 1) {
13760 				action = MLAN_ACT_GET;
13761 				bf_cfg.action = BF_CFG_ACT_GET;
13762 			} else {
13763 				action = MLAN_ACT_SET;
13764 				bf_cfg.action = BF_CFG_ACT_SET;
13765 				/* Eliminate action field */
13766 				token = &buf[2];
13767 				for (i = 1, str = &buf[2]; token != NULL; i++) {
13768 					token = strstr(str, " ");
13769 					pos = str;
13770 					if (token != NULL) {
13771 						*token = '\0';
13772 						str = token + 1;
13773 					}
13774 					woal_atoi(&tmp_val, pos);
13775 					switch (i) {
13776 					case BF_ENABLE_PARAM:
13777 						bf_global->bf_enbl =
13778 							(t_u8)tmp_val;
13779 						break;
13780 					case SOUND_ENABLE_PARAM:
13781 						bf_global->sounding_enbl =
13782 							(t_u8)tmp_val;
13783 						break;
13784 					case FB_TYPE_PARAM:
13785 						bf_global->fb_type =
13786 							(t_u8)tmp_val;
13787 						break;
13788 					case SNR_THRESHOLD_PARAM:
13789 						bf_global->snr_threshold =
13790 							(t_u8)tmp_val;
13791 						break;
13792 					case SOUND_INTVL_PARAM:
13793 						bf_global->sounding_interval =
13794 							(t_u16)tmp_val;
13795 						break;
13796 					case BF_MODE_PARAM:
13797 						bf_global->bf_mode =
13798 							(t_u8)tmp_val;
13799 						break;
13800 					default:
13801 						PRINTM(MERROR,
13802 						       "Invalid Argument\n");
13803 						ret = -EINVAL;
13804 						goto done;
13805 					}
13806 				}
13807 			}
13808 			break;
13809 		case TRIGGER_SOUNDING_FOR_PEER:
13810 			/* First arg  = 2   BfAction
13811 			 * Second arg = 17  MAC "00:50:43:20:BF:64" */
13812 			if (char_count != 19) {
13813 				PRINTM(MERROR, "Invalid argument\n");
13814 				ret = -EINVAL;
13815 				goto done;
13816 			}
13817 			woal_mac2u8(bf_sound->peer_mac, &buf[2]);
13818 			action = MLAN_ACT_SET;
13819 			bf_cfg.action = BF_CFG_ACT_SET;
13820 			break;
13821 		case SET_GET_BF_PERIODICITY:
13822 			/* First arg  = 2   BfAction
13823 			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
13824 			 * Third arg =  1  (min char)  TX BF interval
13825 			 *              10 (max char)  u32 maximum value
13826 			 * 4294967295 */
13827 			if (char_count < 19 || char_count > 30) {
13828 				PRINTM(MERROR, "Invalid argument\n");
13829 				ret = -EINVAL;
13830 				goto done;
13831 			}
13832 
13833 			woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
13834 			if (char_count == 19) {
13835 				action = MLAN_ACT_GET;
13836 				bf_cfg.action = BF_CFG_ACT_GET;
13837 			} else {
13838 				action = MLAN_ACT_SET;
13839 				bf_cfg.action = BF_CFG_ACT_SET;
13840 				if (woal_atoi(&interval, &buf[20]) !=
13841 				    MLAN_STATUS_SUCCESS) {
13842 					ret = -EINVAL;
13843 					goto done;
13844 				}
13845 				bf_periodicity->interval = interval;
13846 			}
13847 			break;
13848 		case TX_BF_FOR_PEER_ENBL:
13849 			/* Handle only SET operation here
13850 			 * First arg  = 2   BfAction
13851 			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
13852 			 * Third arg  = 2   enable/disable bf
13853 			 * Fourth arg = 2   enable/disable sounding
13854 			 * Fifth arg  = 1   FB Type */
13855 			if (char_count != 25 && char_count != 1) {
13856 				PRINTM(MERROR, "Invalid argument\n");
13857 				ret = -EINVAL;
13858 				goto done;
13859 			}
13860 			if (char_count == 1) {
13861 				action = MLAN_ACT_GET;
13862 				bf_cfg.action = BF_CFG_ACT_GET;
13863 			} else {
13864 				woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
13865 				woal_atoi(&tmp_val, &buf[20]);
13866 				tx_bf_peer->bf_enbl = (t_u8)tmp_val;
13867 				woal_atoi(&tmp_val, &buf[22]);
13868 				tx_bf_peer->sounding_enbl = (t_u8)tmp_val;
13869 				woal_atoi(&tmp_val, &buf[24]);
13870 				tx_bf_peer->fb_type = (t_u8)tmp_val;
13871 				action = MLAN_ACT_SET;
13872 				bf_cfg.action = BF_CFG_ACT_SET;
13873 			}
13874 			break;
13875 		case SET_SNR_THR_PEER:
13876 			/* First arg  = 2   BfAction
13877 			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
13878 			 * Third arg  = 1/2 SNR u8 - can be 1/2 charerters */
13879 			if (char_count != 1 &&
13880 			    !(char_count == 21 || char_count == 22)) {
13881 				PRINTM(MERROR, "Invalid argument\n");
13882 				ret = -EINVAL;
13883 				goto done;
13884 			}
13885 			if (char_count == 1) {
13886 				action = MLAN_ACT_GET;
13887 				bf_cfg.action = BF_CFG_ACT_GET;
13888 			} else {
13889 				woal_mac2u8(bf_snr->peer_mac, &buf[2]);
13890 				if (woal_atoi(&snr, &buf[20]) !=
13891 				    MLAN_STATUS_SUCCESS) {
13892 					ret = -EINVAL;
13893 					goto done;
13894 				}
13895 				bf_snr->snr = snr;
13896 				action = MLAN_ACT_SET;
13897 				bf_cfg.action = BF_CFG_ACT_SET;
13898 			}
13899 			break;
13900 		default:
13901 			ret = -EINVAL;
13902 			goto done;
13903 		}
13904 
13905 		/* Save the value */
13906 		bf_cfg.bf_action = bf_action;
13907 		if (MLAN_STATUS_SUCCESS !=
13908 		    woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
13909 			ret = -EFAULT;
13910 			goto done;
13911 		}
13912 	} else {
13913 		ret = -EINVAL;
13914 		goto done;
13915 	}
13916 
13917 	switch (bf_action) {
13918 	case BF_GLOBAL_CONFIGURATION:
13919 		moal_memcpy_ext(priv->phandle, respbuf, bf_global,
13920 				sizeof(mlan_bf_global_cfg_args), respbuflen);
13921 		ret = sizeof(mlan_bf_global_cfg_args);
13922 		break;
13923 	case TRIGGER_SOUNDING_FOR_PEER:
13924 		moal_memcpy_ext(priv->phandle, respbuf, bf_sound,
13925 				sizeof(mlan_bf_global_cfg_args), respbuflen);
13926 		ret = sizeof(mlan_bf_global_cfg_args);
13927 		break;
13928 	case SET_GET_BF_PERIODICITY:
13929 		moal_memcpy_ext(priv->phandle, respbuf, bf_periodicity,
13930 				sizeof(mlan_bf_periodicity_args), respbuflen);
13931 		ret = sizeof(mlan_bf_periodicity_args);
13932 		break;
13933 	case TX_BF_FOR_PEER_ENBL:
13934 		moal_memcpy_ext(priv->phandle, respbuf, tx_bf_peer,
13935 				sizeof(mlan_tx_bf_peer_args), respbuflen);
13936 		ret = sizeof(mlan_tx_bf_peer_args);
13937 		break;
13938 	case SET_SNR_THR_PEER:
13939 		moal_memcpy_ext(priv->phandle, respbuf, bf_snr,
13940 				sizeof(mlan_snr_thr_args), respbuflen);
13941 		ret = sizeof(mlan_snr_thr_args);
13942 		break;
13943 		/** Default case not required as bf_action value already
13944 		 * sanitized */
13945 	}
13946 
13947 done:
13948 	LEAVE();
13949 	return ret;
13950 }
13951 
13952 #ifdef SDIO
13953 /**
13954  * @brief               Cmd53 read/write register
13955  * @param priv          Pointer to moal_private structure
13956  * @param respbuf       Pointer to response buffer
13957  * @param resplen       Response buffer length
13958  *
13959  *  @return             Number of bytes written, negative for failure.
13960  */
woal_priv_cmd53rdwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13961 static int woal_priv_cmd53rdwr(moal_private *priv, t_u8 *respbuf,
13962 			       t_u32 respbuflen)
13963 {
13964 	int header_len = 0;
13965 	int ret = 0;
13966 	t_u8 *buf = NULL;
13967 	t_u8 *data = NULL;
13968 	t_u8 rw, mode;
13969 	t_u16 blklen = 0, blknum = 0;
13970 	int reg = 0;
13971 	t_u32 pattern_len = 0, total_len = 0;
13972 	t_u16 cmd_len;
13973 	gfp_t flag;
13974 
13975 	ENTER();
13976 
13977 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SD_CMD53_RW);
13978 
13979 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
13980 	data = kzalloc(WOAL_2K_BYTES, flag);
13981 	if (!data) {
13982 		PRINTM(MERROR, "Cannot allocate buffer for command!\n");
13983 		ret = -EFAULT;
13984 		goto done;
13985 	}
13986 	moal_memcpy_ext(priv->phandle, &cmd_len, respbuf + header_len,
13987 			sizeof(cmd_len), sizeof(cmd_len));
13988 	buf = respbuf + header_len + sizeof(cmd_len);
13989 
13990 	rw = buf[0]; /* read/write (0/1) */
13991 	reg = buf[5]; /* address */
13992 	reg = (reg << 8) | buf[4];
13993 	reg = (reg << 8) | buf[3];
13994 	reg = (reg << 8) | buf[2];
13995 	mode = buf[6]; /* byte mode/block mode (0/1) */
13996 	blklen = buf[8]; /* block size */
13997 	blklen = (blklen << 8) | buf[7];
13998 	blknum = buf[10]; /* block number or byte number */
13999 	blknum = (blknum << 8) | buf[9];
14000 
14001 	if (mode == BYTE_MODE)
14002 		blklen = 1;
14003 	else
14004 		mode = BLOCK_MODE;
14005 
14006 	total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
14007 	if (total_len > WOAL_2K_BYTES) {
14008 		PRINTM(MERROR, "Total data length is too large!\n");
14009 		ret = -EINVAL;
14010 		goto done;
14011 	}
14012 	PRINTM(MINFO,
14013 	       "CMD53 read/write, addr = %#x, mode = %d, "
14014 	       "block size = %d, block(byte) number = %d\n",
14015 	       reg, mode, blklen, blknum);
14016 
14017 	if (!rw) {
14018 		sdio_claim_host(
14019 			((struct sdio_mmc_card *)priv->phandle->card)->func);
14020 		if (sdio_readsb(
14021 			    ((struct sdio_mmc_card *)priv->phandle->card)->func,
14022 			    respbuf, reg, total_len)) {
14023 			PRINTM(MERROR,
14024 			       "sdio_readsb: reading memory 0x%x failed\n",
14025 			       reg);
14026 			goto done;
14027 		}
14028 		sdio_release_host(
14029 			((struct sdio_mmc_card *)priv->phandle->card)->func);
14030 		ret = total_len;
14031 	} else {
14032 		int pos = 0;
14033 		pattern_len = cmd_len - 11;
14034 		if (pattern_len > total_len)
14035 			pattern_len = total_len;
14036 
14037 		/* Copy/duplicate the pattern to data buffer */
14038 		for (pos = 0; pos < (int)total_len; pos++)
14039 			data[pos] = buf[11 + (pos % pattern_len)];
14040 		sdio_claim_host(
14041 			((struct sdio_mmc_card *)priv->phandle->card)->func);
14042 		if (sdio_writesb(
14043 			    ((struct sdio_mmc_card *)priv->phandle->card)->func,
14044 			    reg, data, total_len))
14045 			PRINTM(MERROR,
14046 			       "sdio_writesb: writing memory 0x%x failed\n",
14047 			       reg);
14048 		sdio_release_host(
14049 			((struct sdio_mmc_card *)priv->phandle->card)->func);
14050 	}
14051 
14052 done:
14053 	kfree(data);
14054 	LEAVE();
14055 	return ret;
14056 }
14057 #endif /* SDIO */
14058 
14059 /**
14060  * @brief               Set/Get Port Control mode
14061  * @param priv          Pointer to moal_private structure
14062  * @param respbuf       Pointer to response buffer
14063  * @param resplen       Response buffer length
14064  *
14065  *  @return             Number of bytes written, negative for failure.
14066  */
woal_priv_port_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14067 static int woal_priv_port_ctrl(moal_private *priv, t_u8 *respbuf,
14068 			       t_u32 respbuflen)
14069 {
14070 	int header_len = 0, user_data_len = 0;
14071 	mlan_ioctl_req *req = NULL;
14072 	mlan_ds_sec_cfg *sec = NULL;
14073 	int ret = 0, data = 0;
14074 	mlan_status status = MLAN_STATUS_SUCCESS;
14075 	ENTER();
14076 
14077 	/* Allocate an IOCTL request buffer */
14078 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
14079 	if (req == NULL) {
14080 		ret = -ENOMEM;
14081 		goto done;
14082 	}
14083 
14084 	/* Fill request buffer */
14085 	sec = (mlan_ds_sec_cfg *)req->pbuf;
14086 	sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
14087 	req->req_id = MLAN_IOCTL_SEC_CFG;
14088 
14089 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PORT_CTRL);
14090 	if ((int)strlen(respbuf) == header_len) {
14091 		/* GET operation */
14092 		user_data_len = 0;
14093 		req->action = MLAN_ACT_GET;
14094 	} else {
14095 		/* SET operation */
14096 		parse_arguments(respbuf + header_len, &data,
14097 				sizeof(data) / sizeof(int), &user_data_len);
14098 		if (user_data_len == 1) {
14099 			sec->param.port_ctrl_enabled = data;
14100 			req->action = MLAN_ACT_SET;
14101 		} else {
14102 			PRINTM(MERROR, "Invalid number of parameters\n");
14103 			ret = -EINVAL;
14104 			goto done;
14105 		}
14106 	}
14107 
14108 	/* Send IOCTL request to MLAN */
14109 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14110 	if (status != MLAN_STATUS_SUCCESS) {
14111 		ret = -EFAULT;
14112 		goto done;
14113 	}
14114 
14115 	if (!user_data_len) {
14116 		moal_memcpy_ext(priv->phandle, respbuf,
14117 				&sec->param.port_ctrl_enabled, sizeof(int),
14118 				respbuflen);
14119 		ret = sizeof(int);
14120 	}
14121 
14122 done:
14123 	if (status != MLAN_STATUS_PENDING)
14124 		kfree(req);
14125 
14126 	LEAVE();
14127 	return ret;
14128 }
14129 
14130 /**
14131  * @brief               Private IOCTL entry to get the By-passed TX packet from
14132  * upper layer
14133  * @param priv          Pointer to moal_private structure
14134  * @param respbuf       Pointer to response buffer
14135  * @param resplen       Response buffer length
14136  *
14137  *  @return             Number of bytes written, negative for failure.
14138  */
woal_priv_bypassed_packet(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14139 static int woal_priv_bypassed_packet(moal_private *priv, t_u8 *respbuf,
14140 				     t_u32 respbuflen)
14141 {
14142 	int header_len = 0;
14143 	int ret = 0;
14144 	struct sk_buff *skb = NULL;
14145 	struct ethhdr *eth;
14146 	t_u16 moreLen = 0, copyLen = 0;
14147 	ENTER();
14148 
14149 #define MLAN_BYPASS_PKT_EXTRA_OFFSET (4)
14150 
14151 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PB_BYPASS);
14152 	copyLen = strlen(respbuf) - header_len;
14153 	moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET +
14154 		  sizeof(mlan_buffer);
14155 
14156 	skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
14157 	if (skb == NULL) {
14158 		PRINTM(MERROR, "kmalloc no memory !!\n");
14159 		LEAVE();
14160 		return -ENOMEM;
14161 	}
14162 
14163 	skb_reserve(skb, moreLen);
14164 
14165 	moal_memcpy_ext(priv->phandle, skb_put(skb, copyLen),
14166 			respbuf + header_len, copyLen, copyLen);
14167 
14168 	eth = (struct ethhdr *)skb->data;
14169 	eth->h_proto = __constant_htons(eth->h_proto);
14170 	skb->dev = priv->netdev;
14171 
14172 	HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));
14173 
14174 	woal_hard_start_xmit(skb, priv->netdev);
14175 
14176 	LEAVE();
14177 	return ret;
14178 }
14179 
14180 /**
14181  * @brief               Set Robustcoex gpiocfg
14182  * @param priv          Pointer to moal_private structure
14183  * @param respbuf       Pointer to response buffer
14184  * @param resplen       Response buffer length
14185  *
14186  *  @return             Number of bytes written, negative for failure.
14187  */
woal_priv_robustcoex(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14188 static int woal_priv_robustcoex(moal_private *priv, t_u8 *respbuf,
14189 				t_u32 respbuflen)
14190 {
14191 	int header_len = 0, user_data_len = 0;
14192 	int ret = 0, data[3] = {0};
14193 	mlan_ds_misc_cfg *robust_coex_cfg = NULL;
14194 	mlan_ioctl_req *req = NULL;
14195 	mlan_status status = MLAN_STATUS_SUCCESS;
14196 
14197 	ENTER();
14198 
14199 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14200 	if (req == NULL) {
14201 		ret = -ENOMEM;
14202 		goto done;
14203 	}
14204 	robust_coex_cfg = (mlan_ds_misc_cfg *)req->pbuf;
14205 	while (respbuf[0] == ' ') {
14206 		/** skip space */
14207 		respbuf++;
14208 	}
14209 
14210 	if (strncmp(respbuf, "gpiocfg", strlen("gpiocfg")) == 0) {
14211 		header_len = strlen("gpiocfg") + 1;
14212 		parse_arguments(respbuf + header_len, data,
14213 				sizeof(data) / sizeof(int), &user_data_len);
14214 		if (user_data_len > 3) {
14215 			PRINTM(MERROR, "Invalid parameter number\n");
14216 			ret = -EINVAL;
14217 			goto done;
14218 		}
14219 		if (data[0] != ROBUSTCOEX_GPIOCFG_ENABLE &&
14220 		    data[0] != ROBUSTCOEX_GPIOCFG_DISABLE) {
14221 			PRINTM(MERROR, "Invalid parameter number\n");
14222 			ret = -EINVAL;
14223 			goto done;
14224 		}
14225 		if (data[0] == ROBUSTCOEX_GPIOCFG_ENABLE) {
14226 			if (user_data_len != 3) {
14227 				PRINTM(MMSG,
14228 				       "Please provide gpio num and gpio polarity for ROBUSTCOEX_GPIOCFG_ENABLE\n");
14229 				ret = -EINVAL;
14230 				goto done;
14231 			}
14232 			robust_coex_cfg->param.robustcoexparams.method =
14233 				ROBUSTCOEX_GPIO_CFG;
14234 			robust_coex_cfg->param.robustcoexparams.enable =
14235 				ROBUSTCOEX_GPIOCFG_ENABLE;
14236 			robust_coex_cfg->param.robustcoexparams.gpio_num =
14237 				data[1];
14238 			robust_coex_cfg->param.robustcoexparams.gpio_polarity =
14239 				data[2];
14240 		} else {
14241 			robust_coex_cfg->param.robustcoexparams.method =
14242 				ROBUSTCOEX_GPIO_CFG;
14243 			robust_coex_cfg->param.robustcoexparams.enable =
14244 				ROBUSTCOEX_GPIOCFG_DISABLE;
14245 			robust_coex_cfg->param.robustcoexparams.gpio_num = 0;
14246 			robust_coex_cfg->param.robustcoexparams.gpio_polarity =
14247 				0;
14248 		}
14249 		req->action = MLAN_ACT_SET;
14250 		req->req_id = MLAN_IOCTL_MISC_CFG;
14251 		robust_coex_cfg->sub_command = MLAN_OID_MISC_ROBUSTCOEX;
14252 	} else {
14253 		PRINTM(MERROR, "Invalid parameter\n");
14254 		ret = -EFAULT;
14255 		goto done;
14256 	}
14257 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14258 	if (status != MLAN_STATUS_SUCCESS) {
14259 		ret = -EFAULT;
14260 		goto done;
14261 	}
14262 
14263 done:
14264 	if (status != MLAN_STATUS_PENDING)
14265 		kfree(req);
14266 	LEAVE();
14267 	return ret;
14268 }
14269 
14270 /**
14271  * @brief               Set DMCS mapping policy or get DMCS status
14272  * @param priv          Pointer to moal_private structure
14273  * @param respbuf       Pointer to response buffer
14274  * @param resplen       Response buffer length
14275  *
14276  *  @return             Number of bytes written, negative for failure.
14277  */
woal_priv_dmcs(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14278 static int woal_priv_dmcs(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
14279 {
14280 	int header_len = 0, user_data_len = 0;
14281 	int ret = 0, data[2] = {0};
14282 	mlan_ds_misc_cfg *dmcs_cfg = NULL;
14283 	mlan_ioctl_req *req = NULL;
14284 	mlan_status status = MLAN_STATUS_SUCCESS;
14285 
14286 	ENTER();
14287 
14288 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14289 	if (req == NULL) {
14290 		ret = -ENOMEM;
14291 		goto done;
14292 	}
14293 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DMCS);
14294 	dmcs_cfg = (mlan_ds_misc_cfg *)req->pbuf;
14295 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14296 			&user_data_len);
14297 	if (user_data_len > 2) {
14298 		PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
14299 		ret = -EINVAL;
14300 		goto done;
14301 	}
14302 	req->req_id = MLAN_IOCTL_MISC_CFG;
14303 	dmcs_cfg->sub_command = MLAN_OID_MISC_DMCS_CONFIG;
14304 	dmcs_cfg->param.dmcs_policy.subcmd = data[0];
14305 	switch (data[0]) {
14306 	case 0:
14307 		if (user_data_len != 2) {
14308 			PRINTM(MERROR, "Please provide mapping policy\n");
14309 			ret = -EINVAL;
14310 			goto done;
14311 		}
14312 		req->action = MLAN_ACT_SET;
14313 		dmcs_cfg->param.dmcs_policy.mapping_policy = data[1];
14314 		break;
14315 	case 1:
14316 		req->action = MLAN_ACT_GET;
14317 		break;
14318 	default:
14319 		break;
14320 	}
14321 
14322 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14323 	if (status != MLAN_STATUS_SUCCESS) {
14324 		ret = -EFAULT;
14325 		goto done;
14326 	}
14327 	if (req->action == MLAN_ACT_GET) {
14328 		moal_memcpy_ext(priv->phandle, respbuf,
14329 				&dmcs_cfg->param.dmcs_status,
14330 				sizeof(mlan_ds_misc_dmcs_status), respbuflen);
14331 	}
14332 	ret = sizeof(mlan_ds_misc_dmcs_status);
14333 done:
14334 	if (status != MLAN_STATUS_PENDING)
14335 		kfree(req);
14336 	LEAVE();
14337 	return ret;
14338 }
14339 
14340 /**
14341  * @brief               Set and get boot sleep configure
14342  * @param priv          Pointer to moal_private structure
14343  * @param respbuf       Pointer to response buffer
14344  * @param resplen       Response buffer length
14345  *
14346  *  @return             Number of bytes written, negative for failure.
14347  */
woal_priv_bootsleep(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14348 static int woal_priv_bootsleep(moal_private *priv, t_u8 *respbuf,
14349 			       t_u32 respbuflen)
14350 {
14351 	int ret = MLAN_STATUS_SUCCESS;
14352 	int user_data_len = 0;
14353 	int header_len = 0;
14354 	int allowed = 1;
14355 	int data[1] = {0};
14356 	mlan_ioctl_req *req = NULL;
14357 	mlan_ds_misc_cfg *misc = NULL;
14358 
14359 	ENTER();
14360 
14361 	if (!priv || !priv->phandle) {
14362 		PRINTM(MERROR, "priv or handle is null\n");
14363 		ret = -EFAULT;
14364 		goto done;
14365 	}
14366 
14367 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14368 	if (req == NULL) {
14369 		LEAVE();
14370 		return -ENOMEM;
14371 	}
14372 
14373 	misc = (mlan_ds_misc_cfg *)req->pbuf;
14374 	misc->sub_command = MLAN_OID_MISC_BOOT_SLEEP;
14375 	req->req_id = MLAN_IOCTL_MISC_CFG;
14376 
14377 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BOOTSLEEP);
14378 
14379 	if ((int)strlen(respbuf) == header_len) {
14380 		req->action = MLAN_ACT_GET;
14381 	} else {
14382 		req->action = MLAN_ACT_SET;
14383 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14384 				&user_data_len);
14385 		if (user_data_len != allowed) {
14386 			PRINTM(MERROR, "Invalid number of args! %d\n",
14387 			       user_data_len);
14388 			ret = -EINVAL;
14389 			goto done;
14390 		}
14391 		misc->param.boot_sleep = data[0] ? 1 : 0;
14392 		PRINTM(MIOCTL, "boot sleep cfg:%u\n", misc->param.boot_sleep);
14393 	}
14394 
14395 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT_TIMEOUT);
14396 	if (ret != MLAN_STATUS_SUCCESS) {
14397 		ret = -EFAULT;
14398 		goto done;
14399 	}
14400 
14401 	moal_memcpy_ext(priv->phandle, respbuf, &misc->param.boot_sleep,
14402 			sizeof(misc->param.boot_sleep), respbuflen);
14403 	ret = sizeof(misc->param.boot_sleep);
14404 
14405 	PRINTM(MIOCTL, "boot sleep cfg: %u\n", misc->param.boot_sleep);
14406 
14407 done:
14408 	if (ret != MLAN_STATUS_PENDING)
14409 		kfree(req);
14410 	LEAVE();
14411 	return ret;
14412 }
14413 
14414 /**
14415  *  * @brief               Set and get txwatchdog check
14416  *   * @param priv          Pointer to moal_private structure
14417  *    * @param respbuf       Pointer to response buffer
14418  *     * @param resplen       Response buffer length
14419  *      *
14420  *       *  @return             Number of bytes written, negative for failure.
14421  *        */
woal_priv_txwatchdog(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14422 static int woal_priv_txwatchdog(moal_private *priv, t_u8 *respbuf,
14423 				t_u32 respbuflen)
14424 {
14425 	int ret = 0;
14426 	int header_len = 0;
14427 	int user_data_len = 0;
14428 	int data[1] = {0};
14429 	int allowed = 1;
14430 	t_u32 action;
14431 
14432 	ENTER();
14433 
14434 	if (!priv || !priv->phandle) {
14435 		PRINTM(MERROR, "priv or handle is null\n");
14436 		ret = -EFAULT;
14437 		goto done;
14438 	}
14439 
14440 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXWATCHDOG);
14441 
14442 	if (strlen(respbuf) == header_len) {
14443 		action = MLAN_ACT_GET;
14444 		ret = sizeof(t_u32);
14445 	} else {
14446 		action = MLAN_ACT_SET;
14447 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14448 				&user_data_len);
14449 		if (user_data_len != allowed) {
14450 			PRINTM(MERROR, "Invalid number of args! %d\n",
14451 			       user_data_len);
14452 			ret = -EINVAL;
14453 			goto done;
14454 		}
14455 	}
14456 
14457 	if (action == MLAN_ACT_SET) {
14458 		priv->txwatchdog_disable = ((*data == 0) ? MTRUE : MFALSE);
14459 	} else {
14460 		*data = ((priv->txwatchdog_disable == MTRUE) ? 0 : 1);
14461 	}
14462 	memcpy(respbuf, data, sizeof(t_u32));
14463 	PRINTM(MINFO, "priv->txwatchdog_disable:%u, action:%u, data[0]=%d\n",
14464 	       priv->txwatchdog_disable, action, data[0]);
14465 
14466 done:
14467 	LEAVE();
14468 	return ret;
14469 }
14470 
14471 #if defined(PCIE)
14472 /**
14473  * @brief               Enable SSU support
14474  * @param priv          Pointer to moal_private structure
14475  * @param used_len 		used length
14476  * @param respbuf       Pointer to response buffer
14477  * @param resplen       Response buffer length
14478  *
14479  *  @return             Number of bytes written, negative for failure.
14480  */
woal_priv_ssu_cmd(moal_private * priv,t_u8 used_len,t_u8 * respbuf,t_u32 respbuflen)14481 static int woal_priv_ssu_cmd(moal_private *priv, t_u8 used_len, t_u8 *respbuf,
14482 			     t_u32 respbuflen)
14483 {
14484 	int ret = 0;
14485 	mlan_ds_misc_cfg *ssu_cfg = NULL;
14486 	mlan_ioctl_req *req = NULL;
14487 	ssu_params_cfg *ssu_params;
14488 	mlan_status status = MLAN_STATUS_SUCCESS;
14489 
14490 	ENTER();
14491 
14492 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14493 	if (req == NULL) {
14494 		ret = -ENOMEM;
14495 		goto done;
14496 	}
14497 	ssu_cfg = (mlan_ds_misc_cfg *)req->pbuf;
14498 	memset(&ssu_cfg->param.ssu_params, 0, sizeof(mlan_ds_ssu_params));
14499 	if (!used_len) {
14500 		req->action = MLAN_ACT_SET;
14501 		ssu_cfg->param.ssu_params.nskip = 0;
14502 		ssu_cfg->param.ssu_params.nsel = 1;
14503 		ssu_cfg->param.ssu_params.adcdownsample = 3;
14504 		ssu_cfg->param.ssu_params.mask_adc_pkt = 0;
14505 		ssu_cfg->param.ssu_params.out_16bits = 1;
14506 	} else {
14507 		ssu_params = (ssu_params_cfg *)respbuf;
14508 		DBG_HEXDUMP(MCMD_D, "User SSU params:", respbuf,
14509 			    sizeof(mlan_ds_ssu_params));
14510 		if (ssu_params->ssu_mode == 2)
14511 			req->action = MLAN_ACT_DEFAULT;
14512 		else {
14513 			req->action = MLAN_ACT_SET;
14514 			ssu_cfg->param.ssu_params.nskip = ssu_params->nskip;
14515 			ssu_cfg->param.ssu_params.nsel = ssu_params->nsel;
14516 			ssu_cfg->param.ssu_params.adcdownsample =
14517 				ssu_params->adcdownsample;
14518 			ssu_cfg->param.ssu_params.mask_adc_pkt =
14519 				ssu_params->mask_adc_pkt;
14520 			ssu_cfg->param.ssu_params.out_16bits =
14521 				ssu_params->out_16bits;
14522 			ssu_cfg->param.ssu_params.spec_pwr_enable =
14523 				ssu_params->spec_pwr_enable;
14524 			ssu_cfg->param.ssu_params.rate_deduction =
14525 				ssu_params->rate_deduction;
14526 			ssu_cfg->param.ssu_params.n_pkt_avg =
14527 				ssu_params->n_pkt_avg;
14528 		}
14529 	}
14530 	req->req_id = MLAN_IOCTL_MISC_CFG;
14531 	ssu_cfg->sub_command = MLAN_OID_MISC_SSU;
14532 
14533 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14534 	if (status != MLAN_STATUS_SUCCESS) {
14535 		ret = -EFAULT;
14536 		goto done;
14537 	}
14538 
14539 done:
14540 	if (status != MLAN_STATUS_PENDING)
14541 		kfree(req);
14542 	LEAVE();
14543 	return ret;
14544 }
14545 #endif
14546 
14547 /**
14548  * @brief               Configure the hal/phy cfg params
14549  *
14550  *  The command structure contains the following parameters
14551  *      dot11b_psd_mask: 1: enable, 0: disable
14552  *      Reserved : reserved 7 params for future such use
14553  *
14554  *  @param priv    Pointer to the mlan_private driver data struct
14555  *  @param respbuf      A pointer to response buffer
14556  *  @param respbuflen   Available length of response buffer
14557  *
14558  *  @return         Number of bytes written if successful else negative value
14559  */
woal_priv_hal_phy_cfg_cmd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14560 static int woal_priv_hal_phy_cfg_cmd(moal_private *priv, t_u8 *respbuf,
14561 				     t_u32 respbuflen)
14562 {
14563 	mlan_ioctl_req *req = NULL;
14564 	mlan_ds_misc_cfg *cfg = NULL;
14565 	int ret = 0;
14566 	mlan_ds_hal_phy_cfg_params *data_ptr;
14567 	mlan_status status = MLAN_STATUS_SUCCESS;
14568 
14569 	ENTER();
14570 
14571 	data_ptr = (mlan_ds_hal_phy_cfg_params *)respbuf;
14572 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14573 	if (req == NULL) {
14574 		ret = -ENOMEM;
14575 		goto done;
14576 	}
14577 
14578 	req->req_id = MLAN_IOCTL_MISC_CFG;
14579 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
14580 	cfg->sub_command = MLAN_OID_MISC_HAL_PHY_CFG;
14581 
14582 	cfg->param.hal_phy_cfg_params.dot11b_psd_mask_cfg =
14583 		data_ptr->dot11b_psd_mask_cfg;
14584 
14585 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14586 	if (status != MLAN_STATUS_SUCCESS) {
14587 		ret = -EFAULT;
14588 		goto done;
14589 	}
14590 
14591 done:
14592 	if (status != MLAN_STATUS_PENDING)
14593 		kfree(req);
14594 	LEAVE();
14595 	return ret;
14596 }
14597 
14598 /**
14599  * @brief               Enable/disable CSI support
14600  *
14601  *  The command structure contains the following parameters
14602  *      csi_enable: 1: enable, 0: diable
14603  *      csi_filter_cnt: Number of CSI filters
14604  *      csi_filter: CSI filters
14605  *
14606  *  @param priv    Pointer to the mlan_private driver data struct
14607  *  @param respbuf      A pointer to response buffer
14608  *  @param respbuflen   Available length of response buffer
14609  *
14610  *  @return         Number of bytes written if successful else negative value
14611  */
woal_priv_csi_cmd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14612 static int woal_priv_csi_cmd(moal_private *priv, t_u8 *respbuf,
14613 			     t_u32 respbuflen)
14614 {
14615 	mlan_ioctl_req *req = NULL;
14616 	mlan_ds_misc_cfg *cfg = NULL;
14617 	int ret = 0;
14618 	mlan_ds_csi_params *data_ptr;
14619 	mlan_status status = MLAN_STATUS_SUCCESS;
14620 
14621 	ENTER();
14622 
14623 	data_ptr = (mlan_ds_csi_params *)respbuf;
14624 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14625 	if (req == NULL) {
14626 		ret = -ENOMEM;
14627 		goto done;
14628 	}
14629 
14630 	req->req_id = MLAN_IOCTL_MISC_CFG;
14631 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
14632 	cfg->sub_command = MLAN_OID_MISC_CSI;
14633 
14634 	cfg->param.csi_params.csi_enable = data_ptr->csi_enable;
14635 	if (data_ptr->csi_enable == 1) {
14636 		cfg->param.csi_params.head_id = data_ptr->head_id;
14637 		cfg->param.csi_params.tail_id = data_ptr->tail_id;
14638 		cfg->param.csi_params.csi_filter_cnt = data_ptr->csi_filter_cnt;
14639 		cfg->param.csi_params.chip_id = data_ptr->chip_id;
14640 		if (cfg->param.csi_params.csi_filter_cnt > CSI_FILTER_MAX)
14641 			cfg->param.csi_params.csi_filter_cnt = CSI_FILTER_MAX;
14642 		moal_memcpy_ext(priv->phandle, cfg->param.csi_params.csi_filter,
14643 				data_ptr->csi_filter,
14644 				sizeof(mlan_csi_filter_t) *
14645 					cfg->param.csi_params.csi_filter_cnt,
14646 				sizeof(mlan_csi_filter_t) * CSI_FILTER_MAX);
14647 	}
14648 
14649 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14650 	if (status != MLAN_STATUS_SUCCESS) {
14651 		ret = -EFAULT;
14652 		goto done;
14653 	}
14654 
14655 done:
14656 	if (status != MLAN_STATUS_PENDING)
14657 		kfree(req);
14658 	LEAVE();
14659 	return ret;
14660 }
14661 
14662 /**
14663  * @brief               configure 11ax HE capability or HE operation
14664  *
14665  *
14666  *  @param priv    Pointer to the mlan_private driver data struct
14667  *  @param respbuf      A pointer to response buffer
14668  *  @param len          length used
14669  *  @param respbuflen   Available length of response buffer
14670  *
14671  *  @return         Number of bytes written if successful else negative value
14672  */
woal_priv_11axcfg_cmd(moal_private * priv,t_u8 * respbuf,t_u8 len,t_u32 respbuflen)14673 static int woal_priv_11axcfg_cmd(moal_private *priv, t_u8 *respbuf, t_u8 len,
14674 				 t_u32 respbuflen)
14675 {
14676 	mlan_ioctl_req *req = NULL;
14677 	mlan_ds_11ax_cfg *cfg = NULL;
14678 	int ret = 0;
14679 	mlan_status status = MLAN_STATUS_SUCCESS;
14680 
14681 	ENTER();
14682 
14683 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cfg));
14684 	if (req == NULL) {
14685 		ret = -ENOMEM;
14686 		goto done;
14687 	}
14688 
14689 	req->req_id = MLAN_IOCTL_11AX_CFG;
14690 	req->action = MLAN_ACT_SET;
14691 	cfg = (mlan_ds_11ax_cfg *)req->pbuf;
14692 	cfg->sub_command = MLAN_OID_11AX_HE_CFG;
14693 	if (len)
14694 		moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.he_cfg,
14695 				respbuf, len, sizeof(mlan_ds_11ax_he_cfg));
14696 	else
14697 		req->action = MLAN_ACT_GET;
14698 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14699 	if (status != MLAN_STATUS_SUCCESS) {
14700 		ret = -EFAULT;
14701 		goto done;
14702 	}
14703 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.he_cfg,
14704 			sizeof(mlan_ds_11ax_he_cfg), respbuflen);
14705 	ret = sizeof(mlan_ds_11ax_he_cfg);
14706 done:
14707 	if (status != MLAN_STATUS_PENDING)
14708 		kfree(req);
14709 	LEAVE();
14710 	return ret;
14711 }
14712 /**
14713  * @brief               Configure TWT Setup parameters
14714  *
14715  * @param priv          Pointer to the mlan_private driver data struct
14716  * @param respbuf       A pointer to response buffer
14717  * @param len           Length used
14718  * @param respbuflen    Available length of response buffer
14719  *
14720  * @return              Number of bytes written if successful else negative
14721  * value
14722  */
woal_priv_twt_setup(moal_private * priv,t_u8 * respbuf,t_u8 len,t_u32 respbuflen)14723 static int woal_priv_twt_setup(moal_private *priv, t_u8 *respbuf, t_u8 len,
14724 			       t_u32 respbuflen)
14725 {
14726 	mlan_ioctl_req *req = NULL;
14727 	mlan_ds_twtcfg *cfg = NULL;
14728 	int ret = 0;
14729 	mlan_status status = MLAN_STATUS_SUCCESS;
14730 
14731 	ENTER();
14732 
14733 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
14734 	if (req == NULL) {
14735 		PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
14736 		ret = -ENOMEM;
14737 		goto done;
14738 	}
14739 
14740 	req->req_id = MLAN_IOCTL_11AX_CFG;
14741 	req->action = MLAN_ACT_SET;
14742 	cfg = (mlan_ds_twtcfg *)req->pbuf;
14743 	cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
14744 	cfg->sub_id = MLAN_11AX_TWT_SETUP_SUBID;
14745 
14746 	if (len) {
14747 		moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_setup,
14748 				respbuf, len, sizeof(mlan_ds_twt_setup));
14749 	}
14750 
14751 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14752 	if (status != MLAN_STATUS_SUCCESS) {
14753 		PRINTM(MERROR, "woal_request_ioctl failed!\n");
14754 		ret = -EFAULT;
14755 		goto done;
14756 	}
14757 
14758 	ret = sizeof(mlan_ds_twt_setup);
14759 done:
14760 	if (status != MLAN_STATUS_PENDING) {
14761 		kfree(req);
14762 	}
14763 	LEAVE();
14764 	return ret;
14765 }
14766 
14767 /**
14768  * @brief               Configure TWT Tear down parameters
14769  *
14770  * @param priv          Pointer to the mlan_private driver data struct
14771  * @param respbuf       A pointer to response buffer
14772  * @param len           Length used
14773  * @param respbuflen    Available length of response buffer
14774  *
14775  * @return              Number of bytes written if successful else negative
14776  * value
14777  */
woal_priv_twt_teardown(moal_private * priv,t_u8 * respbuf,t_u8 len,t_u32 respbuflen)14778 static int woal_priv_twt_teardown(moal_private *priv, t_u8 *respbuf, t_u8 len,
14779 				  t_u32 respbuflen)
14780 {
14781 	mlan_ioctl_req *req = NULL;
14782 	mlan_ds_twtcfg *cfg = NULL;
14783 	int ret = 0;
14784 	mlan_status status = MLAN_STATUS_SUCCESS;
14785 
14786 	ENTER();
14787 
14788 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
14789 	if (req == NULL) {
14790 		PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
14791 		ret = -ENOMEM;
14792 		goto done;
14793 	}
14794 
14795 	req->req_id = MLAN_IOCTL_11AX_CFG;
14796 	req->action = MLAN_ACT_SET;
14797 	cfg = (mlan_ds_twtcfg *)req->pbuf;
14798 	cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
14799 	cfg->sub_id = MLAN_11AX_TWT_TEARDOWN_SUBID;
14800 
14801 	if (len) {
14802 		moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_teardown,
14803 				respbuf, len, sizeof(mlan_ds_twt_teardown));
14804 	}
14805 
14806 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14807 	if (status != MLAN_STATUS_SUCCESS) {
14808 		PRINTM(MERROR, "woal_request_ioctl failed!\n");
14809 		ret = -EFAULT;
14810 		goto done;
14811 	}
14812 
14813 	ret = sizeof(mlan_ds_twt_teardown);
14814 done:
14815 	if (status != MLAN_STATUS_PENDING) {
14816 		kfree(req);
14817 	}
14818 	LEAVE();
14819 	return ret;
14820 }
14821 
14822 #ifdef WIFI_DIRECT_SUPPORT
14823 #if defined(UAP_CFG80211)
14824 /**
14825  * @brief               Set/Get P2P NoA (Notice of Absence) parameters
14826  * @param priv          Pointer to moal_private structure
14827  * @param respbuf       Pointer to response buffer
14828  * @param resplen       Response buffer length
14829  *
14830  *  @return             Number of bytes written, negative for failure.
14831  */
woal_priv_cfg_noa(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14832 static int woal_priv_cfg_noa(moal_private *priv, t_u8 *respbuf,
14833 			     t_u32 respbuflen)
14834 {
14835 	int header_len = 0, user_data_len = 0;
14836 	int ret = 0, data[7];
14837 	mlan_ds_wifi_direct_config noa_cfg;
14838 
14839 	ENTER();
14840 
14841 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_NOA);
14842 	memset(&noa_cfg, 0, sizeof(noa_cfg));
14843 
14844 	memset(data, 0, sizeof(data));
14845 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14846 			&user_data_len);
14847 
14848 	if (user_data_len > 5) {
14849 		PRINTM(MERROR, "invalid parameters\n");
14850 		ret = -EINVAL;
14851 		goto done;
14852 	}
14853 
14854 	noa_cfg.flags |= WIFI_DIRECT_NOA;
14855 
14856 	if (woal_p2p_config(priv, MLAN_ACT_GET, &noa_cfg) !=
14857 	    MLAN_STATUS_SUCCESS) {
14858 		PRINTM(MERROR, "Could not get P2P noa config\n");
14859 		ret = -EINVAL;
14860 		goto done;
14861 	}
14862 
14863 	if ((int)strlen(respbuf) == header_len) {
14864 		/* GET operation */
14865 		moal_memcpy_ext(priv->phandle, respbuf, &noa_cfg,
14866 				sizeof(noa_cfg), respbuflen);
14867 		ret = sizeof(noa_cfg);
14868 	} else {
14869 		switch (user_data_len) {
14870 		case 5:
14871 			noa_cfg.noa_interval = (t_u32)data[4];
14872 			/* fall through */
14873 		case 4:
14874 			noa_cfg.noa_duration = (t_u32)data[3];
14875 			/* fall through */
14876 		case 3:
14877 			if (data[2] < 1 || data[2] > 255) {
14878 				PRINTM(MERROR,
14879 				       "Invalid number of absence intervals\n");
14880 				ret = -EINVAL;
14881 				goto done;
14882 			}
14883 			noa_cfg.noa_count = (t_u8)data[2];
14884 			/* fall through */
14885 		case 2:
14886 			if (data[1] < 0 || data[1] > 255) {
14887 				PRINTM(MERROR, "Invalid Index\n");
14888 				ret = -EINVAL;
14889 				goto done;
14890 			}
14891 			noa_cfg.index = (t_u16)data[1];
14892 			/* fall through */
14893 		case 1:
14894 			if (data[0] < 0 || data[0] > 1) {
14895 				PRINTM(MERROR, "Invalid noa enable\n");
14896 				ret = -EINVAL;
14897 				goto done;
14898 			}
14899 			noa_cfg.noa_enable = (t_u8)data[0];
14900 			noa_cfg.flags |= WIFI_DIRECT_NOA;
14901 			break;
14902 		default:
14903 			break;
14904 		}
14905 		if (woal_p2p_config(priv, MLAN_ACT_SET, &noa_cfg) !=
14906 		    MLAN_STATUS_SUCCESS) {
14907 			PRINTM(MERROR, "woal_p2p_config fail\n");
14908 			ret = -EFAULT;
14909 		}
14910 	}
14911 
14912 done:
14913 
14914 	LEAVE();
14915 	return ret;
14916 }
14917 
14918 /**
14919  * @brief               Set/Get P2P OPP-PS parameters
14920  * @param priv          Pointer to moal_private structure
14921  * @param respbuf       Pointer to response buffer
14922  * @param resplen       Response buffer length
14923  *
14924  *  @return             Number of bytes written, negative for failure.
14925  */
woal_priv_cfg_opp_ps(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14926 static int woal_priv_cfg_opp_ps(moal_private *priv, t_u8 *respbuf,
14927 				t_u32 respbuflen)
14928 {
14929 	int header_len = 0, user_data_len = 0;
14930 	int ret = 0, data[7];
14931 	mlan_ds_wifi_direct_config opp_ps_cfg;
14932 
14933 	ENTER();
14934 
14935 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_OPP_PS);
14936 	memset(&opp_ps_cfg, 0, sizeof(opp_ps_cfg));
14937 
14938 	memset(data, 0, sizeof(data));
14939 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14940 			&user_data_len);
14941 
14942 	if (user_data_len > 2) {
14943 		PRINTM(MERROR, "invalid parameters\n");
14944 		ret = -EINVAL;
14945 		goto done;
14946 	}
14947 
14948 	opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;
14949 
14950 	if (woal_p2p_config(priv, MLAN_ACT_GET, &opp_ps_cfg) !=
14951 	    MLAN_STATUS_SUCCESS) {
14952 		PRINTM(MERROR, "Could not get P2P opp ps config\n");
14953 		ret = -EINVAL;
14954 		goto done;
14955 	}
14956 
14957 	if ((int)strlen(respbuf) == header_len) {
14958 		/* GET operation */
14959 		moal_memcpy_ext(priv->phandle, respbuf, &opp_ps_cfg,
14960 				sizeof(opp_ps_cfg), respbuflen);
14961 		ret = sizeof(opp_ps_cfg);
14962 	} else {
14963 		switch (user_data_len) {
14964 		case 2:
14965 			opp_ps_cfg.ct_window = (t_u8)data[1];
14966 			/* fall through */
14967 		case 1:
14968 			if (data[0] < 0 || data[0] > 1) {
14969 				PRINTM(MERROR, "Invalid ps enable\n");
14970 				ret = -EINVAL;
14971 				goto done;
14972 			}
14973 			opp_ps_cfg.opp_ps_enable = (t_u8)data[0];
14974 			opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;
14975 			/* fall through */
14976 		default:
14977 			break;
14978 		}
14979 		if (woal_p2p_config(priv, MLAN_ACT_SET, &opp_ps_cfg) !=
14980 		    MLAN_STATUS_SUCCESS) {
14981 			PRINTM(MERROR, "woal_p2p_config fail\n");
14982 			ret = -EINVAL;
14983 		}
14984 	}
14985 
14986 done:
14987 	LEAVE();
14988 	return ret;
14989 }
14990 #endif
14991 #endif
14992 
14993 /**
14994  * @brief               Set/Get GPIO TSF latch clock sync config parameters
14995  * @param priv          Pointer to moal_private structure
14996  * @param respbuf       Pointer to response buffer
14997  * @param resplen       Response buffer length
14998  *
14999  *  @return             Number of bytes written, negative for failure.
15000  */
woal_priv_cfg_clock_sync(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15001 static int woal_priv_cfg_clock_sync(moal_private *priv, t_u8 *respbuf,
15002 				    t_u32 respbuflen)
15003 {
15004 	int header_len = 0, user_data_len = 0;
15005 	int ret = 0, data[5];
15006 	mlan_ds_gpio_tsf_latch *clock_sync_cfg = NULL;
15007 	mlan_ioctl_req *req = NULL;
15008 	mlan_ds_misc_cfg *misc_cfg = NULL;
15009 	mlan_status status = MLAN_STATUS_SUCCESS;
15010 
15011 	ENTER();
15012 
15013 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_CLOCK_SYNC);
15014 
15015 	memset(data, 0, sizeof(data));
15016 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15017 			&user_data_len);
15018 
15019 	if (user_data_len > 5) {
15020 		PRINTM(MERROR, "invalid parameters\n");
15021 		ret = -EINVAL;
15022 		goto done;
15023 	}
15024 
15025 	/* Allocate an IOCTL request buffer */
15026 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15027 	if (req == NULL) {
15028 		ret = -ENOMEM;
15029 		goto done;
15030 	}
15031 
15032 	/* Fill request buffer */
15033 	req->req_id = MLAN_IOCTL_MISC_CFG;
15034 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
15035 	misc_cfg->sub_command = MLAN_OID_MISC_GPIO_TSF_LATCH;
15036 	clock_sync_cfg = &misc_cfg->param.gpio_tsf_latch_config;
15037 	memset(clock_sync_cfg, 0, sizeof(mlan_ds_gpio_tsf_latch));
15038 
15039 	if ((int)strlen(respbuf) == header_len) {
15040 		/* GET operation */
15041 		req->action = MLAN_ACT_GET;
15042 		user_data_len = 0;
15043 	} else {
15044 		req->action = MLAN_ACT_SET;
15045 		switch (user_data_len) {
15046 		case 5:
15047 			clock_sync_cfg->clock_sync_gpio_pulse_width =
15048 				(t_u16)data[4];
15049 			/* fall through */
15050 		case 4:
15051 			if (data[3] < 0 || data[3] > 1) {
15052 				PRINTM(MERROR, "Invalid Level/Trigger\n");
15053 				ret = -EINVAL;
15054 				goto done;
15055 			}
15056 			clock_sync_cfg->clock_sync_gpio_level_toggle =
15057 				(t_u8)data[3];
15058 			/* fall through */
15059 		case 3:
15060 			if (data[2] < 1 || data[2] > 255) {
15061 				PRINTM(MERROR,
15062 				       "Invalid number of GPIO Pin Number\n");
15063 				ret = -EINVAL;
15064 				goto done;
15065 			}
15066 			clock_sync_cfg->clock_sync_gpio_pin_number =
15067 				(t_u8)data[2];
15068 			/* fall through */
15069 		case 2:
15070 			if (data[1] < 0 || data[1] > 2) {
15071 				PRINTM(MERROR, "Invalid Role\n");
15072 				ret = -EINVAL;
15073 				goto done;
15074 			}
15075 			clock_sync_cfg->clock_sync_Role = (t_u8)data[1];
15076 			/* fall through */
15077 		case 1:
15078 			if (data[0] < 0 || data[0] > 2) {
15079 				PRINTM(MERROR, "Invalid Mode\n");
15080 				ret = -EINVAL;
15081 				goto done;
15082 			}
15083 			clock_sync_cfg->clock_sync_mode = (t_u8)data[0];
15084 			break;
15085 		default:
15086 			break;
15087 		}
15088 	}
15089 	/* Send IOCTL request to MLAN */
15090 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15091 	if (status != MLAN_STATUS_SUCCESS) {
15092 		ret = -EFAULT;
15093 		goto done;
15094 	}
15095 
15096 	if (!user_data_len) {
15097 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)clock_sync_cfg,
15098 				sizeof(mlan_ds_gpio_tsf_latch), respbuflen);
15099 		ret = sizeof(mlan_ds_gpio_tsf_latch);
15100 	}
15101 
15102 done:
15103 	if (status != MLAN_STATUS_PENDING)
15104 		kfree(req);
15105 
15106 	LEAVE();
15107 	return ret;
15108 }
15109 
15110 /**
15111  * @brief               Set/Get GPIO TSF latch get tsf info config parameters
15112  * @param priv          Pointer to moal_private structure
15113  * @param respbuf       Pointer to response buffer
15114  * @param resplen       Response buffer length
15115  *
15116  *  @return             Number of bytes written, negative for failure.
15117  */
woal_priv_cfg_get_tsf_info(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15118 static int woal_priv_cfg_get_tsf_info(moal_private *priv, t_u8 *respbuf,
15119 				      t_u32 respbuflen)
15120 {
15121 	int header_len = 0, user_data_len = 0;
15122 	int ret = 0, data[1];
15123 	mlan_ds_tsf_info *tsf_info;
15124 	mlan_ioctl_req *req = NULL;
15125 	mlan_ds_misc_cfg *misc_cfg = NULL;
15126 	mlan_status status = MLAN_STATUS_SUCCESS;
15127 
15128 	ENTER();
15129 
15130 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_GET_TSF_INFO);
15131 
15132 	memset(data, 0, sizeof(data));
15133 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15134 			&user_data_len);
15135 
15136 	if (user_data_len > 1) {
15137 		PRINTM(MERROR, "invalid parameters\n");
15138 		ret = -EINVAL;
15139 		goto done;
15140 	}
15141 	/* Allocate an IOCTL request buffer */
15142 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15143 	if (req == NULL) {
15144 		ret = -ENOMEM;
15145 		goto done;
15146 	}
15147 
15148 	/* Fill request buffer */
15149 	req->req_id = MLAN_IOCTL_MISC_CFG;
15150 	req->action = MLAN_ACT_GET;
15151 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
15152 	misc_cfg->sub_command = MLAN_OID_MISC_GET_TSF_INFO;
15153 	tsf_info = &misc_cfg->param.tsf_info;
15154 	memset(tsf_info, 0, sizeof(mlan_ds_tsf_info));
15155 	if (user_data_len == 1) {
15156 		if (data[0] < 0 || data[0] > 1) {
15157 			PRINTM(MERROR, "Invalid tsf Format\n");
15158 			ret = -EINVAL;
15159 			goto done;
15160 		}
15161 		tsf_info->tsf_format = data[0];
15162 	}
15163 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15164 	if (status != MLAN_STATUS_SUCCESS) {
15165 		ret = -EFAULT;
15166 		goto done;
15167 	}
15168 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)tsf_info,
15169 			sizeof(mlan_ds_tsf_info), respbuflen);
15170 	ret = sizeof(mlan_ds_tsf_info);
15171 done:
15172 	if (status != MLAN_STATUS_PENDING)
15173 		kfree(req);
15174 
15175 	LEAVE();
15176 	return ret;
15177 }
15178 
15179 #ifdef UAP_SUPPORT
15180 /**
15181  * @brief               Set/Get target channel
15182  * @param priv          Pointer to moal_private structure
15183  * @param respbuf       Pointer to response buffer
15184  * @param resplen       Response buffer length
15185  *
15186  *  @return             Number of bytes written, negative for failure.
15187  */
woal_priv_target_channel(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15188 static int woal_priv_target_channel(moal_private *priv, t_u8 *respbuf,
15189 				    t_u32 respbuflen)
15190 {
15191 	int header_len = 0, user_data_len = 0;
15192 	int ret = 0, data[1];
15193 
15194 	ENTER();
15195 	if (!priv || (priv->bss_type != MLAN_BSS_TYPE_UAP)) {
15196 		PRINTM(MERROR, "priv is null or interface is not AP");
15197 		ret = -EFAULT;
15198 		LEAVE();
15199 		return ret;
15200 	}
15201 
15202 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TARGET_CHANNEL);
15203 	if ((int)strlen(respbuf) == header_len) {
15204 		/* GET operation */
15205 		user_data_len = 0;
15206 	} else {
15207 		/* SET operation */
15208 		parse_arguments(respbuf + header_len, data,
15209 				sizeof(data) / sizeof(int), &user_data_len);
15210 		if (user_data_len > 1) {
15211 			PRINTM(MERROR, "Invalid parameter number\n");
15212 			ret = -EINVAL;
15213 			goto done;
15214 		}
15215 		if (user_data_len)
15216 			priv->target_chan = data[0];
15217 	}
15218 	data[0] = priv->target_chan;
15219 	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
15220 			respbuflen);
15221 	ret = sizeof(int);
15222 done:
15223 
15224 	LEAVE();
15225 	return ret;
15226 }
15227 
15228 /**
15229  * @brief               Set/Get backup channel
15230  * @param priv          Pointer to moal_private structure
15231  * @param respbuf       Pointer to response buffer
15232  * @param resplen       Response buffer length
15233  *
15234  *  @return             Number of bytes written, negative for failure.
15235  */
woal_priv_backup_channel(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15236 static int woal_priv_backup_channel(moal_private *priv, t_u8 *respbuf,
15237 				    t_u32 respbuflen)
15238 {
15239 	int header_len = 0, user_data_len = 0;
15240 	int ret = 0, data[1];
15241 
15242 	ENTER();
15243 	if (!priv || (priv->bss_type != MLAN_BSS_TYPE_UAP)) {
15244 		PRINTM(MERROR, "priv is null or interface is not AP");
15245 		ret = -EFAULT;
15246 		LEAVE();
15247 		return ret;
15248 	}
15249 
15250 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BACKUP_CHANNEL);
15251 	if ((int)strlen(respbuf) == header_len) {
15252 		/* GET operation */
15253 		user_data_len = 0;
15254 	} else {
15255 		/* SET operation */
15256 		parse_arguments(respbuf + header_len, data,
15257 				sizeof(data) / sizeof(int), &user_data_len);
15258 		if (user_data_len > 1) {
15259 			PRINTM(MERROR, "Invalid parameter number\n");
15260 			ret = -EINVAL;
15261 			goto done;
15262 		}
15263 		if (user_data_len)
15264 			priv->backup_chan = data[0];
15265 	}
15266 	data[0] = priv->backup_chan;
15267 	moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
15268 			respbuflen);
15269 	ret = sizeof(int);
15270 done:
15271 
15272 	LEAVE();
15273 	return ret;
15274 }
15275 #endif
15276 
15277 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
15278 #ifdef WIFI_DIRECT_SUPPORT
15279 #define DEF_NOA_INTERVAL 100
15280 /**
15281  ** @brief               Set/Get P2P NoA (Notice of Absence) parameters
15282  ** @param priv          Pointer to moal_private structure
15283  ** @param respbuf       Pointer to response buffer
15284  ** @param resplen       Response buffer length
15285  **
15286  **  @return             Number of bytes written, negative for failure.
15287  **/
woal_p2p_ps_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15288 static int woal_p2p_ps_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
15289 {
15290 	int user_data_len = 0;
15291 	int ret = 0, data[2];
15292 	u32 duration = priv->phandle->noa_duration;
15293 	u32 interval = 0;
15294 
15295 	ENTER();
15296 	if (strlen(respbuf) > strlen("P2P_PERIODIC_SLEEP")) {
15297 		memset((char *)data, 0, sizeof(data));
15298 		parse_arguments(respbuf + strlen("P2P_PERIODIC_SLEEP") + 1,
15299 				data, ARRAY_SIZE(data), &user_data_len);
15300 	}
15301 	if ((user_data_len != 1) && (user_data_len != 2)) {
15302 		PRINTM(MERROR,
15303 		       " Invalid parameter number for P2P_PERIODIC_SLEEP");
15304 		ret = -EINVAL;
15305 		goto done;
15306 	}
15307 	if (data[0] < DEF_NOA_INTERVAL)
15308 		interval = DEF_NOA_INTERVAL;
15309 	else
15310 		interval = (data[0] + DEF_NOA_INTERVAL - 1) / DEF_NOA_INTERVAL *
15311 			   DEF_NOA_INTERVAL;
15312 
15313 	if (user_data_len == 2)
15314 		duration = data[1];
15315 	if (duration >= interval) {
15316 		PRINTM(MERROR,
15317 		       " Invalid noa duration/interval! duration=%d interval=%d\n",
15318 		       duration, interval);
15319 		ret = -EINVAL;
15320 		goto done;
15321 	}
15322 	priv->phandle->noa_interval = interval;
15323 	priv->phandle->noa_duration = duration;
15324 	PRINTM(MIOCTL, "configure noa interval=%d, duration=%d\n",
15325 	       priv->phandle->noa_interval, priv->phandle->noa_duration);
15326 done:
15327 	LEAVE();
15328 	return ret;
15329 }
15330 #endif
15331 #endif
15332 
15333 /**
15334  * @brief               Set/Get DFS repeater mode
15335  *
15336  * @param priv          Pointer to moal_private structure
15337  * @param respbuf       Pointer to response buffer
15338  * @param resplen       Response buffer length
15339  *
15340  *  @return             Number of bytes written, negative for failure.
15341  */
woal_priv_dfs_repeater_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15342 static int woal_priv_dfs_repeater_cfg(moal_private *priv, t_u8 *respbuf,
15343 				      t_u32 respbuflen)
15344 {
15345 	int ret = 0;
15346 	int user_data_len = 0, header_len = 0, data[1] = {0};
15347 	mlan_ioctl_req *req = NULL;
15348 	mlan_ds_misc_cfg *misc_cfg = NULL;
15349 	mlan_ds_misc_dfs_repeater *dfs_repeater = NULL;
15350 	mlan_status status = MLAN_STATUS_SUCCESS;
15351 
15352 	ENTER();
15353 
15354 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_REPEATER_CFG);
15355 
15356 	/* Allocate an IOCTL request buffer */
15357 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15358 	if (req == NULL) {
15359 		ret = -ENOMEM;
15360 		goto done;
15361 	}
15362 
15363 	/* Fill request buffer */
15364 	req->req_id = MLAN_IOCTL_MISC_CFG;
15365 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
15366 	misc_cfg->sub_command = MLAN_OID_MISC_DFS_REAPTER_MODE;
15367 	dfs_repeater =
15368 		(mlan_ds_misc_dfs_repeater *)&misc_cfg->param.dfs_repeater;
15369 
15370 	if ((int)strlen(respbuf) == header_len) {
15371 		/* GET operation */
15372 		user_data_len = 0;
15373 		req->action = MLAN_ACT_GET;
15374 	} else {
15375 		/* SET operation */
15376 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15377 				&user_data_len);
15378 		if (user_data_len != 1) {
15379 			PRINTM(MERROR, "Invalid number of args! %d\n",
15380 			       user_data_len);
15381 			ret = -EINVAL;
15382 			goto done;
15383 		}
15384 		if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
15385 			PRINTM(MERROR, "Invalid DFS repeater mode %d\n",
15386 			       data[0]);
15387 			ret = -EINVAL;
15388 			goto done;
15389 		}
15390 		dfs_repeater->mode = (t_u16)data[0];
15391 
15392 		req->action = MLAN_ACT_SET;
15393 	}
15394 
15395 	/* Send IOCTL request to MLAN */
15396 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15397 	if (status != MLAN_STATUS_SUCCESS) {
15398 		ret = -EFAULT;
15399 		goto done;
15400 	}
15401 
15402 	if (!user_data_len) {
15403 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)dfs_repeater,
15404 				sizeof(mlan_ds_misc_dfs_repeater), respbuflen);
15405 		ret = sizeof(mlan_ds_misc_dfs_repeater);
15406 	}
15407 
15408 	/* Store current value of DFS repeater mode for futher references. eg.,
15409 	 * for avoiding CAC timers
15410 	 */
15411 	priv->phandle->dfs_repeater_mode = dfs_repeater->mode;
15412 
15413 done:
15414 	if (status != MLAN_STATUS_PENDING)
15415 		kfree(req);
15416 
15417 	LEAVE();
15418 	return ret;
15419 }
15420 
15421 #ifdef WIFI_DIRECT_SUPPORT
15422 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
15423 /**
15424  * @brief               Set/Get MIRACAST configuration parameters
15425  *
15426  * @param priv          Pointer to moal_private structure
15427  * @param respbuf       Pointer to response buffer
15428  * @param resplen       Response buffer length
15429  *
15430  *  @return             Number of bytes written, negative for failure.
15431  */
woal_priv_miracast_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15432 static int woal_priv_miracast_cfg(moal_private *priv, t_u8 *respbuf,
15433 				  t_u32 respbuflen)
15434 {
15435 	int ret = 0;
15436 	int user_data_len = 0, header_len = 0, data[3] = {0, 0, 0};
15437 
15438 	ENTER();
15439 
15440 	if (!priv || !priv->phandle) {
15441 		PRINTM(MERROR, "priv or handle is null\n");
15442 		ret = -EFAULT;
15443 		goto done;
15444 	}
15445 
15446 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIRACAST_CFG);
15447 
15448 	if ((int)strlen(respbuf) == header_len) {
15449 		/* GET operation */
15450 		data[0] = priv->phandle->miracast_mode;
15451 		data[1] = priv->phandle->miracast_scan_time;
15452 		data[2] = priv->phandle->scan_chan_gap;
15453 
15454 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
15455 				sizeof(data), respbuflen);
15456 		ret = sizeof(data);
15457 	} else {
15458 		/* SET operation */
15459 		memset(data, 0, sizeof(data));
15460 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15461 				&user_data_len);
15462 
15463 		if (user_data_len > 3) {
15464 			PRINTM(MERROR, "Too many arguments\n");
15465 			ret = -EINVAL;
15466 			goto done;
15467 		}
15468 		if (data[0] < 0 || data[0] > 2 || data[1] < 0 || data[2] < 0) {
15469 			PRINTM(MERROR, "Invalid argument\n");
15470 			ret = -EINVAL;
15471 			goto done;
15472 		}
15473 	}
15474 
15475 	if (user_data_len >= 1)
15476 		priv->phandle->miracast_mode = (t_u8)data[0];
15477 	if (user_data_len >= 2)
15478 		priv->phandle->miracast_scan_time = (t_u16)data[1];
15479 	if (user_data_len == 3)
15480 		priv->phandle->scan_chan_gap = (t_u16)data[2];
15481 
15482 done:
15483 	LEAVE();
15484 	return ret;
15485 }
15486 
15487 /**
15488  *   @brief Configuring scan gap for miracast mode
15489  *
15490  *  @param priv         A pointer to moal_private structure
15491  *  @param respbuf      A pointer to response buffer
15492  *  @param respbuflen   Available length of response buffer
15493  *
15494  *  @return             0 --success, otherwise failure
15495  */
woal_set_scan_chan_gap(moal_private * priv,t_u8 * respbuf,int respbuflen)15496 static int woal_set_scan_chan_gap(moal_private *priv, t_u8 *respbuf,
15497 				  int respbuflen)
15498 {
15499 	t_u32 data[2];
15500 	int ret = 0;
15501 	int user_data_len = 0;
15502 
15503 	ENTER();
15504 
15505 	if (strlen(respbuf) > strlen("SCAN_TIMING")) {
15506 		memset((char *)data, 0, sizeof(data));
15507 		parse_arguments(respbuf + strlen("SCAN_TIMING") + 1, data,
15508 				ARRAY_SIZE(data), &user_data_len);
15509 	}
15510 
15511 	if (user_data_len != 2) {
15512 		PRINTM(MERROR, "Invalid arguments for scan timing\n");
15513 		ret = -EINVAL;
15514 		goto done;
15515 	}
15516 	priv->phandle->miracast_scan_time = (t_u16)data[0];
15517 	priv->phandle->scan_chan_gap = (t_u16)data[1];
15518 done:
15519 	LEAVE();
15520 	return ret;
15521 }
15522 #endif
15523 #endif
15524 
15525 /**
15526  * @brief               Set/Get control to coex RX window size configuration
15527  *
15528  * @param priv          Pointer to moal_private structure
15529  * @param respbuf       Pointer to response buffer
15530  * @param resplen       Response buffer length
15531  *
15532  *  @return             Number of bytes written, negative for failure.
15533  */
woal_priv_coex_rx_winsize(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15534 static int woal_priv_coex_rx_winsize(moal_private *priv, t_u8 *respbuf,
15535 				     t_u32 respbuflen)
15536 {
15537 	int ret = 0;
15538 	int user_data_len = 0, header_len = 0, data = 0;
15539 	mlan_ioctl_req *req = NULL;
15540 	mlan_ds_11n_cfg *cfg_11n = NULL;
15541 	mlan_status status = MLAN_STATUS_SUCCESS;
15542 
15543 	ENTER();
15544 
15545 	if (!priv || !priv->phandle) {
15546 		PRINTM(MERROR, "priv or handle is null\n");
15547 		ret = -EFAULT;
15548 		goto done;
15549 	}
15550 
15551 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_COEX_RX_WINSIZE);
15552 
15553 	/* Allocate an IOCTL request buffer */
15554 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
15555 	if (req == NULL) {
15556 		ret = -ENOMEM;
15557 		goto done;
15558 	}
15559 
15560 	/* Fill request buffer */
15561 	req->req_id = MLAN_IOCTL_11N_CFG;
15562 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
15563 	cfg_11n->sub_command = MLAN_OID_11N_CFG_COEX_RX_WINSIZE;
15564 
15565 	if ((int)strlen(respbuf) == header_len) {
15566 		/* GET operation */
15567 		user_data_len = 0;
15568 		req->action = MLAN_ACT_GET;
15569 	} else {
15570 		/* SET operation */
15571 		parse_arguments(respbuf + header_len, &data,
15572 				sizeof(data) / sizeof(int), &user_data_len);
15573 		if (user_data_len != 1) {
15574 			PRINTM(MERROR, "Invalid number of args! %d\n",
15575 			       user_data_len);
15576 			ret = -EINVAL;
15577 			goto done;
15578 		}
15579 		if ((data != MTRUE) && (data != MFALSE)) {
15580 			PRINTM(MERROR,
15581 			       "Invalid coex RX window size parameter %d\n",
15582 			       data);
15583 			ret = -EINVAL;
15584 			goto done;
15585 		}
15586 		cfg_11n->param.coex_rx_winsize = data;
15587 		req->action = MLAN_ACT_SET;
15588 	}
15589 
15590 	/* Send IOCTL request to MLAN */
15591 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15592 	if (status != MLAN_STATUS_SUCCESS) {
15593 		ret = -EFAULT;
15594 		goto done;
15595 	}
15596 
15597 	if (!user_data_len) {
15598 		moal_memcpy_ext(priv->phandle, respbuf,
15599 				(t_u8 *)&cfg_11n->param.coex_rx_winsize,
15600 				sizeof(t_u32), respbuflen);
15601 		ret = sizeof(t_u32);
15602 	}
15603 
15604 done:
15605 	if (status != MLAN_STATUS_PENDING)
15606 		kfree(req);
15607 
15608 	LEAVE();
15609 	return ret;
15610 }
15611 
15612 /**
15613  * @brief               Set/Get control to TX AMPDU configuration on infra link
15614  *
15615  * @param priv          Pointer to moal_private structure
15616  * @param respbuf       Pointer to response buffer
15617  * @param resplen       Response buffer length
15618  *
15619  *  @return             Number of bytes written, negative for failure.
15620  */
woal_priv_txaggrctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15621 static int woal_priv_txaggrctrl(moal_private *priv, t_u8 *respbuf,
15622 				t_u32 respbuflen)
15623 {
15624 	int ret = 0;
15625 	int user_data_len = 0, header_len = 0, data = 0;
15626 	mlan_ioctl_req *req = NULL;
15627 	mlan_ds_11n_cfg *cfg_11n = NULL;
15628 	mlan_status status = MLAN_STATUS_SUCCESS;
15629 
15630 	ENTER();
15631 
15632 	if (!priv || !priv->phandle) {
15633 		PRINTM(MERROR, "priv or handle is null\n");
15634 		ret = -EFAULT;
15635 		goto done;
15636 	}
15637 
15638 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AGGR_CTRL);
15639 
15640 	/* Allocate an IOCTL request buffer */
15641 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
15642 	if (req == NULL) {
15643 		ret = -ENOMEM;
15644 		goto done;
15645 	}
15646 
15647 	/* Fill request buffer */
15648 	req->req_id = MLAN_IOCTL_11N_CFG;
15649 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
15650 	cfg_11n->sub_command = MLAN_OID_11N_CFG_TX_AGGR_CTRL;
15651 
15652 	if ((int)strlen(respbuf) == header_len) {
15653 		/* GET operation */
15654 		user_data_len = 0;
15655 		req->action = MLAN_ACT_GET;
15656 	} else {
15657 		/* SET operation */
15658 		parse_arguments(respbuf + header_len, &data,
15659 				sizeof(data) / sizeof(int), &user_data_len);
15660 		if (user_data_len != 1) {
15661 			PRINTM(MERROR, "Invalid number of args! %d\n",
15662 			       user_data_len);
15663 			ret = -EINVAL;
15664 			goto done;
15665 		}
15666 		if ((data != MTRUE) && (data != MFALSE)) {
15667 			PRINTM(MERROR, "Invalid txaggrctrl parameter %d\n",
15668 			       data);
15669 			ret = -EINVAL;
15670 			goto done;
15671 		}
15672 		cfg_11n->param.txaggrctrl = data;
15673 		req->action = MLAN_ACT_SET;
15674 	}
15675 
15676 	/* Send IOCTL request to MLAN */
15677 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15678 	if (status != MLAN_STATUS_SUCCESS) {
15679 		ret = -EFAULT;
15680 		goto done;
15681 	}
15682 
15683 	if (!user_data_len) {
15684 		moal_memcpy_ext(priv->phandle, respbuf,
15685 				(t_u8 *)&cfg_11n->param.txaggrctrl,
15686 				sizeof(t_u32), respbuflen);
15687 		ret = sizeof(t_u32);
15688 	}
15689 
15690 done:
15691 	if (status != MLAN_STATUS_PENDING)
15692 		kfree(req);
15693 
15694 	LEAVE();
15695 	return ret;
15696 }
15697 
15698 /**
15699  * @brief               Set/Get control to enable/disable auto TDLS
15700  *
15701  * @param priv          Pointer to moal_private structure
15702  * @param respbuf       Pointer to response buffer
15703  * @param resplen       Response buffer length
15704  *
15705  *  @return             Number of bytes written, negative for failure.
15706  */
woal_priv_auto_tdls(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15707 static int woal_priv_auto_tdls(moal_private *priv, t_u8 *respbuf,
15708 			       t_u32 respbuflen)
15709 {
15710 	int ret = 0;
15711 	int user_data_len = 0, header_len = 0, data = 0;
15712 
15713 	ENTER();
15714 
15715 	if (!priv || !priv->phandle) {
15716 		PRINTM(MERROR, "priv or handle is null\n");
15717 		ret = -EFAULT;
15718 		goto done;
15719 	}
15720 
15721 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_TDLS);
15722 
15723 	if ((int)strlen(respbuf) == header_len) {
15724 		/* GET operation */
15725 		data = priv->enable_auto_tdls;
15726 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
15727 				sizeof(data), respbuflen);
15728 		ret = sizeof(data);
15729 	} else {
15730 		/* SET operation */
15731 		parse_arguments(respbuf + header_len, &data,
15732 				sizeof(data) / sizeof(int), &user_data_len);
15733 		if (user_data_len != 1) {
15734 			PRINTM(MERROR, "Invalid number of args! %d\n",
15735 			       user_data_len);
15736 			ret = -EINVAL;
15737 			goto done;
15738 		}
15739 		if ((data != MTRUE) && (data != MFALSE)) {
15740 			PRINTM(MERROR, "Invalid autotdls parameter %d\n", data);
15741 			ret = -EINVAL;
15742 			goto done;
15743 		}
15744 		priv->enable_auto_tdls = (t_u8)data;
15745 	}
15746 
15747 done:
15748 	LEAVE();
15749 	return ret;
15750 }
15751 
15752 #ifdef PCIE
15753 /**
15754  * @brief               Read/Write PCIE register
15755  *
15756  * @param priv          Pointer to moal_private structure
15757  * @param respbuf       Pointer to response buffer
15758  * @param resplen       Response buffer length
15759  *
15760  * @return              Number of bytes written, negative for failure.
15761  */
woal_priv_pcie_reg_rw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15762 static int woal_priv_pcie_reg_rw(moal_private *priv, t_u8 *respbuf,
15763 				 t_u32 respbuflen)
15764 {
15765 	moal_handle *handle = priv->phandle;
15766 	int data[3];
15767 	t_u32 reg;
15768 	t_u32 value;
15769 	int ret = MLAN_STATUS_SUCCESS;
15770 	int user_data_len = 0, header_len = 0;
15771 
15772 	ENTER();
15773 
15774 	memset(data, 0, sizeof(data));
15775 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_REG_RW);
15776 	if ((int)strlen(respbuf) == header_len) {
15777 		PRINTM(MERROR, "Invalid number of parameters\n");
15778 		ret = -EINVAL;
15779 		goto done;
15780 	}
15781 
15782 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15783 			&user_data_len);
15784 	if ((user_data_len != 1) && (user_data_len != 2)) {
15785 		PRINTM(MERROR, "Invalid number of parameters\n");
15786 		ret = -EINVAL;
15787 		goto done;
15788 	}
15789 
15790 	reg = (t_u32)data[0];
15791 	if (user_data_len == 1) {
15792 		if (moal_read_reg(handle, reg, &value)) {
15793 			ret = -EFAULT;
15794 			goto done;
15795 		}
15796 		data[1] = value;
15797 	} else {
15798 		value = data[1];
15799 		if (moal_write_reg(handle, reg, value)) {
15800 			ret = -EFAULT;
15801 			goto done;
15802 		}
15803 	}
15804 	moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
15805 			respbuflen);
15806 	ret = sizeof(data);
15807 
15808 done:
15809 	LEAVE();
15810 	return ret;
15811 }
15812 
15813 /**
15814  * @brief               Read/Write PCIE register/memory from BAR0
15815  *
15816  * @param priv          Pointer to moal_private structure
15817  * @param respbuf       Pointer to response buffer
15818  * @param resplen       Response buffer length
15819  *
15820  * @return              Number of bytes written, negative for failure.
15821  */
woal_priv_pcie_bar0_reg_rw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15822 static int woal_priv_pcie_bar0_reg_rw(moal_private *priv, t_u8 *respbuf,
15823 				      t_u32 respbuflen)
15824 {
15825 	moal_handle *handle = priv->phandle;
15826 	pcie_service_card *card = (pcie_service_card *)handle->card;
15827 	int data[3];
15828 	t_u32 reg;
15829 	t_u32 value;
15830 	int ret = MLAN_STATUS_SUCCESS;
15831 	int user_data_len = 0, header_len = 0;
15832 
15833 	ENTER();
15834 
15835 	memset(data, 0, sizeof(data));
15836 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_BAR0_REG_RW);
15837 	if ((int)strlen(respbuf) == header_len) {
15838 		PRINTM(MERROR, "Invalid number of parameters\n");
15839 		ret = -EINVAL;
15840 		goto done;
15841 	}
15842 
15843 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15844 			&user_data_len);
15845 	if ((user_data_len != 1) && (user_data_len != 2)) {
15846 		PRINTM(MERROR, "Invalid number of parameters\n");
15847 		ret = -EINVAL;
15848 		goto done;
15849 	}
15850 
15851 	reg = (t_u32)data[0];
15852 	if (user_data_len == 1) {
15853 		value = ioread32(card->pci_mmap + reg);
15854 		if (value == MLAN_STATUS_FAILURE) {
15855 			ret = -EFAULT;
15856 			goto done;
15857 		}
15858 		data[1] = value;
15859 	} else {
15860 		value = data[1];
15861 		iowrite32(value, card->pci_mmap + reg);
15862 	}
15863 	moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
15864 			respbuflen);
15865 	ret = sizeof(data);
15866 
15867 done:
15868 	LEAVE();
15869 	return ret;
15870 }
15871 #endif
15872 
15873 /**
15874  * @brief               Get SOC temperature
15875  *
15876  * @param priv          Pointer to moal_private structure
15877  * @param respbuf       Pointer to response buffer
15878  * @param resplen       Response buffer length
15879  *
15880  * @return              Number of bytes written, negative for failure.
15881  */
woal_priv_get_sensor_temp(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15882 static int woal_priv_get_sensor_temp(moal_private *priv, t_u8 *respbuf,
15883 				     t_u32 respbuflen)
15884 {
15885 	mlan_ioctl_req *req = NULL;
15886 	mlan_ds_misc_cfg *pcfg = NULL;
15887 	int ret = 0;
15888 	mlan_status status = MLAN_STATUS_SUCCESS;
15889 
15890 	ENTER();
15891 
15892 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15893 	if (req == NULL) {
15894 		ret = -ENOMEM;
15895 		goto done;
15896 	}
15897 
15898 	pcfg = (mlan_ds_misc_cfg *)req->pbuf;
15899 	pcfg->sub_command = MLAN_OID_MISC_GET_SENSOR_TEMP;
15900 	req->req_id = MLAN_IOCTL_MISC_CFG;
15901 	req->action = MLAN_ACT_GET;
15902 
15903 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15904 	if (status != MLAN_STATUS_SUCCESS) {
15905 		ret = -EFAULT;
15906 		goto done;
15907 	}
15908 
15909 	memset(respbuf, 0, respbuflen);
15910 	moal_memcpy_ext(priv->phandle, respbuf,
15911 			&pcfg->param.sensor_temp.temperature, sizeof(t_u32),
15912 			respbuflen);
15913 
15914 	ret = sizeof(t_u32);
15915 
15916 done:
15917 	if (status != MLAN_STATUS_PENDING)
15918 		kfree(req);
15919 	LEAVE();
15920 	return ret;
15921 }
15922 
15923 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
15924 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
15925 /**
15926  * @brief               Enable/disable DFS offload
15927  *
15928  * @param priv          Pointer to moal_private structure
15929  * @param respbuf       Pointer to response buffer
15930  * @param resplen       Response buffer length
15931  *
15932  * @return              Number of bytes written, negative for failure.
15933  */
woal_priv_dfs_offload_enable(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15934 static int woal_priv_dfs_offload_enable(moal_private *priv, t_u8 *respbuf,
15935 					t_u32 respbuflen)
15936 {
15937 	int ret = 0, dfs_offload_en = 0, user_data_len = 0, header_len = 0,
15938 	    dfs_offload;
15939 
15940 	ENTER();
15941 
15942 	if (!priv) {
15943 		PRINTM(MERROR, "priv is NULL\n");
15944 		ret = -EFAULT;
15945 		goto done;
15946 	}
15947 
15948 	dfs_offload = moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD);
15949 	if (woal_is_any_interface_active(priv->phandle)) {
15950 		PRINTM(MERROR,
15951 		       "DFS offload enable/disable do not allowed after BSS started!\n");
15952 		ret = -EFAULT;
15953 		goto done;
15954 	}
15955 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_OFFLOAD);
15956 	parse_arguments(respbuf + header_len, &dfs_offload_en,
15957 			sizeof(dfs_offload_en) / sizeof(int), &user_data_len);
15958 	if (user_data_len != 1) {
15959 		PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
15960 		ret = -EINVAL;
15961 		goto done;
15962 	}
15963 
15964 	if (dfs_offload_en != 0 && dfs_offload_en != 1) {
15965 		PRINTM(MERROR, "Invalid args!\n");
15966 		ret = -EINVAL;
15967 		goto done;
15968 	}
15969 	if (dfs_offload != dfs_offload_en) {
15970 		dfs_offload = dfs_offload_en;
15971 		if (dfs_offload)
15972 			moal_extflg_set(priv->phandle, EXT_DFS_OFFLOAD);
15973 		else
15974 			moal_extflg_clear(priv->phandle, EXT_DFS_OFFLOAD);
15975 	}
15976 done:
15977 	LEAVE();
15978 	return ret;
15979 }
15980 #endif
15981 #endif
15982 
15983 /**
15984  * @brief               Set/Get TDLS CS off channel value
15985  *
15986  * @param priv          Pointer to moal_private structure
15987  * @param respbuf       Pointer to response buffer
15988  * @param resplen       Response buffer length
15989 
15990  *  @return             Number of bytes written, negative for failure.
15991  */
woal_priv_tdls_cs_chan(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15992 static int woal_priv_tdls_cs_chan(moal_private *priv, t_u8 *respbuf,
15993 				  t_u32 respbuflen)
15994 {
15995 	mlan_ioctl_req *ioctl_req = NULL;
15996 	mlan_ds_misc_cfg *misc = NULL;
15997 	mlan_status status = MLAN_STATUS_SUCCESS;
15998 	int ret = 0;
15999 	int user_data_len = 0, header_len = 0, data = 0;
16000 
16001 	ENTER();
16002 
16003 	if (!priv || !priv->phandle) {
16004 		PRINTM(MERROR, "priv or handle is null\n");
16005 		ret = -EFAULT;
16006 		goto done;
16007 	}
16008 
16009 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16010 	if (ioctl_req == NULL) {
16011 		ret = -ENOMEM;
16012 		goto done;
16013 	}
16014 
16015 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16016 	misc->sub_command = MLAN_OID_MISC_TDLS_CS_CHANNEL;
16017 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16018 
16019 	header_len = strlen("TDLS_CS_CHAN");
16020 	if ((int)strlen(respbuf) == header_len) {
16021 		/* GET operation */
16022 		ioctl_req->action = MLAN_ACT_GET;
16023 	} else {
16024 		/* SET operation */
16025 		parse_arguments(respbuf + header_len + 1, &data,
16026 				sizeof(data) / sizeof(int), &user_data_len);
16027 		if (user_data_len != 1) {
16028 			PRINTM(MERROR, "Invalid number of args! %d\n",
16029 			       user_data_len);
16030 			ret = -EINVAL;
16031 			goto done;
16032 		}
16033 		ioctl_req->action = MLAN_ACT_SET;
16034 		misc->param.tdls_cs_channel = (t_u8)data;
16035 	}
16036 
16037 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16038 	if (status != MLAN_STATUS_SUCCESS) {
16039 		ret = -EFAULT;
16040 		goto done;
16041 	}
16042 
16043 	ret = sprintf(respbuf, "off channel %d\n",
16044 		      misc->param.tdls_cs_channel) +
16045 	      1;
16046 
16047 	PRINTM(MIOCTL, "tdls CS channel %d\n", misc->param.tdls_cs_channel);
16048 done:
16049 	if (status != MLAN_STATUS_PENDING)
16050 		kfree(ioctl_req);
16051 
16052 	LEAVE();
16053 	return ret;
16054 }
16055 /**
16056  * @brief               Set/Get TDLS idle timeout value
16057  *
16058  * @param priv          Pointer to moal_private structure
16059  * @param respbuf       Pointer to response buffer
16060  * @param resplen       Response buffer length
16061 
16062  *  @return             Number of bytes written, negative for failure.
16063  */
woal_priv_tdls_idle_time(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16064 static int woal_priv_tdls_idle_time(moal_private *priv, t_u8 *respbuf,
16065 				    t_u32 respbuflen)
16066 {
16067 	mlan_ioctl_req *ioctl_req = NULL;
16068 	mlan_ds_misc_cfg *misc = NULL;
16069 	mlan_status status = MLAN_STATUS_SUCCESS;
16070 	int ret = 0;
16071 	int user_data_len = 0, header_len = 0, data = 0;
16072 
16073 	ENTER();
16074 
16075 	if (!priv || !priv->phandle) {
16076 		PRINTM(MERROR, "priv or handle is null\n");
16077 		ret = -EFAULT;
16078 		goto done;
16079 	}
16080 
16081 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16082 	if (ioctl_req == NULL) {
16083 		ret = -ENOMEM;
16084 		goto done;
16085 	}
16086 
16087 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16088 	misc->sub_command = MLAN_OID_MISC_TDLS_IDLE_TIME;
16089 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16090 
16091 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TDLS_IDLE_TIME);
16092 	if ((int)strlen(respbuf) == header_len) {
16093 		/* GET operation */
16094 		ioctl_req->action = MLAN_ACT_GET;
16095 	} else {
16096 		/* SET operation */
16097 		parse_arguments(respbuf + header_len, &data,
16098 				sizeof(data) / sizeof(int), &user_data_len);
16099 		if (user_data_len != 1) {
16100 			PRINTM(MERROR, "Invalid number of args! %d\n",
16101 			       user_data_len);
16102 			ret = -EINVAL;
16103 			goto done;
16104 		}
16105 		ioctl_req->action = MLAN_ACT_SET;
16106 		misc->param.tdls_idle_time = (t_u16)data;
16107 	}
16108 
16109 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16110 	if (status != MLAN_STATUS_SUCCESS) {
16111 		ret = -EFAULT;
16112 		goto done;
16113 	}
16114 
16115 	moal_memcpy_ext(priv->phandle, respbuf,
16116 			(t_u8 *)&misc->param.tdls_idle_time, sizeof(t_u16),
16117 			respbuflen);
16118 	ret = sizeof(t_u16);
16119 
16120 	PRINTM(MIOCTL, "tdls idle time %d\n", misc->param.tdls_idle_time);
16121 done:
16122 	if (status != MLAN_STATUS_PENDING)
16123 		kfree(ioctl_req);
16124 
16125 	LEAVE();
16126 	return ret;
16127 }
16128 
16129 /**
16130  * @brief               Set/Get dynamic bandwidth
16131  *
16132  * @param priv          Pointer to moal_private structure
16133  * @param respbuf       Pointer to response buffer
16134  * @param resplen       Response buffer length
16135 
16136  *  @return             Number of bytes written, negative for failure.
16137  */
woal_priv_config_dyn_bw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16138 static int woal_priv_config_dyn_bw(moal_private *priv, t_u8 *respbuf,
16139 				   t_u32 respbuflen)
16140 {
16141 	mlan_ioctl_req *ioctl_req = NULL;
16142 	mlan_ds_misc_cfg *misc = NULL;
16143 	mlan_status status = MLAN_STATUS_SUCCESS;
16144 	int ret = 0;
16145 	int user_data_len = 0, header_len = 0, data = 0;
16146 
16147 	ENTER();
16148 
16149 	if (!priv || !priv->phandle) {
16150 		PRINTM(MERROR, "priv or handle is null\n");
16151 		ret = -EFAULT;
16152 		goto done;
16153 	}
16154 
16155 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16156 	if (ioctl_req == NULL) {
16157 		ret = -ENOMEM;
16158 		goto done;
16159 	}
16160 
16161 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16162 	misc->sub_command = MLAN_OID_MISC_DYN_BW;
16163 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16164 
16165 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DYN_BW);
16166 	if ((int)strlen(respbuf) == header_len) {
16167 		/* GET operation */
16168 		ioctl_req->action = MLAN_ACT_GET;
16169 	} else {
16170 		/* SET operation */
16171 		parse_arguments(respbuf + header_len, &data,
16172 				sizeof(data) / sizeof(int), &user_data_len);
16173 		if (user_data_len != 1) {
16174 			PRINTM(MERROR, "Invalid number of args! %d\n",
16175 			       user_data_len);
16176 			ret = -EINVAL;
16177 			goto done;
16178 		}
16179 		ioctl_req->action = MLAN_ACT_SET;
16180 		misc->param.dyn_bw = (t_u16)data;
16181 	}
16182 
16183 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16184 	if (status != MLAN_STATUS_SUCCESS) {
16185 		ret = -EFAULT;
16186 		goto done;
16187 	}
16188 
16189 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.dyn_bw,
16190 			sizeof(t_u16), respbuflen);
16191 	ret = sizeof(t_u16);
16192 
16193 	PRINTM(MIOCTL, "Dynamic bandwidth %d\n", misc->param.dyn_bw);
16194 done:
16195 	if (status != MLAN_STATUS_PENDING)
16196 		kfree(ioctl_req);
16197 
16198 	LEAVE();
16199 	return ret;
16200 }
16201 
16202 #if defined(UAP_SUPPORT)
16203 /**
16204  * @brief               Check validation of channel and oper class
16205  *
16206  * @param priv          Pointer to moal_private structure
16207  * @param channel       channel
16208  * @param oper_class    oper_class
16209 
16210  *  @return             SUCCESS/FAIL
16211  */
woal_check_valid_channel_operclass(moal_private * priv,int channel,int oper_class)16212 static int woal_check_valid_channel_operclass(moal_private *priv, int channel,
16213 					      int oper_class)
16214 {
16215 	int ret = 0;
16216 	mlan_ioctl_req *ioctl_req = NULL;
16217 	mlan_ds_misc_cfg *misc = NULL;
16218 	mlan_status status = MLAN_STATUS_SUCCESS;
16219 
16220 	ENTER();
16221 
16222 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16223 	if (ioctl_req == NULL) {
16224 		ret = -ENOMEM;
16225 		goto done;
16226 	}
16227 
16228 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16229 	misc->sub_command = MLAN_OID_MISC_OPER_CLASS_CHECK;
16230 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16231 	ioctl_req->action = MLAN_ACT_GET;
16232 	misc->param.bw_chan_oper.oper_class = (t_u8)oper_class;
16233 	misc->param.bw_chan_oper.channel = (t_u8)channel;
16234 
16235 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16236 	if (status != MLAN_STATUS_SUCCESS) {
16237 		ret = -EFAULT;
16238 		goto done;
16239 	}
16240 
16241 done:
16242 	if (status != MLAN_STATUS_PENDING)
16243 		kfree(ioctl_req);
16244 
16245 	LEAVE();
16246 	return ret;
16247 }
16248 
16249 /**
16250  * @brief Enable radar detect for DFS channel
16251  *
16252  * @param priv            A pointer to moal private structure
16253  * @param chan            channel
16254  * @return                N/A
16255  */
woal_enable_dfs(moal_private * priv,t_u8 channel,t_u8 wait_option)16256 static void woal_enable_dfs(moal_private *priv, t_u8 channel, t_u8 wait_option)
16257 {
16258 	mlan_ioctl_req *req = NULL;
16259 	mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
16260 	mlan_ds_11h_cfg *p11h_cfg = NULL;
16261 	mlan_status status = MLAN_STATUS_SUCCESS;
16262 	ENTER();
16263 	PRINTM(MCMND, "Enable Radar detect, chan %d\n", channel);
16264 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
16265 	if (NULL == req) {
16266 		PRINTM(MIOCTL, "No Memory to allocate ioctl buffer\n");
16267 		LEAVE();
16268 		return;
16269 	}
16270 	p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
16271 	pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;
16272 	pchan_rpt_req->startFreq = 5000;
16273 	pchan_rpt_req->chanNum = channel;
16274 	pchan_rpt_req->host_based = MTRUE;
16275 	pchan_rpt_req->millisec_dwell_time = 0;
16276 
16277 	p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
16278 	req->req_id = MLAN_IOCTL_11H_CFG;
16279 	req->action = MLAN_ACT_SET;
16280 	/* Send Channel Check command and wait until the report is ready */
16281 	status = woal_request_ioctl(priv, req, wait_option);
16282 	if (status != MLAN_STATUS_PENDING)
16283 		kfree(req);
16284 	LEAVE();
16285 	return;
16286 }
16287 
16288 /**
16289  *  @brief send CSA/ECSA action frame
16290  *
16291  ** @param priv          Pointer to moal_private structure
16292  *  @param block_tx      0-no need block traffic 1- need block traffic
16293  *  @param oper_class    oper_class
16294  *  @param channel       channel
16295  *  @param switch count  how many csa/ecsa beacon will send out
16296  *  @param wait_option
16297  *
16298  *  @return             channel center frequency center, if found; O, otherwise
16299  */
woal_action_channel_switch(moal_private * priv,t_u8 block_tx,t_u8 oper_class,t_u8 channel,t_u8 switch_count,t_u8 wait_option)16300 static int woal_action_channel_switch(moal_private *priv, t_u8 block_tx,
16301 				      t_u8 oper_class, t_u8 channel,
16302 				      t_u8 switch_count, t_u8 wait_option)
16303 {
16304 	mlan_status ret = MLAN_STATUS_SUCCESS;
16305 	mlan_ds_bss *bss = NULL;
16306 	mlan_ioctl_req *req = NULL;
16307 
16308 	ENTER();
16309 
16310 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
16311 	if (req == NULL) {
16312 		ret = MLAN_STATUS_FAILURE;
16313 		goto done;
16314 	}
16315 
16316 	bss = (mlan_ds_bss *)req->pbuf;
16317 	bss->sub_command = MLAN_OID_ACTION_CHAN_SWITCH;
16318 	req->req_id = MLAN_IOCTL_BSS;
16319 	req->action = MLAN_ACT_SET;
16320 	bss->param.chanswitch.chan_switch_mode = block_tx;
16321 	bss->param.chanswitch.new_channel_num = channel;
16322 	if (!switch_count)
16323 		bss->param.chanswitch.chan_switch_count = DEF_NUM_PKTS;
16324 	else
16325 		bss->param.chanswitch.chan_switch_count =
16326 			MIN(switch_count, MAX_NUM_PKTS);
16327 	bss->param.chanswitch.new_oper_class = oper_class;
16328 	ret = woal_request_ioctl(priv, req, wait_option);
16329 done:
16330 	if (ret != MLAN_STATUS_PENDING)
16331 		kfree(req);
16332 	LEAVE();
16333 	return ret;
16334 }
16335 
16336 #ifdef UAP_SUPPORT
16337 /**
16338  *  @brief move the uAP to transition channel
16339  *
16340  *  @param priv          Pointer to moal_private structure
16341  *
16342  *  @return              N/A
16343  */
woal_move_to_next_channel(moal_private * priv)16344 void woal_move_to_next_channel(moal_private *priv)
16345 {
16346 	mlan_ds_11h_chan_dfs_state ch_dfs;
16347 	t_u8 next_chan = 0;
16348 	if (priv->target_chan) {
16349 		next_chan = priv->target_chan;
16350 		priv->target_chan = 0;
16351 	} else if (priv->backup_chan) {
16352 		next_chan = priv->backup_chan;
16353 	}
16354 	if (!next_chan)
16355 		return;
16356 	memset(&ch_dfs, 0, sizeof(ch_dfs));
16357 	ch_dfs.channel = next_chan;
16358 	if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET, &ch_dfs))
16359 		PRINTM(MERROR, "%s: woal_11h_chan_dfs_state failed \n",
16360 		       __func__);
16361 	if (ch_dfs.dfs_required)
16362 		woal_enable_dfs(priv, next_chan, MOAL_NO_WAIT);
16363 	woal_action_channel_switch(priv, MTRUE, 0, next_chan, 0, MOAL_NO_WAIT);
16364 	return;
16365 }
16366 #endif
16367 
16368 /**
16369  * @brief               Set extended channel switch ie
16370  *
16371  * @param priv          Pointer to moal_private structure
16372  * @param respbuf       Pointer to response buffer
16373  * @param resplen       Response buffer length
16374  *
16375  * @return             Number of bytes written, negative for failure.
16376  */
woal_priv_extend_channel_switch(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16377 static int woal_priv_extend_channel_switch(moal_private *priv, t_u8 *respbuf,
16378 					   t_u32 respbuflen)
16379 {
16380 	int ret = 0;
16381 	int user_data_len = 0;
16382 	int data[5] = {0};
16383 	t_u8 channel;
16384 	mlan_ds_11h_chan_dfs_state ch_dfs;
16385 	ENTER();
16386 
16387 	if (!priv || !priv->phandle || (priv->bss_role != MLAN_BSS_ROLE_UAP) ||
16388 	    (priv->bss_started != MTRUE)) {
16389 		PRINTM(MERROR,
16390 		       "priv or handle is null or interface is not AP/GO"
16391 		       "or AP is not started\n");
16392 		ret = -EFAULT;
16393 		LEAVE();
16394 		return ret;
16395 	}
16396 
16397 	parse_arguments(respbuf + strlen(CMD_NXP) +
16398 				strlen(PRIV_CMD_EXTEND_CHAN_SWITCH),
16399 			data, ARRAY_SIZE(data), &user_data_len);
16400 
16401 	if (sizeof(int) * user_data_len > sizeof(data)) {
16402 		PRINTM(MERROR, "Too many arguments\n");
16403 		ret = -EINVAL;
16404 		LEAVE();
16405 		return ret;
16406 	}
16407 	if (user_data_len < 4) {
16408 		PRINTM(MERROR, "Too few arguments\n");
16409 		ret = -EINVAL;
16410 		LEAVE();
16411 		return ret;
16412 	}
16413 
16414 	/* For 2.4G channels skip the DFS checks */
16415 	channel = data[2];
16416 	if (channel > MAX_BG_CHANNEL) {
16417 		memset(&ch_dfs, 0, sizeof(ch_dfs));
16418 		ch_dfs.channel = data[2];
16419 
16420 		if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET, &ch_dfs)) {
16421 			PRINTM(MERROR, "%s: woal_11h_chan_dfs_state failed \n",
16422 			       __func__);
16423 			ret = -EFAULT;
16424 			LEAVE();
16425 			return ret;
16426 		}
16427 
16428 		if (ch_dfs.dfs_required &&
16429 		    (ch_dfs.dfs_state == DFS_UNAVAILABLE ||
16430 		     ch_dfs.dfs_state == DFS_USABLE)) {
16431 			PRINTM(MERROR,
16432 			       "DFS: Channel=%d is not Available, cannot switch to this channel\n",
16433 			       data[2]);
16434 			ret = -EFAULT;
16435 			LEAVE();
16436 			return ret;
16437 		}
16438 
16439 		if (ch_dfs.dfs_required)
16440 			woal_enable_dfs(priv, data[2], MOAL_IOCTL_WAIT);
16441 	}
16442 	if (data[1]) {
16443 		if (woal_check_valid_channel_operclass(priv, data[2],
16444 						       data[1])) {
16445 			PRINTM(MERROR, "Wrong channel switch parameters!\n");
16446 			ret = -EINVAL;
16447 			goto done;
16448 		}
16449 	}
16450 	if (data[3])
16451 		woal_channel_switch(priv, data[0], data[1], data[2], data[3],
16452 				    data[4], MFALSE);
16453 	else
16454 		woal_action_channel_switch(priv, data[0], data[1], data[2],
16455 					   data[4], MOAL_IOCTL_WAIT);
16456 done:
16457 	LEAVE();
16458 	return ret;
16459 }
16460 
16461 /**
16462  * @brief               P2P extended channel switch
16463  *
16464  * @param priv          Pointer to moal_private structure
16465  * @param respbuf       Pointer to response buffer
16466  * @param resplen       Response buffer length
16467 
16468  *  @return             Number of bytes written, negative for failure.
16469  */
woal_priv_p2p_ecsa(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16470 static int woal_priv_p2p_ecsa(moal_private *priv, t_u8 *respbuf,
16471 			      t_u32 respbuflen)
16472 {
16473 	int ret = 0;
16474 	int user_data_len = 0, header_len = 0;
16475 	int data[2] = {0};
16476 	t_u8 bw = 0, oper_class = 0, channel = 0;
16477 	IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
16478 	custom_ie *pcust_chansw_ie = NULL;
16479 	mlan_ioctl_req *ioctl_req = NULL;
16480 	mlan_ds_misc_cfg *misc = NULL;
16481 	mlan_status status = MLAN_STATUS_SUCCESS;
16482 
16483 	ENTER();
16484 
16485 	if (!priv || !priv->phandle) {
16486 		PRINTM(MERROR, "priv or handle is null\n");
16487 		ret = -EFAULT;
16488 		goto done;
16489 	}
16490 
16491 	if (priv->bss_role != MLAN_BSS_ROLE_UAP) {
16492 		PRINTM(MERROR,
16493 		       "Extended Channel Switch is only allowed for AP/GO mode\n");
16494 		ret = -EFAULT;
16495 		goto done;
16496 	}
16497 
16498 	if (priv->bss_started != MTRUE) {
16499 		PRINTM(MERROR, "AP is not started!\n");
16500 		ret = -EFAULT;
16501 		goto done;
16502 	}
16503 
16504 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16505 	if (ioctl_req == NULL) {
16506 		ret = -ENOMEM;
16507 		goto done;
16508 	}
16509 
16510 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16511 	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
16512 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16513 	ioctl_req->action = MLAN_ACT_SET;
16514 	misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
16515 	misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
16516 
16517 	pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
16518 	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
16519 	pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ExtChanSwitchAnn_t);
16520 	pcust_chansw_ie->mgmt_subtype_mask =
16521 		MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
16522 							    BEACON/probe resp*/
16523 	ext_chan_switch =
16524 		(IEEEtypes_ExtChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
16525 
16526 	header_len = strlen("P2P_ECSA");
16527 	parse_arguments(respbuf + header_len + 1, data, ARRAY_SIZE(data),
16528 			&user_data_len);
16529 
16530 	if (user_data_len != 2) {
16531 		PRINTM(MERROR, "Invalid parameters\n");
16532 		ret = -EFAULT;
16533 		goto done;
16534 	}
16535 
16536 	channel = data[0];
16537 	/* bandwidth 20:20M 40:40M 80:80M*/
16538 	bw = data[1];
16539 	if (bw != 20 && bw != 40 && bw != 80) {
16540 		PRINTM(MERROR, "Unsupported bandwidth\n");
16541 		ret = -EINVAL;
16542 		goto done;
16543 	}
16544 	if (channel >= 52 && channel <= 144) {
16545 		PRINTM(MERROR, "Switch to DFS channel is not allowed!\n");
16546 		ret = -EINVAL;
16547 		goto done;
16548 	}
16549 
16550 	woal_priv_get_nonglobal_operclass_by_bw_channel(priv, bw, channel,
16551 							&oper_class);
16552 	if (oper_class == 0) {
16553 		PRINTM(MERROR, "Wrong parameters!\n");
16554 		ret = -EFAULT;
16555 		goto done;
16556 	}
16557 	ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
16558 	ext_chan_switch->len = 4;
16559 	ext_chan_switch->chan_switch_mode = 1;
16560 	ext_chan_switch->new_oper_class = oper_class;
16561 	ext_chan_switch->new_channel_num = channel;
16562 	ext_chan_switch->chan_switch_count = DEF_CHAN_SWITCH_COUNT;
16563 
16564 	if (ext_chan_switch->chan_switch_mode) {
16565 		if (netif_carrier_ok(priv->netdev))
16566 			netif_carrier_off(priv->netdev);
16567 		woal_stop_queue(priv->netdev);
16568 		priv->uap_tx_blocked = MTRUE;
16569 	}
16570 
16571 	DBG_HEXDUMP(MCMD_D, "ECSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer,
16572 		    pcust_chansw_ie->ie_length);
16573 
16574 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16575 	if (status != MLAN_STATUS_SUCCESS) {
16576 		ret = -EFAULT;
16577 		goto done;
16578 	}
16579 
16580 	priv->phandle->chsw_wait_q_woken = MFALSE;
16581 	/* wait for channel switch to complete  */
16582 	wait_event_interruptible_timeout(
16583 		priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
16584 		(u32)HZ * (ext_chan_switch->chan_switch_count + 2) * 110 /
16585 			1000);
16586 
16587 	pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
16588 	pcust_chansw_ie->mgmt_subtype_mask = 0;
16589 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16590 	if (status != MLAN_STATUS_SUCCESS) {
16591 		PRINTM(MERROR, "Failed to clear ECSA IE\n");
16592 	}
16593 done:
16594 	if (status != MLAN_STATUS_PENDING)
16595 		kfree(ioctl_req);
16596 
16597 	LEAVE();
16598 	return ret;
16599 }
16600 #endif
16601 
16602 /**
16603 * @brief               Set random mac configure value (ON/OFF)
16604 *
16605 * @param priv          Pointer to moal_private structure
16606 * @param respbuf       Pointer to response buffer
16607 * @param resplen       Response buffer length
16608 
16609 *  @return             Number of bytes written, negative for failure.
16610 */
woal_priv_config_random_mac(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16611 static int woal_priv_config_random_mac(moal_private *priv, t_u8 *respbuf,
16612 				       t_u32 respbuflen)
16613 {
16614 	int ret = 0;
16615 	int header_len = 0, space_len = 0, i;
16616 	t_u8 rand_data[3];
16617 	const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
16618 
16619 	ENTER();
16620 
16621 	if (!priv || !priv->phandle) {
16622 		PRINTM(MERROR, "priv or handle is null\n");
16623 		ret = -EFAULT;
16624 		goto done;
16625 	}
16626 
16627 	header_len = strlen("FAKEMAC");
16628 	if ((int)strlen(respbuf) >= header_len) {
16629 		for (i = 0; i < (int)(strlen(respbuf) - header_len - 1); i++) {
16630 			if (respbuf[header_len + 1 + i] != ' ')
16631 				break;
16632 		}
16633 		space_len = i;
16634 
16635 		if (strncmp(respbuf + header_len + 1 + space_len, "On",
16636 			    strlen("On")) == 0) {
16637 			if (memcmp(priv->random_mac, zero_mac,
16638 				   MLAN_MAC_ADDR_LENGTH)) {
16639 				ret = sprintf(respbuf,
16640 					      "FAKEMAC has been On\n") +
16641 				      1;
16642 				goto done;
16643 			}
16644 			moal_memcpy_ext(priv->phandle, priv->random_mac,
16645 					priv->current_addr, ETH_ALEN,
16646 					MLAN_MAC_ADDR_LENGTH);
16647 			get_random_bytes(rand_data, 3);
16648 			moal_memcpy_ext(priv->phandle, priv->random_mac + 3,
16649 					rand_data, 3, 3);
16650 			PRINTM(MMSG, "FAKEMAC parameter is On\n");
16651 		} else if (strncmp(respbuf + header_len + 1 + space_len, "Off",
16652 				   strlen("Off")) == 0) {
16653 			memset(priv->random_mac, 0, ETH_ALEN);
16654 			PRINTM(MMSG, "FAKEMAC parameter is Off\n");
16655 		} else {
16656 			PRINTM(MERROR, "Invalid parameter!\n");
16657 			ret = -EINVAL;
16658 			goto done;
16659 		}
16660 	} else {
16661 		PRINTM(MERROR, "Invalid parameter!\n");
16662 		ret = -EINVAL;
16663 		goto done;
16664 	}
16665 
16666 done:
16667 	LEAVE();
16668 	return ret;
16669 }
16670 
16671 /**
16672  * @brief               enable/disable roaming offload to firmware
16673  *
16674  * @param priv          Pointer to moal_private structure
16675  * @param respbuf       Pointer to response buffer
16676  * @param resplen       Response buffer length
16677 
16678  *  @return             Number of bytes written, negative for failure.
16679  */
woal_priv_set_roam_offload(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16680 static int woal_priv_set_roam_offload(moal_private *priv, t_u8 *respbuf,
16681 				      t_u32 respbuflen)
16682 {
16683 	int user_data_len = 0, header_len = 0, ret = 0;
16684 	int data = 0;
16685 #ifdef STA_CFG80211
16686 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
16687 	t_u8 enable = 0;
16688 #endif
16689 #endif
16690 
16691 	ENTER();
16692 
16693 	if (!priv || !priv->phandle) {
16694 		PRINTM(MERROR, "priv or handle is null\n");
16695 		ret = -EFAULT;
16696 		goto done;
16697 	}
16698 
16699 #ifdef STA_CFG80211
16700 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
16701 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
16702 		ret = -EFAULT;
16703 		goto done;
16704 	}
16705 #endif
16706 #endif
16707 
16708 	header_len = strlen("SETROAMOFFLOAD");
16709 	parse_arguments(respbuf + header_len + 1, &data, 1, &user_data_len);
16710 
16711 	if (data < 0 || data > 5) {
16712 		PRINTM(MERROR, "Invalid parameters\n");
16713 		ret = -EFAULT;
16714 		goto done;
16715 	}
16716 
16717 #ifdef STA_CFG80211
16718 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
16719 	if (!data) {
16720 		woal_cfg80211_vendor_event(priv, event_set_key_mgmt_offload,
16721 					   &enable, sizeof(enable));
16722 	}
16723 #endif
16724 #endif
16725 
16726 	ret = woal_enable_fw_roaming(priv, data);
16727 done:
16728 
16729 	LEAVE();
16730 	return ret;
16731 }
16732 
16733 /**
16734  * @brief               set roaming offload aplist to firmware
16735  *
16736  * @param priv          Pointer to moal_private structure
16737  * @param respbuf       Pointer to response buffer
16738  * @param resplen       Response buffer length
16739 
16740  *  @return             Number of bytes written, negative for failure.
16741  */
woal_priv_set_roam_offload_aplist(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16742 static int woal_priv_set_roam_offload_aplist(moal_private *priv, t_u8 *respbuf,
16743 					     t_u32 respbuflen)
16744 {
16745 	mlan_ioctl_req *ioctl_req = NULL;
16746 	mlan_ds_misc_cfg *misc = NULL;
16747 	mlan_ds_misc_roam_offload *roam = NULL;
16748 	mlan_ds_misc_roam_offload_aplist *aplist = NULL;
16749 	mlan_status status = MLAN_STATUS_SUCCESS;
16750 	int ret = 0, i = 0;
16751 	int user_data_len = 0, header_len = 0;
16752 	int ap_count = 0;
16753 	char *begin = NULL, *end = NULL;
16754 	t_u8 mac_addr[6];
16755 
16756 	ENTER();
16757 
16758 	if (!priv || !priv->phandle) {
16759 		PRINTM(MERROR, "priv or handle is null\n");
16760 		ret = -EFAULT;
16761 		goto done;
16762 	}
16763 
16764 #ifdef STA_CFG80211
16765 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
16766 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
16767 		ret = -EFAULT;
16768 		goto done;
16769 	}
16770 #endif
16771 #endif
16772 
16773 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16774 	if (ioctl_req == NULL) {
16775 		ret = -ENOMEM;
16776 		goto done;
16777 	}
16778 
16779 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16780 	misc->sub_command = MLAN_OID_MISC_ROAM_OFFLOAD_APLIST;
16781 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16782 
16783 	roam = (mlan_ds_misc_roam_offload *)&misc->param.roam_offload;
16784 	/*Set enable to invalid value(valid: 0, 1, 2)*/
16785 	roam->enable = 3;
16786 	aplist = &roam->aplist;
16787 
16788 	header_len = strlen("SETROAMOFFLAPLIST");
16789 	user_data_len = strlen(respbuf) - header_len;
16790 	if (!user_data_len) {
16791 		/* GET operation */
16792 		ioctl_req->action = MLAN_ACT_GET;
16793 	} else {
16794 		begin = &respbuf[header_len + 1];
16795 		end = begin;
16796 		while (begin && *begin == ' ') {
16797 			begin++;
16798 			end++;
16799 		}
16800 		while (end && *end != ' ')
16801 			end++;
16802 		if (end != NULL)
16803 			*end = '\0';
16804 		end++;
16805 		if (begin) {
16806 			if (woal_atoi(&ap_count, begin) !=
16807 			    MLAN_STATUS_SUCCESS) {
16808 				ret = -EINVAL;
16809 				goto done;
16810 			}
16811 		}
16812 		aplist->ap_num = ap_count;
16813 		if (ap_count > 0 && ap_count <= MAX_AP_LIST) {
16814 			/* SET operation */
16815 			ioctl_req->action = MLAN_ACT_SET;
16816 			for (i = 0; i < ap_count; i++) {
16817 				begin = end;
16818 				while (begin && *begin == ' ') {
16819 					begin++;
16820 					end++;
16821 				}
16822 				while (end && *end != ' ' && *end != '\0')
16823 					end++;
16824 				if (end == begin) {
16825 					PRINTM(MERROR,
16826 					       "AP number %d is wrong\n",
16827 					       ap_count);
16828 					ret = -EINVAL;
16829 					goto done;
16830 				}
16831 				if (end != NULL)
16832 					*end = '\0';
16833 				end++;
16834 				woal_mac2u8(mac_addr, begin);
16835 				moal_memcpy_ext(priv->phandle,
16836 						aplist->ap_mac[i], mac_addr,
16837 						MLAN_MAC_ADDR_LENGTH,
16838 						MLAN_MAC_ADDR_LENGTH);
16839 			}
16840 		} else {
16841 			PRINTM(MERROR,
16842 			       "AP number is wrong.Support max 8 APs\n");
16843 			ret = -EINVAL;
16844 			goto done;
16845 		}
16846 	}
16847 
16848 	DBG_HEXDUMP(MERROR, "APLIST", (t_u8 *)aplist->ap_mac,
16849 		    aplist->ap_num * MLAN_MAC_ADDR_LENGTH);
16850 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16851 	if (status != MLAN_STATUS_SUCCESS) {
16852 		ret = -EFAULT;
16853 		goto done;
16854 	}
16855 
16856 done:
16857 	if (status != MLAN_STATUS_PENDING)
16858 		kfree(ioctl_req);
16859 
16860 	LEAVE();
16861 	return ret;
16862 }
16863 /**
16864  * @brief               Configure roaming offload to firmware
16865  *
16866  * @param priv          Pointer to moal_private structure
16867  * @param respbuf       Pointer to response buffer
16868  * @param resplen       Response buffer length
16869 
16870  *  @return             Number of bytes written, negative for failure.
16871  */
woal_priv_roam_offload_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16872 static int woal_priv_roam_offload_cfg(moal_private *priv, t_u8 *respbuf,
16873 				      t_u32 respbuflen)
16874 {
16875 	int ret = 0, user_data_len = 0, header_len = 0, data = 0;
16876 	char *begin = NULL, *end = NULL, *pvariable_name = NULL;
16877 	t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
16878 	woal_roam_offload_cfg roam_offload_cfg;
16879 	t_u8 len = 0;
16880 	int count = 0, i = 0;
16881 
16882 	ENTER();
16883 
16884 	if (!priv || !priv->phandle) {
16885 		PRINTM(MERROR, "priv or handle is null\n");
16886 		ret = -EFAULT;
16887 		goto done;
16888 	}
16889 
16890 #ifdef STA_CFG80211
16891 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
16892 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
16893 		ret = -EFAULT;
16894 		goto done;
16895 	}
16896 #endif
16897 #endif
16898 
16899 	memset((char *)&roam_offload_cfg, 0, sizeof(roam_offload_cfg));
16900 	header_len = strlen("CFGROAMOFFLOAD");
16901 	user_data_len = strlen(respbuf) - header_len;
16902 	if (!user_data_len) {
16903 		PRINTM(MERROR, "Invalid number of parameters\n");
16904 		ret = -EINVAL;
16905 		goto done;
16906 	}
16907 	roam_offload_cfg.band_rssi.band_preferred = 0xff;
16908 	roam_offload_cfg.trigger_condition = 0xff;
16909 	end = &respbuf[header_len];
16910 	while (((t_u8 *)end - &respbuf[header_len]) < user_data_len - 1) {
16911 		end++;
16912 		begin = end;
16913 		while (begin && *begin == ' ') {
16914 			begin++;
16915 			end++;
16916 		}
16917 		while (end && *end != ' ' && *end != '\0' && *end != '=')
16918 			end++;
16919 		if (end == begin) {
16920 			PRINTM(MERROR, "Invalid command specified!\n");
16921 			ret = -EINVAL;
16922 			goto done;
16923 		}
16924 		if (end)
16925 			*end = '\0';
16926 		pvariable_name = begin;
16927 
16928 		if (((t_u8 *)end - &respbuf[header_len]) >= user_data_len) {
16929 			PRINTM(MERROR, "Invalid command length!\n");
16930 			ret = -EINVAL;
16931 			goto done;
16932 		}
16933 		end++;
16934 		begin = end;
16935 		while (begin && (*begin == ' ' || *begin == '=')) {
16936 			begin++;
16937 			end++;
16938 		}
16939 		while (end && *end != ' ' && *end != '\0' && *end != '=')
16940 			end++;
16941 		if (end == begin) {
16942 			PRINTM(MERROR, "Invalid command specified!\n");
16943 			ret = -EINVAL;
16944 			goto done;
16945 		}
16946 		if (end != NULL)
16947 			*end = '\0';
16948 		if (pvariable_name && begin) {
16949 			if (strcmp(pvariable_name, "AUTO_RECONNECT") == 0) {
16950 				woal_atoi(&data, begin);
16951 			} else if (strcmp(pvariable_name, "BSSID") == 0) {
16952 				woal_mac2u8(mac_addr, begin);
16953 				moal_memcpy_ext(priv->phandle,
16954 						roam_offload_cfg.bssid,
16955 						mac_addr, MLAN_MAC_ADDR_LENGTH,
16956 						MLAN_MAC_ADDR_LENGTH);
16957 			} else if (strcmp(pvariable_name, "BLACKLIST") == 0) {
16958 				if (woal_atoi(&count, begin) !=
16959 				    MLAN_STATUS_SUCCESS) {
16960 					ret = -EINVAL;
16961 					goto done;
16962 				}
16963 				if (count > 0 && count <= MAX_AP_LIST) {
16964 					roam_offload_cfg.black_list.ap_num =
16965 						count;
16966 					for (i = 0; i < count; i++) {
16967 						end++;
16968 						begin = end;
16969 						while (begin && *begin == ' ') {
16970 							begin++;
16971 							end++;
16972 						}
16973 						while (end && *end != ' ' &&
16974 						       *end != '\0')
16975 							end++;
16976 						if (end == begin) {
16977 							PRINTM(MERROR,
16978 							       "BSSID %d is wrong\n",
16979 							       count);
16980 							ret = -EINVAL;
16981 							goto done;
16982 						}
16983 						if (end != NULL)
16984 							*end = '\0';
16985 						woal_mac2u8(mac_addr, begin);
16986 						moal_memcpy_ext(
16987 							priv->phandle,
16988 							roam_offload_cfg
16989 								.black_list
16990 								.ap_mac[i],
16991 							mac_addr,
16992 							MLAN_MAC_ADDR_LENGTH,
16993 							MLAN_MAC_ADDR_LENGTH);
16994 					}
16995 				} else {
16996 					PRINTM(MERROR,
16997 					       "BSSID number is wrong.Support max %d BSSIDs\n",
16998 					       MAX_AP_LIST);
16999 					ret = -EINVAL;
17000 					goto done;
17001 				}
17002 			} else if (strcmp(pvariable_name, "SSID") == 0) {
17003 				if (woal_atoi(&count, begin) !=
17004 				    MLAN_STATUS_SUCCESS) {
17005 					ret = -EINVAL;
17006 					goto done;
17007 				}
17008 				if (count > 0 && count <= MAX_SSID_NUM) {
17009 					roam_offload_cfg.ssid_list.ssid_num =
17010 						count;
17011 					for (i = 0; i < count; i++) {
17012 						end++;
17013 						begin = end;
17014 						while (begin && *begin == ' ') {
17015 							begin++;
17016 							end++;
17017 						}
17018 						while (end && *end != ' ' &&
17019 						       *end != '\0') {
17020 							end++;
17021 							len++;
17022 						}
17023 						if ((end == begin) ||
17024 						    len >= MLAN_MAX_SSID_LENGTH) {
17025 							PRINTM(MERROR,
17026 							       "SSID %d is wrong\n",
17027 							       count);
17028 							ret = -EINVAL;
17029 							goto done;
17030 						}
17031 						if (end != NULL)
17032 							*end = '\0';
17033 						roam_offload_cfg.ssid_list
17034 							.ssids[i]
17035 							.ssid_len = len + 1;
17036 						moal_memcpy_ext(
17037 							priv->phandle,
17038 							(t_u8 *)&roam_offload_cfg
17039 								.ssid_list
17040 								.ssids[i]
17041 								.ssid,
17042 							begin, len + 1,
17043 							MLAN_MAX_SSID_LENGTH);
17044 						len = 0;
17045 					}
17046 				} else {
17047 					PRINTM(MERROR,
17048 					       "SSID number is wrong.Support max %d SSIDs\n",
17049 					       MAX_SSID_NUM);
17050 					ret = -EINVAL;
17051 					goto done;
17052 				}
17053 			} else if (strcmp(pvariable_name, "RETRY_COUNT") == 0) {
17054 				woal_atoi(&data, begin);
17055 				roam_offload_cfg.retry_count = (t_u8)data;
17056 			} else if (strcmp(pvariable_name,
17057 					  "TRIGGER_CONDITION") == 0) {
17058 				woal_atoi(&data, begin);
17059 				roam_offload_cfg.trigger_condition =
17060 					(t_u16)data;
17061 			} else if (strcmp(pvariable_name, "MAX_RSSI") == 0) {
17062 				woal_atoi(&data, begin);
17063 				roam_offload_cfg.max_rssi = (t_u8)data;
17064 				roam_offload_cfg.rssi_param_set_flag = 1;
17065 			} else if (strcmp(pvariable_name, "MIN_RSSI") == 0) {
17066 				woal_atoi(&data, begin);
17067 				roam_offload_cfg.min_rssi = (t_u8)data;
17068 				roam_offload_cfg.rssi_param_set_flag = 1;
17069 			} else if (strcmp(pvariable_name, "STEP_RSSI") == 0) {
17070 				woal_atoi(&data, begin);
17071 				roam_offload_cfg.step_rssi = (t_u8)data;
17072 				roam_offload_cfg.rssi_param_set_flag = 1;
17073 			} else if (strcmp(pvariable_name, "BAND_PREFER") == 0) {
17074 				woal_atoi(&data, begin);
17075 				roam_offload_cfg.band_rssi.band_preferred =
17076 					(t_u8)data;
17077 				roam_offload_cfg.band_rssi_flag = 1;
17078 			} else if (strcmp(pvariable_name, "RSSI_HYSTERESIS") ==
17079 				   0) {
17080 				woal_atoi(&data, begin);
17081 				roam_offload_cfg.band_rssi.rssi_hysteresis =
17082 					(t_u8)data;
17083 				roam_offload_cfg.band_rssi_flag = 1;
17084 			}
17085 
17086 			else if (strcmp(pvariable_name, "BSSTYPE") == 0) {
17087 				woal_atoi(&data, begin);
17088 				roam_offload_cfg.bgscan_cfg.bss_type =
17089 					(t_u8)data;
17090 				roam_offload_cfg.bgscan_set_flag++;
17091 			} else if (strcmp(pvariable_name, "CHANSPERSCAN") ==
17092 				   0) {
17093 				woal_atoi(&data, begin);
17094 				roam_offload_cfg.bgscan_cfg.channels_per_scan =
17095 					(t_u8)data;
17096 				roam_offload_cfg.bgscan_set_flag++;
17097 			} else if (strcmp(pvariable_name, "BGRPTCONDITION") ==
17098 				   0) {
17099 				woal_atoi(&data, begin);
17100 				roam_offload_cfg.bgscan_cfg.bg_rpt_condition =
17101 					(t_u32)data;
17102 				roam_offload_cfg.bgscan_set_flag++;
17103 			} else if (strcmp(pvariable_name, "SCANINTERVAL") ==
17104 				   0) {
17105 				woal_atoi(&data, begin);
17106 				roam_offload_cfg.bgscan_cfg.scan_interval =
17107 					(t_u32)data;
17108 				roam_offload_cfg.bgscan_set_flag++;
17109 			}
17110 
17111 			else if (strcmp(pvariable_name, "EESMODE") == 0) {
17112 				woal_atoi(&data, begin);
17113 				roam_offload_cfg.ees_cfg.ees_mode = (t_u16)data;
17114 				roam_offload_cfg.ees_param_set_flag++;
17115 			} else if (strcmp(pvariable_name, "EESRPTCONDITION") ==
17116 				   0) {
17117 				woal_atoi(&data, begin);
17118 				roam_offload_cfg.ees_cfg.ees_rpt_condition =
17119 					(t_u16)data;
17120 				roam_offload_cfg.ees_param_set_flag++;
17121 			} else if (strcmp(pvariable_name, "HIGHSCANPERIOD") ==
17122 				   0) {
17123 				woal_atoi(&data, begin);
17124 				roam_offload_cfg.ees_cfg.high_scan_period =
17125 					(t_u16)data;
17126 				roam_offload_cfg.ees_param_set_flag++;
17127 			} else if (strcmp(pvariable_name, "HIGHSCANCOUNT") ==
17128 				   0) {
17129 				woal_atoi(&data, begin);
17130 				roam_offload_cfg.ees_cfg.high_scan_count =
17131 					(t_u16)data;
17132 				roam_offload_cfg.ees_param_set_flag++;
17133 			} else if (strcmp(pvariable_name, "MIDSCANPERIOD") ==
17134 				   0) {
17135 				woal_atoi(&data, begin);
17136 				roam_offload_cfg.ees_cfg.mid_scan_period =
17137 					(t_u16)data;
17138 				roam_offload_cfg.ees_param_set_flag++;
17139 			} else if (strcmp(pvariable_name, "MIDSCANCOUNT") ==
17140 				   0) {
17141 				woal_atoi(&data, begin);
17142 				roam_offload_cfg.ees_cfg.mid_scan_count =
17143 					(t_u16)data;
17144 				roam_offload_cfg.ees_param_set_flag++;
17145 			} else if (strcmp(pvariable_name, "LOWSCANPERIOD") ==
17146 				   0) {
17147 				woal_atoi(&data, begin);
17148 				roam_offload_cfg.ees_cfg.low_scan_period =
17149 					(t_u16)data;
17150 				roam_offload_cfg.ees_param_set_flag++;
17151 			} else if (strcmp(pvariable_name, "LOWSCANCOUNT") ==
17152 				   0) {
17153 				woal_atoi(&data, begin);
17154 				roam_offload_cfg.ees_cfg.low_scan_count =
17155 					(t_u16)data;
17156 				roam_offload_cfg.ees_param_set_flag++;
17157 			}
17158 
17159 			else if (strcmp(pvariable_name, "BCNMISSTHRESHOLD") ==
17160 				 0) {
17161 				woal_atoi(&data, begin);
17162 				roam_offload_cfg.bcn_miss_threshold =
17163 					(t_u8)data;
17164 			}
17165 
17166 			else if (strcmp(pvariable_name,
17167 					"PREBCNMISSTHRESHOLD") == 0) {
17168 				woal_atoi(&data, begin);
17169 				roam_offload_cfg.pre_bcn_miss_threshold =
17170 					(t_u8)data;
17171 			} else if (strcmp(pvariable_name, "REPEATCOUNT") == 0) {
17172 				woal_atoi(&data, begin);
17173 				roam_offload_cfg.repeat_count = (t_u16)data;
17174 			} else {
17175 				PRINTM(MERROR, "Un-support parameter: %s\n",
17176 				       pvariable_name);
17177 				ret = -EINVAL;
17178 				goto done;
17179 			}
17180 		}
17181 	}
17182 	if (priv->phandle->fw_roam_enable == AUTO_RECONNECT) {
17183 		moal_memcpy_ext(priv->phandle,
17184 				priv->phandle->auto_reconnect_bssid,
17185 				roam_offload_cfg.bssid, MLAN_MAC_ADDR_LENGTH,
17186 				sizeof(mlan_802_11_mac_addr));
17187 		moal_memcpy_ext(priv->phandle,
17188 				&priv->phandle->auto_reconnect_ssid,
17189 				&roam_offload_cfg.ssid_list.ssids[0],
17190 				sizeof(mlan_802_11_ssid),
17191 				sizeof(mlan_802_11_ssid));
17192 		priv->phandle->auto_reconnect_retry_count = (t_u8)data;
17193 	} else {
17194 		if (moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS))
17195 			moal_memcpy_ext(priv->phandle,
17196 					(void *)&priv->phandle->fw_roam_params,
17197 					(void *)&roam_offload_cfg,
17198 					sizeof(roam_offload_cfg),
17199 					sizeof(priv->phandle->fw_roam_params));
17200 		else {
17201 			if (woal_config_fw_roaming(priv, ROAM_OFFLOAD_PARAM_CFG,
17202 						   &roam_offload_cfg)) {
17203 				PRINTM(MERROR,
17204 				       "%s: config fw roaming failed \n",
17205 				       __func__);
17206 				ret = -EFAULT;
17207 			}
17208 		}
17209 	}
17210 done:
17211 	LEAVE();
17212 	return ret;
17213 }
17214 
17215 /**
17216  * @brief               Configure roaming SSID passphrase
17217  *
17218  * @param priv          Pointer to moal_private structure
17219  * @param respbuf       Pointer to response buffer
17220  * @param resplen       Response buffer length
17221 
17222  *  @return             Number of bytes written, negative for failure.
17223  */
woal_priv_set_roam_passphrase(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17224 static int woal_priv_set_roam_passphrase(moal_private *priv, t_u8 *respbuf,
17225 					 t_u32 respbuflen)
17226 {
17227 	mlan_ioctl_req *req = NULL;
17228 	mlan_ds_sec_cfg *sec = NULL;
17229 	int ret = 0, action = -1;
17230 	int user_data_len = 0, header_len = 0;
17231 	char *begin, *end, *opt, *item;
17232 	mlan_status status = MLAN_STATUS_SUCCESS;
17233 	woal_roam_offload_cfg roam_offload_cfg;
17234 	mlan_ds_passphrase *ssid_passphrase = NULL;
17235 
17236 	ENTER();
17237 
17238 	if (!priv || !priv->phandle) {
17239 		PRINTM(MERROR, "priv or handle is null\n");
17240 		ret = -EFAULT;
17241 		goto done;
17242 	}
17243 
17244 #ifdef STA_CFG80211
17245 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
17246 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
17247 		ret = -EFAULT;
17248 		goto done;
17249 	}
17250 #endif
17251 #endif
17252 
17253 	memset((char *)&roam_offload_cfg, 0, sizeof(roam_offload_cfg));
17254 	header_len = strlen("SETROAMPASSPHRASE");
17255 	user_data_len = strlen(respbuf) - header_len;
17256 	if (!user_data_len) {
17257 		PRINTM(MERROR, "Invalid number of parameters\n");
17258 		ret = -EINVAL;
17259 		goto done;
17260 	}
17261 
17262 	/* Parse the buf to get the cmd_action */
17263 	begin = respbuf + header_len;
17264 	while (begin && *begin == ' ')
17265 		begin++;
17266 	end = woal_strsep(&begin, ';', '/');
17267 	if (end)
17268 		action = woal_atox(end);
17269 	PRINTM(MMSG, "action= %d\n", action);
17270 	if (action != 1 || end[1] != '\0') {
17271 		PRINTM(MERROR, "Invalid action argument %s\n", end);
17272 		ret = -EINVAL;
17273 		goto done;
17274 	}
17275 
17276 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
17277 	if (req == NULL) {
17278 		ret = -ENOMEM;
17279 		goto done;
17280 	}
17281 
17282 	req->req_id = MLAN_IOCTL_SEC_CFG;
17283 	sec = (mlan_ds_sec_cfg *)req->pbuf;
17284 	sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
17285 	sec->multi_passphrase = 1;
17286 	req->action = MLAN_ACT_SET;
17287 
17288 	/*Parse the buffer like "ssid=xxx passphrase=xxxx;ssid=xxx
17289 	 * passphrase=xxx"*/
17290 	while (begin) {
17291 		while (begin && *begin == ' ')
17292 			begin++;
17293 		end = woal_strsep(&begin, ';', '/');
17294 		item = woal_strsep(&end, ' ', '/');
17295 		opt = woal_strsep(&item, '=', '/');
17296 		while (opt) {
17297 			if (roam_offload_cfg.userset_passphrase >=
17298 			    MAX_SEC_SSID_NUM - 1) {
17299 				PRINTM(MERROR,
17300 				       "Support max %d security SSIDs!\n",
17301 				       MAX_SEC_SSID_NUM);
17302 				break;
17303 			}
17304 			ssid_passphrase =
17305 				&sec->param.roam_passphrase
17306 					 [roam_offload_cfg.userset_passphrase];
17307 			if (!opt || !item || !end) {
17308 				PRINTM(MERROR, "Invalid option\n");
17309 				ret = -EINVAL;
17310 				goto done;
17311 			} else if (!strnicmp(opt, "ssid", strlen(opt))) {
17312 				if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
17313 					PRINTM(MERROR,
17314 					       "SSID length exceeds max length\n");
17315 					ret = -EFAULT;
17316 					goto done;
17317 				}
17318 				ssid_passphrase->ssid.ssid_len = strlen(item);
17319 				strncpy((char *)ssid_passphrase->ssid.ssid,
17320 					item,
17321 					MIN(strlen(item),
17322 					    MLAN_MAX_SSID_LENGTH));
17323 				PRINTM(MINFO, "ssid=%s, len=%d\n",
17324 				       ssid_passphrase->ssid.ssid,
17325 				       (int)ssid_passphrase->ssid.ssid_len);
17326 			} else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
17327 				   req->action == MLAN_ACT_SET) {
17328 				if (strlen(item) < MLAN_MIN_PASSPHRASE_LENGTH ||
17329 				    strlen(item) > MLAN_MAX_PASSPHRASE_LENGTH) {
17330 					PRINTM(MERROR,
17331 					       "Invalid length for passphrase\n");
17332 					ret = -EINVAL;
17333 					goto done;
17334 				}
17335 				ssid_passphrase->psk_type = MLAN_PSK_PASSPHRASE;
17336 				moal_memcpy_ext(priv->phandle,
17337 						ssid_passphrase->psk.passphrase
17338 							.passphrase,
17339 						item, strlen(item),
17340 						MLAN_MAX_PASSPHRASE_LENGTH);
17341 				ssid_passphrase->psk.passphrase.passphrase_len =
17342 					strlen(item);
17343 				PRINTM(MINFO, "passphrase=%s, len=%d\n",
17344 				       ssid_passphrase->psk.passphrase
17345 					       .passphrase,
17346 				       (int)ssid_passphrase->psk.passphrase
17347 					       .passphrase_len);
17348 			} else {
17349 				PRINTM(MERROR, "Invalid option %s\n", opt);
17350 				ret = -EINVAL;
17351 				goto done;
17352 			}
17353 			if (!end || *end == '\0')
17354 				break;
17355 			while (end && *end == ' ')
17356 				end++;
17357 			item = woal_strsep(&end, ' ', '/');
17358 			opt = woal_strsep(&item, '=', '/');
17359 		}
17360 		roam_offload_cfg.userset_passphrase++;
17361 	}
17362 
17363 	if (moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS)) {
17364 		moal_memcpy_ext(priv->phandle,
17365 				(char *)priv->phandle->ssid_passphrase,
17366 				(char *)sec->param.roam_passphrase,
17367 				MAX_SEC_SSID_NUM * sizeof(mlan_ds_passphrase),
17368 				MAX_SEC_SSID_NUM * sizeof(mlan_ds_passphrase));
17369 		priv->phandle->fw_roam_params.userset_passphrase =
17370 			roam_offload_cfg.userset_passphrase;
17371 		goto done;
17372 	}
17373 
17374 	if (woal_config_fw_roaming(priv, ROAM_OFFLOAD_ENABLE,
17375 				   &roam_offload_cfg)) {
17376 		PRINTM(MERROR, "%s: config fw roaming failed \n", __func__);
17377 		ret = -EFAULT;
17378 		goto done;
17379 	}
17380 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17381 	if (status != MLAN_STATUS_SUCCESS) {
17382 		ret = -EFAULT;
17383 		goto done;
17384 	}
17385 
17386 done:
17387 	if (status != MLAN_STATUS_PENDING)
17388 		kfree(req);
17389 	LEAVE();
17390 	return ret;
17391 }
17392 
17393 /**
17394  * @brief               Download start keep alive parameters
17395  *
17396  * @param priv          Pointer to moal_private structure
17397  * @param mkeep_alive_id       keep alive ID number
17398  * @param ip_pke        IP packet from host
17399  * @param ip_pke_len    IP packet length from host
17400  * @param src_mac       Source MAC address
17401  * @param dst_mac       Destination MAC address
17402  * @param period_msec   Send keep alive packet interval
17403 
17404  * @return      0: success  fail otherwise
17405  */
woal_start_mkeep_alive(moal_private * priv,t_u8 mkeep_alive_id,t_u8 * ip_pkt,t_u16 ip_pkt_len,t_u8 * src_mac,t_u8 * dst_mac,t_u32 period_msec,t_u32 retry_interval,t_u8 retry_cnt)17406 int woal_start_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id,
17407 			   t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac,
17408 			   t_u8 *dst_mac, t_u32 period_msec,
17409 			   t_u32 retry_interval, t_u8 retry_cnt)
17410 {
17411 	mlan_ioctl_req *ioctl_req = NULL;
17412 	mlan_ds_misc_cfg *misc = NULL;
17413 	mlan_status status = MLAN_STATUS_SUCCESS;
17414 	int ret = 0;
17415 
17416 	ENTER();
17417 
17418 	if (!priv || !priv->phandle) {
17419 		PRINTM(MERROR, "priv or handle is null\n");
17420 		ret = -EFAULT;
17421 		goto done;
17422 	}
17423 
17424 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17425 	if (ioctl_req == NULL) {
17426 		ret = -ENOMEM;
17427 		goto done;
17428 	}
17429 
17430 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
17431 	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
17432 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
17433 
17434 	if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
17435 		PRINTM(MERROR, "Invalid parameters\n");
17436 		ret = -EFAULT;
17437 		goto done;
17438 	}
17439 
17440 	/* SET operation */
17441 	ioctl_req->action = MLAN_ACT_SET;
17442 	misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
17443 	misc->param.keep_alive.enable = true;
17444 	misc->param.keep_alive.send_interval = period_msec;
17445 	misc->param.keep_alive.retry_interval = retry_interval;
17446 	misc->param.keep_alive.retry_count = retry_cnt;
17447 	moal_memcpy_ext(priv->phandle, misc->param.keep_alive.dst_mac, dst_mac,
17448 			MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17449 	moal_memcpy_ext(priv->phandle, misc->param.keep_alive.src_mac, src_mac,
17450 			MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17451 	misc->param.keep_alive.pkt_len =
17452 		MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
17453 	moal_memcpy_ext(priv->phandle, misc->param.keep_alive.packet, ip_pkt,
17454 			ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
17455 
17456 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17457 	if (status != MLAN_STATUS_SUCCESS) {
17458 		ret = -EFAULT;
17459 		goto done;
17460 	}
17461 
17462 done:
17463 	if (status != MLAN_STATUS_PENDING)
17464 		kfree(ioctl_req);
17465 
17466 	LEAVE();
17467 	return ret;
17468 }
17469 
17470 /**
17471  * @brief               Download stop keep alive parameters
17472  *
17473  * @param priv          Pointer to moal_private structure
17474  * @param mkeep_alive_id       keep alive ID number
17475  * @param ip_pkt        Last packet
17476  * @param ip_pkt_len    Last packet length
17477 
17478  * @return      0: success  fail otherwise
17479  */
woal_stop_mkeep_alive(moal_private * priv,t_u8 mkeep_alive_id,t_u8 reset,t_u8 * ip_pkt,t_u8 * pkt_len)17480 int woal_stop_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id, t_u8 reset,
17481 			  t_u8 *ip_pkt, t_u8 *pkt_len)
17482 {
17483 	mlan_ioctl_req *ioctl_req = NULL;
17484 	mlan_ds_misc_cfg *misc = NULL;
17485 	mlan_status status = MLAN_STATUS_SUCCESS;
17486 	mlan_ds_misc_keep_alive *misc_keep_alive = NULL;
17487 	int ret = 0;
17488 
17489 	ENTER();
17490 
17491 	if (!priv || !priv->phandle) {
17492 		PRINTM(MERROR, "priv or handle is null\n");
17493 		ret = -EFAULT;
17494 		goto done;
17495 	}
17496 
17497 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17498 	if (ioctl_req == NULL) {
17499 		ret = -ENOMEM;
17500 		goto done;
17501 	}
17502 
17503 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
17504 	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
17505 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
17506 	misc_keep_alive = &misc->param.keep_alive;
17507 
17508 	if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
17509 		PRINTM(MERROR, "Invalid parameters\n");
17510 		ret = -EFAULT;
17511 		goto done;
17512 	}
17513 
17514 	/* GET operation */
17515 	ioctl_req->action = MLAN_ACT_GET;
17516 	misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
17517 	misc_keep_alive->enable = false;
17518 
17519 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17520 	if (status != MLAN_STATUS_SUCCESS) {
17521 		ret = -EFAULT;
17522 		goto done;
17523 	}
17524 
17525 	if (!misc_keep_alive->enable) {
17526 		PRINTM(MERROR, "ID %d is already stop\n", mkeep_alive_id);
17527 		goto done;
17528 	}
17529 
17530 	if (reset)
17531 		ioctl_req->action = MLAN_ACT_RESET;
17532 	else
17533 		/* SET operation */
17534 		ioctl_req->action = MLAN_ACT_SET;
17535 	misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
17536 	misc_keep_alive->enable = false;
17537 
17538 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17539 	if (status != MLAN_STATUS_SUCCESS) {
17540 		ret = -EFAULT;
17541 		goto done;
17542 	}
17543 
17544 #ifdef STA_CFG80211
17545 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
17546 	if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
17547 		ret = woal_mkeep_alive_vendor_event(priv,
17548 						    &misc->param.keep_alive);
17549 		if (ret)
17550 			PRINTM(MERROR,
17551 			       "Keep alive vendor event upload failed\n");
17552 	}
17553 #endif
17554 #endif
17555 	if (pkt_len) {
17556 		*pkt_len = MIN(misc_keep_alive->pkt_len,
17557 			       (MKEEP_ALIVE_IP_PKT_MAX - 1));
17558 		PRINTM(MINFO, "keep alive stop pkt_len is %d\n", *pkt_len);
17559 	}
17560 	if (*pkt_len && ip_pkt)
17561 		moal_memcpy_ext(priv->phandle, ip_pkt, misc_keep_alive->packet,
17562 				*pkt_len, *pkt_len);
17563 
17564 done:
17565 	if (status != MLAN_STATUS_PENDING)
17566 		kfree(ioctl_req);
17567 
17568 	LEAVE();
17569 	return ret;
17570 }
17571 
17572 /**
17573  * @brief               Save cloud keep alive params in driver handle
17574  *
17575  * @param priv          Pointer to moal_private structure
17576  * @params              Other params for keep alive
17577 
17578  *  @return             Number of bytes written, negative for failure.
17579  */
woal_priv_save_cloud_keep_alive_params(moal_private * priv,t_u8 mkeep_alive_id,t_u8 enable,t_u16 ether_type,t_u8 * ip_pkt,t_u16 ip_pkt_len,t_u8 * src_mac,t_u8 * dst_mac,t_u32 period_msec,t_u32 retry_interval,t_u8 retry_cnt)17580 int woal_priv_save_cloud_keep_alive_params(moal_private *priv,
17581 					   t_u8 mkeep_alive_id, t_u8 enable,
17582 					   t_u16 ether_type, t_u8 *ip_pkt,
17583 					   t_u16 ip_pkt_len, t_u8 *src_mac,
17584 					   t_u8 *dst_mac, t_u32 period_msec,
17585 					   t_u32 retry_interval, t_u8 retry_cnt)
17586 
17587 {
17588 	mlan_ioctl_req *ioctl_req = NULL;
17589 	mlan_ds_misc_cfg *misc = NULL;
17590 	int ret = 0;
17591 	mlan_ds_misc_keep_alive *keep_alive = NULL;
17592 	moal_handle *phandle = NULL;
17593 
17594 	ENTER();
17595 
17596 	if (!priv || !priv->phandle) {
17597 		PRINTM(MERROR, "priv or handle is null\n");
17598 		ret = -EFAULT;
17599 		goto done;
17600 	}
17601 	phandle = priv->phandle;
17602 
17603 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17604 	if (ioctl_req == NULL) {
17605 		ret = -ENOMEM;
17606 		goto done;
17607 	}
17608 
17609 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
17610 	misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
17611 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
17612 
17613 	if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
17614 		PRINTM(MERROR, "Invalid parameters\n");
17615 		ret = -EINVAL;
17616 		goto done;
17617 	}
17618 
17619 	/* GET operation */
17620 	ioctl_req->action = MLAN_ACT_GET;
17621 	misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
17622 	misc->param.keep_alive.enable = true;
17623 
17624 	ret = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17625 	if (ret != MLAN_STATUS_SUCCESS) {
17626 		ret = -EFAULT;
17627 		goto done;
17628 	}
17629 
17630 	if (misc->param.keep_alive.enable) {
17631 		PRINTM(MERROR, "ID %d is in use\n", mkeep_alive_id);
17632 		ret = -EINVAL;
17633 		goto done;
17634 	}
17635 
17636 	keep_alive = &phandle->keep_alive[mkeep_alive_id];
17637 	keep_alive->mkeep_alive_id = mkeep_alive_id;
17638 	keep_alive->enable = enable;
17639 	if (enable) {
17640 		keep_alive->cached = true;
17641 		keep_alive->send_interval = period_msec;
17642 		keep_alive->retry_interval = retry_interval;
17643 		keep_alive->retry_count = retry_cnt;
17644 		moal_memcpy_ext(phandle, keep_alive->dst_mac, dst_mac,
17645 				MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17646 		moal_memcpy_ext(phandle, keep_alive->src_mac, src_mac,
17647 				MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17648 		keep_alive->pkt_len = MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
17649 		moal_memcpy_ext(phandle, keep_alive->packet, ip_pkt, ip_pkt_len,
17650 				MKEEP_ALIVE_IP_PKT_MAX);
17651 		if (ether_type)
17652 			keep_alive->ether_type = ether_type;
17653 		else
17654 			keep_alive->ether_type = 0;
17655 	}
17656 
17657 done:
17658 	if (ret != MLAN_STATUS_PENDING)
17659 		kfree(ioctl_req);
17660 
17661 	LEAVE();
17662 	return ret;
17663 }
17664 
17665 /**
17666  * @brief               Cloud keep alive feature
17667  *
17668  * @param priv          Pointer to moal_private structure
17669  * @param respbuf       Pointer to response buffer
17670  * @param resplen       Response buffer length
17671 
17672  *  @return             Number of bytes written, negative for failure.
17673  */
woal_priv_cloud_keep_alive(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17674 static int woal_priv_cloud_keep_alive(moal_private *priv, t_u8 *respbuf,
17675 				      t_u32 respbuflen)
17676 {
17677 	int ret = 0;
17678 	cloud_keep_alive *keep_alive = NULL;
17679 	int header_len = 0;
17680 
17681 	ENTER();
17682 
17683 	header_len = strlen(PRIV_CMD_CLOUD_KEEP_ALIVE);
17684 
17685 	keep_alive = (cloud_keep_alive *)(respbuf + header_len);
17686 
17687 	if (keep_alive->enable) {
17688 		ret = woal_priv_save_cloud_keep_alive_params(
17689 			priv, keep_alive->mkeep_alive_id, keep_alive->enable, 0,
17690 			keep_alive->pkt, keep_alive->pkt_len,
17691 			keep_alive->src_mac, keep_alive->dst_mac,
17692 			keep_alive->sendInterval, keep_alive->retryInterval,
17693 			keep_alive->retryCount);
17694 	} else {
17695 		if (0 != woal_stop_mkeep_alive(priv, keep_alive->mkeep_alive_id,
17696 					       keep_alive->reset,
17697 					       keep_alive->pkt,
17698 					       &keep_alive->pkt_len)) {
17699 			ret = -EFAULT;
17700 			return ret;
17701 		}
17702 		ret = respbuflen;
17703 	}
17704 
17705 	LEAVE();
17706 	return ret;
17707 }
17708 
17709 /**
17710  *  @brief Set/Get static rx abort config
17711  *
17712  *  @param priv         A pointer to moal_private structure
17713  *  @param respbuf      A pointer to response buffer
17714  *  @param respbuflen   Available length of response buffer
17715  *
17716  *  @return             Number of bytes written, negative for failure.
17717  */
woal_priv_rx_abort_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17718 static int woal_priv_rx_abort_cfg(moal_private *priv, t_u8 *respbuf,
17719 				  t_u32 respbuflen)
17720 {
17721 	mlan_ioctl_req *req = NULL;
17722 	mlan_ds_misc_cfg *misc = NULL;
17723 	int ret = 0;
17724 	int data[2] = {0};
17725 	int header_len = 0, user_data_len = 0;
17726 	mlan_status status = MLAN_STATUS_SUCCESS;
17727 
17728 	ENTER();
17729 
17730 	if (!respbuf) {
17731 		PRINTM(MERROR, "response buffer is not available!\n");
17732 		ret = -EINVAL;
17733 		goto done;
17734 	}
17735 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG);
17736 	user_data_len = strlen(respbuf) - header_len;
17737 
17738 	/* Allocate an IOCTL request buffer */
17739 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17740 	if (req == NULL) {
17741 		ret = -ENOMEM;
17742 		goto done;
17743 	}
17744 
17745 	/* Fill request buffer */
17746 	misc = (mlan_ds_misc_cfg *)req->pbuf;
17747 	misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG;
17748 	req->req_id = MLAN_IOCTL_MISC_CFG;
17749 	if ((int)strlen(respbuf) == header_len) {
17750 		/* GET operation */
17751 		user_data_len = 0;
17752 		req->action = MLAN_ACT_GET;
17753 	} else {
17754 		/* SET operation */
17755 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
17756 				&user_data_len);
17757 		if (user_data_len > 2 ||
17758 		    (data[0] == MTRUE && user_data_len != 2)) {
17759 			PRINTM(MERROR, "Invalid number of args!\n");
17760 			ret = -EINVAL;
17761 			goto done;
17762 		}
17763 		if (data[0] == MTRUE && data[1] > 0x7f) {
17764 			PRINTM(MERROR, "Invalid threshold value\n");
17765 			ret = -EINVAL;
17766 			goto done;
17767 		}
17768 		misc->param.rx_abort_cfg.enable = (t_u8)data[0];
17769 		if (user_data_len == 2)
17770 			misc->param.rx_abort_cfg.rssi_threshold = (t_s8)data[1];
17771 		req->action = MLAN_ACT_SET;
17772 	}
17773 	/* Send IOCTL request to MLAN */
17774 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17775 	if (status != MLAN_STATUS_SUCCESS) {
17776 		ret = -EFAULT;
17777 		goto done;
17778 	}
17779 
17780 	data[0] = misc->param.rx_abort_cfg.enable;
17781 	data[1] = misc->param.rx_abort_cfg.rssi_threshold;
17782 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
17783 			respbuflen);
17784 	ret = sizeof(data);
17785 done:
17786 	if (status != MLAN_STATUS_PENDING)
17787 		kfree(req);
17788 
17789 	LEAVE();
17790 	return ret;
17791 }
17792 
17793 /**
17794  *  @brief Set/Get dynamic rx abort config
17795  *
17796  *  @param priv         A pointer to moal_private structure
17797  *  @param respbuf      A pointer to response buffer
17798  *  @param respbuflen   Available length of response buffer
17799  *
17800  *  @return             Number of bytes written, negative for failure.
17801  */
woal_priv_rx_abort_cfg_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17802 static int woal_priv_rx_abort_cfg_ext(moal_private *priv, t_u8 *respbuf,
17803 				      t_u32 respbuflen)
17804 {
17805 	mlan_ioctl_req *req = NULL;
17806 	mlan_ds_misc_cfg *misc = NULL;
17807 	int ret = 0;
17808 	int data[3] = {0};
17809 	int header_len = 0, user_data_len = 0;
17810 	mlan_status status = MLAN_STATUS_SUCCESS;
17811 
17812 	ENTER();
17813 
17814 	if (!respbuf) {
17815 		PRINTM(MERROR, "response buffer is not available!\n");
17816 		ret = -EINVAL;
17817 		goto done;
17818 	}
17819 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG_EXT);
17820 	user_data_len = strlen(respbuf) - header_len;
17821 
17822 	/* Allocate an IOCTL request buffer */
17823 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17824 	if (req == NULL) {
17825 		ret = -ENOMEM;
17826 		goto done;
17827 	}
17828 
17829 	/* Fill request buffer */
17830 	misc = (mlan_ds_misc_cfg *)req->pbuf;
17831 	misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG_EXT;
17832 	req->req_id = MLAN_IOCTL_MISC_CFG;
17833 	if ((int)strlen(respbuf) == header_len) {
17834 		/* GET operation */
17835 		user_data_len = 0;
17836 		req->action = MLAN_ACT_GET;
17837 	} else {
17838 		/* SET operation */
17839 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
17840 				&user_data_len);
17841 		if (user_data_len > 3 ||
17842 		    (data[0] == MTRUE && user_data_len != 3)) {
17843 			PRINTM(MERROR, "Invalid number of args!\n");
17844 			ret = -EINVAL;
17845 			goto done;
17846 		}
17847 		if (data[0] == MTRUE) {
17848 			if (data[1] > 0x7f) {
17849 				PRINTM(MERROR, "Invalid margin value\n");
17850 				ret = -EINVAL;
17851 				goto done;
17852 			}
17853 			if (data[2] > 0x7f) {
17854 				PRINTM(MERROR,
17855 				       "Invalid ceil threshold value\n");
17856 				ret = -EINVAL;
17857 				goto done;
17858 			}
17859 		}
17860 		misc->param.rx_abort_cfg_ext.enable = (t_u8)data[0];
17861 		if (user_data_len > 1) {
17862 			misc->param.rx_abort_cfg_ext.rssi_margin =
17863 				(t_s8)data[1];
17864 			misc->param.rx_abort_cfg_ext.ceil_rssi_threshold =
17865 				(t_s8)data[2];
17866 		}
17867 		req->action = MLAN_ACT_SET;
17868 	}
17869 	/* Send IOCTL request to MLAN */
17870 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17871 	if (status != MLAN_STATUS_SUCCESS) {
17872 		ret = -EFAULT;
17873 		goto done;
17874 	}
17875 
17876 	data[0] = misc->param.rx_abort_cfg_ext.enable;
17877 	data[1] = misc->param.rx_abort_cfg_ext.rssi_margin;
17878 	data[2] = misc->param.rx_abort_cfg_ext.ceil_rssi_threshold;
17879 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
17880 			respbuflen);
17881 	ret = sizeof(data);
17882 done:
17883 	if (status != MLAN_STATUS_PENDING)
17884 		kfree(req);
17885 
17886 	LEAVE();
17887 	return ret;
17888 }
17889 
17890 /**
17891  *  @brief Enable/Disable Un-associated Dot11mc FTM Frame exchanges
17892  *
17893  *  @param priv         A pointer to moal_private structure
17894  *  @param respbuf      A pointer to response buffer
17895  *  @param respbuflen   Available length of response buffer
17896  *
17897  *  @return             Number of bytes written, negative for failure.
17898  */
woal_priv_dot11mc_unassoc_ftm_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17899 static int woal_priv_dot11mc_unassoc_ftm_cfg(moal_private *priv, t_u8 *respbuf,
17900 					     t_u32 respbuflen)
17901 {
17902 	mlan_ioctl_req *req = NULL;
17903 	mlan_ds_misc_cfg *misc = NULL;
17904 	int ret = 0;
17905 	int data[1] = {0};
17906 	int header_len = 0, user_data_len = 0;
17907 	mlan_status status = MLAN_STATUS_SUCCESS;
17908 
17909 	ENTER();
17910 
17911 	if (!respbuf) {
17912 		PRINTM(MERROR, "response buffer is not available!\n");
17913 		ret = -EINVAL;
17914 		goto done;
17915 	}
17916 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG);
17917 	user_data_len = strlen(respbuf) - header_len;
17918 
17919 	/* Allocate an IOCTL request buffer */
17920 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17921 	if (req == NULL) {
17922 		ret = -ENOMEM;
17923 		goto done;
17924 	}
17925 
17926 	/* Fill request buffer */
17927 	misc = (mlan_ds_misc_cfg *)req->pbuf;
17928 	misc->sub_command = MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG;
17929 	req->req_id = MLAN_IOCTL_MISC_CFG;
17930 	if ((int)strlen(respbuf) == header_len) {
17931 		/* GET operation */
17932 		user_data_len = 0;
17933 		req->action = MLAN_ACT_GET;
17934 	} else {
17935 		/* SET operation */
17936 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
17937 				&user_data_len);
17938 		if (user_data_len > 1) {
17939 			PRINTM(MERROR, "Invalid number of args!\n");
17940 			ret = -EINVAL;
17941 			goto done;
17942 		}
17943 		if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
17944 			PRINTM(MERROR, "Invalid state for unassoc ftm\n");
17945 			ret = -EINVAL;
17946 			goto done;
17947 		}
17948 		misc->param.dot11mc_unassoc_ftm_cfg.state = (t_u16)data[0];
17949 		req->action = MLAN_ACT_SET;
17950 	}
17951 	/* Send IOCTL request to MLAN */
17952 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17953 	if (status != MLAN_STATUS_SUCCESS) {
17954 		ret = -EFAULT;
17955 		goto done;
17956 	}
17957 
17958 	data[0] = misc->param.dot11mc_unassoc_ftm_cfg.state;
17959 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
17960 			respbuflen);
17961 	ret = sizeof(data);
17962 done:
17963 	if (status != MLAN_STATUS_PENDING)
17964 		kfree(req);
17965 
17966 	LEAVE();
17967 	return ret;
17968 }
17969 
17970 /**
17971  *  @brief Set/Get Tx  AMPDU protection mode
17972  *
17973  *  @param priv         A pointer to moal_private structure
17974  *  @param respbuf      A pointer to response buffer
17975  *  @param respbuflen   Available length of response buffer
17976  *
17977  *  @return             Number of bytes written, negative for failure.
17978  */
woal_priv_tx_ampdu_prot_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17979 static int woal_priv_tx_ampdu_prot_mode(moal_private *priv, t_u8 *respbuf,
17980 					t_u32 respbuflen)
17981 {
17982 	mlan_ioctl_req *req = NULL;
17983 	mlan_ds_misc_cfg *misc = NULL;
17984 	int ret = 0;
17985 	int data[1] = {0};
17986 	int header_len = 0, user_data_len = 0;
17987 	mlan_status status = MLAN_STATUS_SUCCESS;
17988 
17989 	ENTER();
17990 
17991 	if (!respbuf) {
17992 		PRINTM(MERROR, "response buffer is not available!\n");
17993 		ret = -EINVAL;
17994 		goto done;
17995 	}
17996 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AMPDU_PROT_MODE);
17997 	user_data_len = strlen(respbuf) - header_len;
17998 
17999 	/* Allocate an IOCTL request buffer */
18000 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18001 	if (req == NULL) {
18002 		ret = -ENOMEM;
18003 		goto done;
18004 	}
18005 
18006 	/* Fill request buffer */
18007 	misc = (mlan_ds_misc_cfg *)req->pbuf;
18008 	misc->sub_command = MLAN_OID_MISC_TX_AMPDU_PROT_MODE;
18009 	req->req_id = MLAN_IOCTL_MISC_CFG;
18010 	if ((int)strlen(respbuf) == header_len) {
18011 		/* GET operation */
18012 		user_data_len = 0;
18013 		req->action = MLAN_ACT_GET;
18014 	} else {
18015 		/* SET operation */
18016 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18017 				&user_data_len);
18018 		if (user_data_len > 1) {
18019 			PRINTM(MERROR, "Invalid number of args!\n");
18020 			ret = -EINVAL;
18021 			goto done;
18022 		}
18023 		if (data[0] > TX_AMPDU_DYNAMIC_RTS_CTS) {
18024 			PRINTM(MERROR, "Invalid protection mode\n");
18025 			ret = -EINVAL;
18026 			goto done;
18027 		}
18028 		misc->param.tx_ampdu_prot_mode.mode = (t_u16)data[0];
18029 		req->action = MLAN_ACT_SET;
18030 	}
18031 	/* Send IOCTL request to MLAN */
18032 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18033 	if (status != MLAN_STATUS_SUCCESS) {
18034 		ret = -EFAULT;
18035 		goto done;
18036 	}
18037 
18038 	data[0] = misc->param.tx_ampdu_prot_mode.mode;
18039 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
18040 			respbuflen);
18041 	ret = sizeof(data);
18042 done:
18043 	if (status != MLAN_STATUS_PENDING)
18044 		kfree(req);
18045 
18046 	LEAVE();
18047 	return ret;
18048 }
18049 
18050 /**
18051  *  @brief Set/Get Tx rate adapt config
18052  *
18053  *  @param priv         A pointer to moal_private structure
18054  *  @param respbuf      A pointer to response buffer
18055  *  @param respbuflen   Available length of response buffer
18056  *
18057  *  @return             Number of bytes written, negative for failure.
18058  */
woal_priv_rate_adapt_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18059 static int woal_priv_rate_adapt_cfg(moal_private *priv, t_u8 *respbuf,
18060 				    t_u32 respbuflen)
18061 {
18062 	mlan_ioctl_req *req = NULL;
18063 	mlan_ds_misc_cfg *misc = NULL;
18064 	int ret = 0;
18065 	int data[4] = {0};
18066 	int header_len = 0, user_data_len = 0;
18067 	mlan_status status = MLAN_STATUS_SUCCESS;
18068 
18069 	ENTER();
18070 
18071 	if (!respbuf) {
18072 		PRINTM(MERROR, "response buffer is not available!\n");
18073 		ret = -EINVAL;
18074 		goto done;
18075 	}
18076 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RATE_ADAPT_CFG);
18077 	user_data_len = strlen(respbuf) - header_len;
18078 
18079 	/* Allocate an IOCTL request buffer */
18080 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18081 	if (req == NULL) {
18082 		ret = -ENOMEM;
18083 		goto done;
18084 	}
18085 
18086 	/* Fill request buffer */
18087 	misc = (mlan_ds_misc_cfg *)req->pbuf;
18088 	misc->sub_command = MLAN_OID_MISC_RATE_ADAPT_CFG;
18089 	req->req_id = MLAN_IOCTL_MISC_CFG;
18090 	if ((int)strlen(respbuf) == header_len) {
18091 		/* GET operation */
18092 		user_data_len = 0;
18093 		req->action = MLAN_ACT_GET;
18094 	} else {
18095 		/* SET operation */
18096 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18097 				&user_data_len);
18098 		if (user_data_len < 1) {
18099 			PRINTM(MERROR, "Invalid number of args!\n");
18100 			ret = -EINVAL;
18101 			goto done;
18102 		}
18103 		if (data[0] > RATEADAPT_ALGO_SR) {
18104 			PRINTM(MERROR, "Invalid Rateadapt Algorithm\n");
18105 			ret = -EINVAL;
18106 			goto done;
18107 		}
18108 		if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
18109 			if ((data[1] & data[2]) == 0xff) {
18110 				/* dynamic CCA noise based rate adapation enable
18111 				 * request nothing to do here
18112 				 */
18113 			} else if (data[1] > 100 || data[2] > 100) {
18114 				PRINTM(MERROR,
18115 				       "Invalid success rate threshold value\n");
18116 				ret = -EINVAL;
18117 				goto done;
18118 			}
18119 			if (data[3] < 10 || data[3] > 0xffff) {
18120 				PRINTM(MERROR, "Invalid interval value\n");
18121 				ret = -EINVAL;
18122 				goto done;
18123 			}
18124 		}
18125 		misc->param.rate_adapt_cfg.sr_rateadapt = (t_u8)data[0];
18126 		if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
18127 			misc->param.rate_adapt_cfg.ra_low_thresh =
18128 				(t_u8)data[1];
18129 			misc->param.rate_adapt_cfg.ra_high_thresh =
18130 				(t_u8)data[2];
18131 			misc->param.rate_adapt_cfg.ra_interval = (t_u16)data[3];
18132 		}
18133 		req->action = MLAN_ACT_SET;
18134 	}
18135 	/* Send IOCTL request to MLAN */
18136 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18137 	if (status != MLAN_STATUS_SUCCESS) {
18138 		ret = -EFAULT;
18139 		goto done;
18140 	}
18141 	data[0] = misc->param.rate_adapt_cfg.sr_rateadapt;
18142 	data[1] = misc->param.rate_adapt_cfg.ra_low_thresh;
18143 	data[2] = misc->param.rate_adapt_cfg.ra_high_thresh;
18144 	data[3] = misc->param.rate_adapt_cfg.ra_interval;
18145 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
18146 			respbuflen);
18147 	ret = sizeof(data);
18148 done:
18149 	if (status != MLAN_STATUS_PENDING)
18150 		kfree(req);
18151 
18152 	LEAVE();
18153 	return ret;
18154 }
18155 
18156 /**
18157  *  @brief Set/Get global cck desense config
18158  *
18159  *  @param priv         A pointer to moal_private structure
18160  *  @param respbuf      A pointer to response buffer
18161  *  @param respbuflen   Available length of response buffer
18162  *
18163  *  @return             Number of bytes written, negative for failure.
18164  */
woal_priv_cck_desense_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18165 static int woal_priv_cck_desense_cfg(moal_private *priv, t_u8 *respbuf,
18166 				     t_u32 respbuflen)
18167 {
18168 	mlan_ioctl_req *req = NULL;
18169 	mlan_ds_misc_cfg *misc = NULL;
18170 	int ret = 0;
18171 	int data[5] = {0};
18172 	int header_len = 0, user_data_len = 0;
18173 	mlan_status status = MLAN_STATUS_SUCCESS;
18174 
18175 	ENTER();
18176 
18177 	if (!respbuf) {
18178 		PRINTM(MERROR, "response buffer is not available!\n");
18179 		ret = -EINVAL;
18180 		goto done;
18181 	}
18182 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CCK_DESENSE_CFG);
18183 	user_data_len = strlen(respbuf) - header_len;
18184 
18185 	/* Allocate an IOCTL request buffer */
18186 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18187 	if (req == NULL) {
18188 		ret = -ENOMEM;
18189 		goto done;
18190 	}
18191 
18192 	/* Fill request buffer */
18193 	misc = (mlan_ds_misc_cfg *)req->pbuf;
18194 	misc->sub_command = MLAN_OID_MISC_CCK_DESENSE_CFG;
18195 	req->req_id = MLAN_IOCTL_MISC_CFG;
18196 	if ((int)strlen(respbuf) == header_len) {
18197 		/* GET operation */
18198 		user_data_len = 0;
18199 		req->action = MLAN_ACT_GET;
18200 	} else {
18201 		/* SET operation */
18202 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18203 				&user_data_len);
18204 		if (user_data_len > 5) {
18205 			PRINTM(MERROR, "Invalid number of args!\n");
18206 			ret = -EINVAL;
18207 			goto done;
18208 		}
18209 		if (data[0] > CCK_DESENSE_MODE_DYN_ENH) {
18210 			PRINTM(MERROR, "Invalid cck desense mode\n");
18211 			ret = -EINVAL;
18212 			goto done;
18213 		}
18214 		if ((data[0] == CCK_DESENSE_MODE_DISABLED &&
18215 		     user_data_len > 1) ||
18216 		    (data[0] == CCK_DESENSE_MODE_DYNAMIC &&
18217 		     user_data_len != 3) ||
18218 		    (data[0] == CCK_DESENSE_MODE_DYN_ENH &&
18219 		     (user_data_len < 3 || user_data_len == 4))) {
18220 			PRINTM(MERROR,
18221 			       "Invalid number of args for requested mode\n");
18222 			ret = -EINVAL;
18223 			goto done;
18224 		}
18225 		if (user_data_len > 1) {
18226 			if (data[1] > 0x7f) {
18227 				PRINTM(MERROR, "Invalid margin value\n");
18228 				ret = -EINVAL;
18229 				goto done;
18230 			}
18231 			if (data[2] > 0x7f) {
18232 				PRINTM(MERROR,
18233 				       "Invalid ceil threshold value\n");
18234 				ret = -EINVAL;
18235 				goto done;
18236 			}
18237 		}
18238 		if (user_data_len > 3) {
18239 			if (data[3] > 0xff || data[4] > 0xff) {
18240 				PRINTM(MERROR,
18241 				       "Invalid ON/OFF intervals value\n");
18242 				ret = -EINVAL;
18243 				goto done;
18244 			}
18245 		}
18246 		misc->param.cck_desense_cfg.mode = (t_u8)data[0];
18247 		if (user_data_len > 1) {
18248 			misc->param.cck_desense_cfg.margin = (t_s8)data[1];
18249 			misc->param.cck_desense_cfg.ceil_thresh = (t_s8)data[2];
18250 		}
18251 		if (data[0] == CCK_DESENSE_MODE_DYN_ENH) {
18252 			if (user_data_len > 3) {
18253 				misc->param.cck_desense_cfg.num_on_intervals =
18254 					(t_u8)data[3];
18255 				misc->param.cck_desense_cfg.num_off_intervals =
18256 					(t_u8)data[4];
18257 			} else {
18258 				/* set these to 0xff. This will indicate the FW
18259 				 * to use previously set values.
18260 				 */
18261 				misc->param.cck_desense_cfg.num_on_intervals =
18262 					0xff;
18263 				misc->param.cck_desense_cfg.num_off_intervals =
18264 					0xff;
18265 			}
18266 		}
18267 		req->action = MLAN_ACT_SET;
18268 	}
18269 	/* Send IOCTL request to MLAN */
18270 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18271 	if (status != MLAN_STATUS_SUCCESS) {
18272 		ret = -EFAULT;
18273 		goto done;
18274 	}
18275 
18276 	data[0] = misc->param.cck_desense_cfg.mode;
18277 	data[1] = misc->param.cck_desense_cfg.margin;
18278 	data[2] = misc->param.cck_desense_cfg.ceil_thresh;
18279 	data[3] = misc->param.cck_desense_cfg.num_on_intervals;
18280 	data[4] = misc->param.cck_desense_cfg.num_off_intervals;
18281 	moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
18282 			respbuflen);
18283 	ret = sizeof(data);
18284 
18285 done:
18286 	if (status != MLAN_STATUS_PENDING)
18287 		kfree(req);
18288 
18289 	LEAVE();
18290 	return ret;
18291 }
18292 
18293 /**
18294  * @brief               set/get low power mode
18295  *
18296  * @param priv          Pointer to moal_private structure
18297  * @param respbuf       Pointer to response buffer
18298  * @param resplen       Response buffer length
18299 
18300  *  @return             Number of bytes written, negative for failure.
18301  */
woal_priv_set_get_lpm(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18302 static int woal_priv_set_get_lpm(moal_private *priv, t_u8 *respbuf,
18303 				 t_u32 respbuflen)
18304 {
18305 	int ret = 0;
18306 	mlan_ioctl_req *req = NULL;
18307 	mlan_ds_power_cfg *cfg = NULL;
18308 	int data = 0;
18309 	int user_data_len = 0, header_len = 0;
18310 	mlan_status status = MLAN_STATUS_SUCCESS;
18311 
18312 	ENTER();
18313 
18314 	if (IS_CARD9098(priv->phandle->card_type) ||
18315 	    IS_CARD9097(priv->phandle->card_type)) {
18316 		header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_LPM);
18317 		if ((int)strlen(respbuf) == header_len) {
18318 			/* GET operation */
18319 			user_data_len = 0;
18320 		} else {
18321 			/* SET operation */
18322 			parse_arguments(respbuf + header_len, &data, 1,
18323 					&user_data_len);
18324 		}
18325 		if (user_data_len >= 2) {
18326 			PRINTM(MERROR, "Too many arguments\n");
18327 			ret = -EINVAL;
18328 			goto done;
18329 		} else {
18330 			req = woal_alloc_mlan_ioctl_req(
18331 				sizeof(mlan_ds_power_cfg));
18332 			if (req == NULL) {
18333 				ret = -ENOMEM;
18334 				goto done;
18335 			}
18336 
18337 			cfg = (mlan_ds_power_cfg *)req->pbuf;
18338 			if (user_data_len == 0) {
18339 				req->action = MLAN_ACT_GET;
18340 			} else {
18341 				cfg->param.lpm = data;
18342 				req->action = MLAN_ACT_SET;
18343 			}
18344 		}
18345 		cfg->sub_command = MLAN_OID_POWER_LOW_POWER_MODE;
18346 		req->req_id = MLAN_IOCTL_POWER_CFG;
18347 
18348 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18349 		if (status != MLAN_STATUS_SUCCESS) {
18350 			ret = -EFAULT;
18351 			goto done;
18352 		}
18353 
18354 		data = cfg->param.lpm;
18355 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
18356 				sizeof(data), respbuflen);
18357 		ret = sizeof(data);
18358 	} else
18359 		PRINTM(MERROR, "Low power mode command is not supported!\n");
18360 
18361 done:
18362 	if (status != MLAN_STATUS_PENDING)
18363 		kfree(req);
18364 	LEAVE();
18365 	return ret;
18366 }
18367 
18368 /**
18369  *  @brief Set/Get HW ARB config
18370  *
18371  *  @param priv         A pointer to moal_private structure
18372  *  @param respbuf      A pointer to response buffer
18373  *  @param respbuflen   Available length of response buffer
18374  *
18375  *  @return             Number of bytes written, negative for failure.
18376  */
woal_priv_arbcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18377 static int woal_priv_arbcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
18378 {
18379 	mlan_ioctl_req *req = NULL;
18380 	mlan_ds_misc_cfg *misc = NULL;
18381 	int ret = 0;
18382 	int data[1];
18383 	int header_len = 0, user_data_len = 0;
18384 	mlan_status status = MLAN_STATUS_SUCCESS;
18385 
18386 	ENTER();
18387 
18388 	if (!respbuf) {
18389 		PRINTM(MERROR, "response buffer is not available!\n");
18390 		ret = -EINVAL;
18391 		goto done;
18392 	}
18393 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ARB_CFG);
18394 	user_data_len = strlen(respbuf) - header_len;
18395 
18396 	/* Allocate an IOCTL request buffer */
18397 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18398 	if (req == NULL) {
18399 		ret = -ENOMEM;
18400 		goto done;
18401 	}
18402 	/* Fill request buffer */
18403 	misc = (mlan_ds_misc_cfg *)req->pbuf;
18404 	misc->sub_command = MLAN_OID_MISC_ARB_CONFIG;
18405 	req->req_id = MLAN_IOCTL_MISC_CFG;
18406 	if ((int)strlen(respbuf) == header_len) {
18407 		/* GET operation */
18408 		user_data_len = 0;
18409 		req->action = MLAN_ACT_GET;
18410 	} else {
18411 		/* SET operation */
18412 		parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18413 				&user_data_len);
18414 		if (user_data_len != 1) {
18415 			PRINTM(MERROR, "Invalid Parameter\n");
18416 			ret = -EFAULT;
18417 			goto done;
18418 		}
18419 		if (data[0] < 0 || data[0] > 4) {
18420 			PRINTM(MERROR, "Invalid Parameter: arb mode 0-4\n");
18421 			ret = -EFAULT;
18422 			goto done;
18423 		}
18424 		misc->param.arb_cfg.arb_mode = (t_u32)data[0];
18425 		req->action = MLAN_ACT_SET;
18426 	}
18427 	/* Send IOCTL request to MLAN */
18428 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18429 	if (status != MLAN_STATUS_SUCCESS) {
18430 		ret = -EFAULT;
18431 		goto done;
18432 	}
18433 
18434 	data[0] = misc->param.arb_cfg.arb_mode;
18435 	moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
18436 			respbuflen);
18437 	ret = sizeof(data);
18438 done:
18439 	if (status != MLAN_STATUS_PENDING)
18440 		kfree(req);
18441 
18442 	LEAVE();
18443 	return ret;
18444 }
18445 
18446 /**
18447  *  @brief      Timer function for TP state command.
18448  *
18449  *  @param data pointer to a buffer
18450  *
18451  *  @return     N/A
18452  */
woal_tp_acnt_timer_func(void * context)18453 void woal_tp_acnt_timer_func(void *context)
18454 {
18455 	moal_handle *phandle = (moal_handle *)context;
18456 	int i = 0;
18457 
18458 	if (phandle == NULL)
18459 		return;
18460 	PRINTM(MDATA, "####### CPU%d: tp acnt timer\n", smp_processor_id());
18461 	/* Tx TP accounting */
18462 	for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
18463 		phandle->tp_acnt.tx_bytes_rate[i] =
18464 			phandle->tp_acnt.tx_bytes[i] -
18465 			phandle->tp_acnt.tx_bytes_last[i];
18466 		phandle->tp_acnt.tx_bytes_last[i] =
18467 			phandle->tp_acnt.tx_bytes[i];
18468 		phandle->tp_acnt.tx_packets_rate[i] =
18469 			phandle->tp_acnt.tx_packets[i] -
18470 			phandle->tp_acnt.tx_packets_last[i];
18471 		phandle->tp_acnt.tx_packets_last[i] =
18472 			phandle->tp_acnt.tx_packets[i];
18473 	}
18474 	phandle->tp_acnt.tx_pending = atomic_read(&phandle->tx_pending);
18475 	/* Tx Interrupt accounting */
18476 	phandle->tp_acnt.tx_intr_rate =
18477 		phandle->tp_acnt.tx_intr_cnt - phandle->tp_acnt.tx_intr_last;
18478 	phandle->tp_acnt.tx_intr_last = phandle->tp_acnt.tx_intr_cnt;
18479 
18480 	/* Rx TP accounting */
18481 	for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
18482 		phandle->tp_acnt.rx_bytes_rate[i] =
18483 			phandle->tp_acnt.rx_bytes[i] -
18484 			phandle->tp_acnt.rx_bytes_last[i];
18485 		phandle->tp_acnt.rx_bytes_last[i] =
18486 			phandle->tp_acnt.rx_bytes[i];
18487 		phandle->tp_acnt.rx_packets_rate[i] =
18488 			phandle->tp_acnt.rx_packets[i] -
18489 			phandle->tp_acnt.rx_packets_last[i];
18490 		phandle->tp_acnt.rx_packets_last[i] =
18491 			phandle->tp_acnt.rx_packets[i];
18492 	}
18493 	phandle->tp_acnt.rx_pending = atomic_read(&phandle->rx_pending);
18494 	// Interrupt accounting, RX
18495 	phandle->tp_acnt.rx_intr_rate =
18496 		phandle->tp_acnt.rx_intr_cnt - phandle->tp_acnt.rx_intr_last;
18497 	phandle->tp_acnt.rx_intr_last = phandle->tp_acnt.rx_intr_cnt;
18498 	phandle->tp_acnt.rx_amsdu_cnt_rate = phandle->tp_acnt.rx_amsdu_cnt -
18499 					     phandle->tp_acnt.rx_amsdu_cnt_last;
18500 	phandle->tp_acnt.rx_amsdu_cnt_last = phandle->tp_acnt.rx_amsdu_cnt;
18501 
18502 	phandle->tp_acnt.rx_amsdu_pkt_cnt_rate =
18503 		phandle->tp_acnt.rx_amsdu_pkt_cnt -
18504 		phandle->tp_acnt.rx_amsdu_pkt_cnt_last;
18505 	phandle->tp_acnt.rx_amsdu_pkt_cnt_last =
18506 		phandle->tp_acnt.rx_amsdu_pkt_cnt;
18507 
18508 	phandle->tp_acnt.tx_amsdu_cnt_rate = phandle->tp_acnt.tx_amsdu_cnt -
18509 					     phandle->tp_acnt.tx_amsdu_cnt_last;
18510 	phandle->tp_acnt.tx_amsdu_cnt_last = phandle->tp_acnt.tx_amsdu_cnt;
18511 
18512 	phandle->tp_acnt.tx_amsdu_pkt_cnt_rate =
18513 		phandle->tp_acnt.tx_amsdu_pkt_cnt -
18514 		phandle->tp_acnt.tx_amsdu_pkt_cnt_last;
18515 	phandle->tp_acnt.tx_amsdu_pkt_cnt_last =
18516 		phandle->tp_acnt.tx_amsdu_pkt_cnt;
18517 
18518 	/* re-arm timer */
18519 	woal_mod_timer(&phandle->tp_acnt.timer, 1000);
18520 }
18521 
18522 /**
18523  *  @brief      set tp state to mlan
18524  *
18525  *  @param priv  pointer to moal_private
18526  *
18527  *  @return     N/A
18528  */
woal_set_tp_state(moal_private * priv)18529 void woal_set_tp_state(moal_private *priv)
18530 {
18531 	mlan_ioctl_req *req = NULL;
18532 	mlan_ds_misc_cfg *misc = NULL;
18533 	moal_handle *handle = priv->phandle;
18534 	mlan_status status = MLAN_STATUS_SUCCESS;
18535 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18536 	if (req == NULL)
18537 		return;
18538 	/* Fill request buffer */
18539 	misc = (mlan_ds_misc_cfg *)req->pbuf;
18540 	misc->sub_command = MLAN_OID_MISC_TP_STATE;
18541 	req->req_id = MLAN_IOCTL_MISC_CFG;
18542 	misc->param.tp_state.on = handle->tp_acnt.on;
18543 	misc->param.tp_state.drop_point = handle->tp_acnt.drop_point;
18544 	req->action = MLAN_ACT_SET;
18545 	/* Send IOCTL request to MLAN */
18546 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18547 	if (status != MLAN_STATUS_PENDING)
18548 		kfree(req);
18549 	return;
18550 }
18551 
18552 /**
18553  *  @brief Set/Get TP statistics.
18554  *
18555  *  @param priv         A pointer to moal_private structure
18556  *  @param respbuf      A pointer to response buffer
18557  *  @param respbuflen   Available length of response buffer
18558  *
18559  *  @return             Number of bytes written, negative for failure.
18560  */
woal_priv_set_tp_state(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18561 static int woal_priv_set_tp_state(moal_private *priv, t_u8 *respbuf,
18562 				  t_u32 respbuflen)
18563 {
18564 	moal_handle *handle = priv->phandle;
18565 	int ret = 0;
18566 	int data[2];
18567 	int header_len = 0, user_data_len = 0;
18568 
18569 	ENTER();
18570 
18571 	if (!respbuf) {
18572 		PRINTM(MERROR, "response buffer is not available!\n");
18573 		ret = -EINVAL;
18574 		goto done;
18575 	}
18576 	header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TP_STATE);
18577 	user_data_len = strlen(respbuf) - header_len;
18578 	parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18579 			&user_data_len);
18580 	if (user_data_len > 2) {
18581 		PRINTM(MERROR, "Invalid number of args!\n");
18582 		ret = -EINVAL;
18583 		goto done;
18584 	}
18585 	if (user_data_len) {
18586 		handle->tp_acnt.on = data[0];
18587 		/* Enable TP statistics collection */
18588 		if (data[0] == 1) {
18589 			handle->tp_acnt.drop_point = data[1];
18590 			if (handle->is_tp_acnt_timer_set == MFALSE) {
18591 				woal_initialize_timer(&handle->tp_acnt.timer,
18592 						      woal_tp_acnt_timer_func,
18593 						      handle);
18594 				handle->is_tp_acnt_timer_set = MTRUE;
18595 				woal_mod_timer(&handle->tp_acnt.timer, 1000);
18596 			}
18597 		} else {
18598 			if (handle->is_tp_acnt_timer_set) {
18599 				woal_cancel_timer(&handle->tp_acnt.timer);
18600 				handle->is_tp_acnt_timer_set = MFALSE;
18601 			}
18602 			memset((void *)&handle->tp_acnt, 0,
18603 			       sizeof(moal_tp_acnt_t));
18604 		}
18605 		woal_set_tp_state(priv);
18606 	}
18607 	/* Get command results */
18608 	if (user_data_len == 0) {
18609 		moal_memcpy_ext(handle, respbuf, (t_u8 *)(&handle->tp_acnt),
18610 				sizeof(handle->tp_acnt), respbuflen);
18611 		ret = sizeof(handle->tp_acnt);
18612 	}
18613 
18614 done:
18615 	LEAVE();
18616 	return ret;
18617 }
18618 
woal_priv_ips_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18619 static int woal_priv_ips_cfg(moal_private *priv, t_u8 *respbuf,
18620 			     t_u32 respbuflen)
18621 {
18622 	moal_handle *handle = priv->phandle;
18623 	mlan_ioctl_req *req = NULL;
18624 	mlan_ds_misc_cfg *misc = NULL;
18625 	t_u32 data[1];
18626 	int ret = 0;
18627 	int user_data_len = 0;
18628 	mlan_status status = MLAN_STATUS_SUCCESS;
18629 
18630 	ENTER();
18631 	if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_IPS_CFG))) {
18632 		/* GET operation */
18633 		user_data_len = 0;
18634 	} else {
18635 		/* SET operation */
18636 		memset((char *)data, 0, sizeof(data));
18637 		parse_arguments(respbuf + strlen(CMD_NXP) +
18638 					strlen(PRIV_CMD_IPS_CFG),
18639 				data, ARRAY_SIZE(data), &user_data_len);
18640 	}
18641 	if (user_data_len) {
18642 		/* Allocate an IOCTL request buffer */
18643 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18644 		if (req == NULL) {
18645 			ret = -ENOMEM;
18646 			goto done;
18647 		}
18648 		/* Fill request buffer */
18649 		misc = (mlan_ds_misc_cfg *)req->pbuf;
18650 		misc->sub_command = MLAN_OID_MISC_IPS_CFG;
18651 		req->req_id = MLAN_IOCTL_MISC_CFG;
18652 		misc->param.ips_ctrl = data[0];
18653 		req->action = MLAN_ACT_SET;
18654 		/* Send IOCTL request to MLAN */
18655 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18656 		if (status != MLAN_STATUS_SUCCESS) {
18657 			ret = -EFAULT;
18658 			goto done;
18659 		}
18660 		handle->ips_ctrl = data[0];
18661 	} else {
18662 		data[0] = handle->ips_ctrl;
18663 		moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
18664 				sizeof(data), respbuflen);
18665 	}
18666 	ret = sizeof(data);
18667 done:
18668 	if (status != MLAN_STATUS_PENDING)
18669 		kfree(req);
18670 	LEAVE();
18671 	return ret;
18672 }
18673 
woal_priv_get_uuid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18674 static int woal_priv_get_uuid(moal_private *priv, t_u8 *respbuf,
18675 			      t_u32 respbuflen)
18676 {
18677 	int ret = -1;
18678 	mlan_fw_info fw_info;
18679 
18680 	ENTER();
18681 
18682 	if (!respbuf) {
18683 		PRINTM(MERROR, "response buffer is not available!\n");
18684 		ret = -1;
18685 	} else {
18686 		fw_info.uuid_lo = fw_info.uuid_hi = 0x0ULL;
18687 
18688 		woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
18689 		snprintf(respbuf, MLAN_MAX_UUID_LEN + 1, "%016llx%016llx",
18690 			 fw_info.uuid_lo, fw_info.uuid_hi);
18691 		ret = strlen(respbuf);
18692 	}
18693 
18694 	LEAVE();
18695 	return ret;
18696 }
18697 
18698 /**
18699  *  @brief Set priv command for Android
18700  *  @param dev          A pointer to net_device structure
18701  *  @param req          A pointer to ifreq structure
18702  *
18703  *  @return             0 --success, otherwise fail
18704  */
woal_android_priv_cmd(struct net_device * dev,struct ifreq * req)18705 int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
18706 {
18707 	int ret = 0;
18708 	android_wifi_priv_cmd priv_cmd;
18709 	moal_private *priv = (moal_private *)netdev_priv(dev);
18710 	char *buf = NULL;
18711 	char *pdata;
18712 #ifdef STA_SUPPORT
18713 	int power_mode = 0;
18714 	int band = 0;
18715 	char *pband = NULL;
18716 	mlan_bss_info bss_info;
18717 	mlan_ds_get_signal signal;
18718 	mlan_rate_cfg_t rate;
18719 	t_u8 country_code[COUNTRY_CODE_LEN];
18720 	int copy_len = 0;
18721 #endif
18722 	int len = 0;
18723 	gfp_t flag;
18724 	char *cmd_buf = NULL;
18725 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
18726 	int cfg80211_wext;
18727 #endif
18728 
18729 	ENTER();
18730 	if (!priv || !priv->phandle) {
18731 		PRINTM(MERROR, "priv or handle is NULL\n");
18732 		ret = -EFAULT;
18733 		goto done;
18734 	}
18735 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
18736 	cfg80211_wext = priv->phandle->params.cfg80211_wext;
18737 #endif
18738 	if (copy_from_user(&priv_cmd, req->ifr_data,
18739 			   sizeof(android_wifi_priv_cmd))) {
18740 		ret = -EFAULT;
18741 		goto done;
18742 	}
18743 #define CMD_BUF_LEN 4096
18744 	if (priv_cmd.used_len < 0 || priv_cmd.total_len <= 0 ||
18745 	    priv_cmd.used_len > priv_cmd.total_len) {
18746 		PRINTM(MERROR,
18747 		       "Invalid Android priv cmd len. used_len: %d, total_len: %d\n",
18748 		       priv_cmd.used_len, priv_cmd.total_len);
18749 		ret = -EINVAL;
18750 		goto done;
18751 	}
18752 	if (priv_cmd.total_len + 1 > CMD_BUF_LEN)
18753 		priv_cmd.total_len = CMD_BUF_LEN - 1;
18754 
18755 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
18756 	buf = kzalloc(CMD_BUF_LEN, flag);
18757 	if (!buf) {
18758 		PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__);
18759 		ret = -ENOMEM;
18760 		goto done;
18761 	}
18762 #ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
18763 	moal_memcpy_ext(priv->phandle, &cmd_buf, &priv_cmd.buf, sizeof(cmd_buf),
18764 			sizeof(cmd_buf));
18765 #else
18766 	cmd_buf = priv_cmd.buf;
18767 #endif
18768 	if (copy_from_user(buf, (const void __user *)cmd_buf,
18769 			   priv_cmd.total_len)) {
18770 		ret = -EFAULT;
18771 		goto done;
18772 	}
18773 	buf[CMD_BUF_LEN - 1] = '\0';
18774 
18775 	PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name);
18776 
18777 	if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) &&
18778 	    woal_check_driver_status(priv->phandle)) {
18779 		PRINTM(MERROR, "%s fail when driver hang\n", buf);
18780 		ret = -EFAULT;
18781 		goto done;
18782 	}
18783 
18784 	if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) == 0) {
18785 		/* This command has come from mlanutl app */
18786 
18787 		/* Check command */
18788 		if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VERSION,
18789 			     strlen(PRIV_CMD_VERSION)) == 0) {
18790 			/* Get version */
18791 			len = woal_get_priv_driver_version(priv, buf,
18792 							   priv_cmd.total_len);
18793 			goto handled;
18794 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BANDCFG,
18795 				    strlen(PRIV_CMD_BANDCFG)) == 0) {
18796 			/* Set/Get band configuration */
18797 			len = woal_setget_priv_bandcfg(priv, buf,
18798 						       priv_cmd.total_len);
18799 			goto handled;
18800 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOSTCMD,
18801 				    strlen(PRIV_CMD_HOSTCMD)) == 0) {
18802 			/* hostcmd configuration */
18803 			len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len,
18804 						MOAL_IOCTL_WAIT);
18805 			goto handled;
18806 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCMDCFG,
18807 				    strlen(PRIV_CMD_11AXCMDCFG)) == 0) {
18808 			/* 11ax command */
18809 			pdata = buf + strlen(CMD_NXP) +
18810 				strlen(PRIV_CMD_11AXCMDCFG);
18811 			len = priv_cmd.total_len - strlen(CMD_NXP) +
18812 			      strlen(PRIV_CMD_11AXCMDCFG);
18813 			len = woal_setget_priv_11axcmdcfg(priv, pdata, len,
18814 							  MOAL_IOCTL_WAIT);
18815 			len += strlen(CMD_NXP) + strlen(PRIV_CMD_11AXCMDCFG);
18816 			goto handled;
18817 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RANGE_EXT,
18818 				    strlen(PRIV_CMD_RANGE_EXT)) == 0) {
18819 			len = woal_setget_priv_range_ext(priv, buf,
18820 							 priv_cmd.total_len);
18821 			goto handled;
18822 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTTXCFG,
18823 				    strlen(PRIV_CMD_HTTXCFG)) == 0) {
18824 			/* Set/Get HT Tx configuration */
18825 			len = woal_setget_priv_httxcfg(priv, buf,
18826 						       priv_cmd.total_len);
18827 			goto handled;
18828 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTCAPINFO,
18829 				    strlen(PRIV_CMD_HTCAPINFO)) == 0) {
18830 			/* Set/Get HT Capability information */
18831 			len = woal_setget_priv_htcapinfo(priv, buf,
18832 							 priv_cmd.total_len);
18833 			goto handled;
18834 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAPARA,
18835 				    strlen(PRIV_CMD_ADDBAPARA)) == 0) {
18836 			/* Set/Get Add BA parameters */
18837 			len = woal_setget_priv_addbapara(priv, buf,
18838 							 priv_cmd.total_len);
18839 			goto handled;
18840 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRPRIOTBL,
18841 				    strlen(PRIV_CMD_AGGRPRIOTBL)) == 0) {
18842 			/* Set/Get Aggregation priority table parameters */
18843 			len = woal_setget_priv_aggrpriotbl(priv, buf,
18844 							   priv_cmd.total_len);
18845 			goto handled;
18846 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAREJECT,
18847 				    strlen(PRIV_CMD_ADDBAREJECT)) == 0) {
18848 			/* Set/Get Add BA reject parameters */
18849 			len = woal_setget_priv_addbareject(priv, buf,
18850 							   priv_cmd.total_len);
18851 			goto handled;
18852 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELBA,
18853 				    strlen(PRIV_CMD_DELBA)) == 0) {
18854 			/* Delete selective BA based on parameters */
18855 			len = woal_priv_delba(priv, buf, priv_cmd.total_len);
18856 			goto handled;
18857 		} else if (strnicmp(buf + strlen(CMD_NXP),
18858 				    PRIV_CMD_REJECTADDBAREQ,
18859 				    strlen(PRIV_CMD_REJECTADDBAREQ)) == 0) {
18860 			/* Set/Get the reject addba requst conditions*/
18861 			len = woal_priv_rejectaddbareq(priv, buf,
18862 						       priv_cmd.total_len);
18863 			goto handled;
18864 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VHTCFG,
18865 				    strlen(PRIV_CMD_VHTCFG)) == 0) {
18866 			/* Set/Get 11AC configuration */
18867 			len = woal_setget_priv_vhtcfg(priv, buf,
18868 						      priv_cmd.total_len);
18869 			goto handled;
18870 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OPERMODECFG,
18871 				    strlen(PRIV_CMD_OPERMODECFG)) == 0) {
18872 			/* Set/Get 11AC configuration */
18873 			len = woal_setget_priv_opermodecfg(priv, buf,
18874 							   priv_cmd.total_len);
18875 			goto handled;
18876 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DATARATE,
18877 				    strlen(PRIV_CMD_DATARATE)) == 0) {
18878 			/* Get data rate */
18879 			len = woal_get_priv_datarate(priv, buf,
18880 						     priv_cmd.total_len);
18881 			goto handled;
18882 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXRATECFG,
18883 				    strlen(PRIV_CMD_TXRATECFG)) == 0) {
18884 			/* Set/Get tx rate cfg */
18885 			len = woal_setget_priv_txratecfg(priv, buf,
18886 							 priv_cmd.total_len);
18887 			goto handled;
18888 #if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
18889 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETLOG,
18890 				    strlen(PRIV_CMD_GETLOG)) == 0) {
18891 			/* Get wireless stats information */
18892 			len = woal_get_priv_getlog(priv, buf,
18893 						   priv_cmd.total_len);
18894 			goto handled;
18895 #endif
18896 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CUSTOMIE,
18897 				    strlen(PRIV_CMD_CUSTOMIE)) == 0) {
18898 			/* Custom IE configuration */
18899 			len = woal_priv_customie(priv, buf, priv_cmd.total_len);
18900 			goto handled;
18901 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ESUPPMODE,
18902 				    strlen(PRIV_CMD_ESUPPMODE)) == 0) {
18903 			/* Esupplicant mode configuration */
18904 			len = woal_setget_priv_esuppmode(priv, buf,
18905 							 priv_cmd.total_len);
18906 			goto handled;
18907 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PASSPHRASE,
18908 				    strlen(PRIV_CMD_PASSPHRASE)) == 0) {
18909 			/* Esupplicant passphrase configuration */
18910 			len = woal_setget_priv_passphrase(priv, buf,
18911 							  priv_cmd.total_len);
18912 			goto handled;
18913 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH,
18914 				    strlen(PRIV_CMD_DEAUTH)) == 0) {
18915 			/* Deauth */
18916 			len = woal_priv_deauth(priv, buf, priv_cmd.total_len);
18917 			goto handled;
18918 #ifdef UAP_SUPPORT
18919 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AP_DEAUTH,
18920 				    strlen(PRIV_CMD_AP_DEAUTH)) == 0) {
18921 			/* AP Deauth */
18922 			len = woal_priv_ap_deauth(priv, buf,
18923 						  priv_cmd.total_len);
18924 			goto handled;
18925 		} else if (strnicmp(buf + strlen(CMD_NXP),
18926 				    PRIV_CMD_GET_STA_LIST,
18927 				    strlen(PRIV_CMD_GET_STA_LIST)) == 0) {
18928 			/* Get STA list */
18929 			len = woal_priv_get_sta_list(priv, buf,
18930 						     priv_cmd.total_len);
18931 			goto handled;
18932 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSS_CONFIG,
18933 				    strlen(PRIV_CMD_BSS_CONFIG)) == 0) {
18934 			/* BSS config */
18935 			len = woal_priv_bss_config(priv, buf,
18936 						   priv_cmd.total_len);
18937 			goto handled;
18938 #endif
18939 #ifdef WIFI_DIRECT_SUPPORT
18940 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
18941 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSSROLE,
18942 				    strlen(PRIV_CMD_BSSROLE)) == 0) {
18943 			/* BSS Role */
18944 			len = woal_priv_bssrole(priv, buf,
18945 						(t_u32)priv_cmd.total_len);
18946 			goto handled;
18947 #endif
18948 #endif
18949 #ifdef STA_SUPPORT
18950 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SETUSERSCAN,
18951 				    strlen(PRIV_CMD_SETUSERSCAN)) == 0) {
18952 			/* Set user scan */
18953 			len = woal_priv_setuserscan(priv, buf,
18954 						    priv_cmd.total_len);
18955 			goto handled;
18956 		} else if (strnicmp(buf + strlen(CMD_NXP),
18957 				    PRIV_CMD_GETSCANTABLE,
18958 				    strlen(PRIV_CMD_GETSCANTABLE)) == 0) {
18959 			/* Get scan table */
18960 			len = woal_priv_getscantable(priv, buf,
18961 						     priv_cmd.total_len);
18962 			goto handled;
18963 		} else if (strnicmp(buf + strlen(CMD_NXP),
18964 				    PRIV_CMD_GETCHANSTATS,
18965 				    strlen(PRIV_CMD_GETCHANSTATS)) == 0) {
18966 			/* Get channel statistics */
18967 			len = woal_priv_get_chanstats(priv, buf,
18968 						      priv_cmd.total_len);
18969 			goto handled;
18970 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_EXTCAPCFG,
18971 				    strlen(PRIV_CMD_EXTCAPCFG)) == 0) {
18972 			/* Extended capabilities configure */
18973 			len = woal_priv_extcapcfg(priv, buf,
18974 						  (t_u32)priv_cmd.total_len);
18975 			goto handled;
18976 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CANCELSCAN,
18977 				    strlen(PRIV_CMD_CANCELSCAN)) == 0) {
18978 			/* Cancel scan */
18979 			len = woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
18980 			goto handled;
18981 #endif
18982 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEEPSLEEP,
18983 				    strlen(PRIV_CMD_DEEPSLEEP)) == 0) {
18984 			/* Deep sleep */
18985 			len = woal_priv_setgetdeepsleep(priv, buf,
18986 							priv_cmd.total_len);
18987 			goto handled;
18988 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPADDR,
18989 				    strlen(PRIV_CMD_IPADDR)) == 0) {
18990 			/* IP address */
18991 			len = woal_priv_setgetipaddr(priv, buf,
18992 						     (t_u32)priv_cmd.total_len);
18993 			goto handled;
18994 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WPSSESSION,
18995 				    strlen(PRIV_CMD_WPSSESSION)) == 0) {
18996 			/* WPS Session */
18997 			len = woal_priv_setwpssession(priv, buf,
18998 						      priv_cmd.total_len);
18999 			goto handled;
19000 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OTPUSERDATA,
19001 				    strlen(PRIV_CMD_OTPUSERDATA)) == 0) {
19002 			/* OTP user data */
19003 			len = woal_priv_otpuserdata(priv, buf,
19004 						    priv_cmd.total_len);
19005 			goto handled;
19006 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_COUNTRYCODE,
19007 				    strlen(PRIV_CMD_COUNTRYCODE)) == 0) {
19008 			/* Country code */
19009 			len = woal_priv_set_get_countrycode(priv, buf,
19010 							    priv_cmd.total_len);
19011 			goto handled;
19012 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFPINFO,
19013 				    strlen(PRIV_CMD_CFPINFO)) == 0) {
19014 			/* CFP info */
19015 			len = woal_priv_get_cfpinfo(priv, buf,
19016 						    priv_cmd.total_len);
19017 			goto handled;
19018 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TCPACKENH,
19019 				    strlen(PRIV_CMD_TCPACKENH)) == 0) {
19020 			/* TCP ack enhancement */
19021 			len = woal_priv_setgettcpackenh(priv, buf,
19022 							priv_cmd.total_len);
19023 			goto handled;
19024 #ifdef REASSOCIATION
19025 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCBSSID,
19026 				    strlen(PRIV_CMD_ASSOCBSSID)) == 0) {
19027 			/* Associate to essid */
19028 			len = woal_priv_assocessid(priv, buf,
19029 						   priv_cmd.total_len, 1);
19030 			goto handled;
19031 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCESSID,
19032 				    strlen(PRIV_CMD_ASSOCESSID)) == 0) {
19033 			/* Associate to essid */
19034 			len = woal_priv_assocessid(priv, buf,
19035 						   priv_cmd.total_len, 0);
19036 			goto handled;
19037 #endif
19038 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTOASSOC,
19039 				    strlen(PRIV_CMD_AUTOASSOC)) == 0) {
19040 			/* Auto assoc */
19041 			len = woal_priv_setgetautoassoc(priv, buf,
19042 							priv_cmd.total_len);
19043 			goto handled;
19044 		} else if (strnicmp(buf + strlen(CMD_NXP),
19045 				    PRIV_CMD_WAKEUPREASON,
19046 				    strlen(PRIV_CMD_WAKEUPREASON)) == 0) {
19047 			/* wakeup reason */
19048 			len = woal_priv_getwakeupreason(priv, buf,
19049 							priv_cmd.total_len);
19050 			goto handled;
19051 #ifdef STA_SUPPORT
19052 		} else if (strnicmp(buf + strlen(CMD_NXP),
19053 				    PRIV_CMD_LISTENINTERVAL,
19054 				    strlen(PRIV_CMD_LISTENINTERVAL)) == 0) {
19055 			/* Listen Interval */
19056 			len = woal_priv_set_get_listeninterval(
19057 				priv, buf, priv_cmd.total_len);
19058 			goto handled;
19059 #endif
19060 #ifdef DEBUG_LEVEL1
19061 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DRVDBG,
19062 				    strlen(PRIV_CMD_DRVDBG)) == 0) {
19063 			/* Driver debug bit mask */
19064 			len = woal_priv_set_get_drvdbg(priv, buf,
19065 						       priv_cmd.total_len);
19066 			goto handled;
19067 #endif
19068 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSCFG,
19069 				    strlen(PRIV_CMD_HSCFG)) == 0) {
19070 			/* HS configuration */
19071 			len = woal_priv_hscfg(priv, buf, priv_cmd.total_len,
19072 					      MTRUE);
19073 			goto handled;
19074 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSSETPARA,
19075 				    strlen(PRIV_CMD_HSSETPARA)) == 0) {
19076 			/* Set HS parameter */
19077 			len = woal_priv_hssetpara(priv, buf,
19078 						  priv_cmd.total_len);
19079 			goto handled;
19080 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MGMT_FILTER,
19081 				    strlen(PRIV_CMD_MGMT_FILTER)) == 0) {
19082 			/* Management frame filter wakeup */
19083 			len = woal_priv_mgmt_filter(priv, buf,
19084 						    priv_cmd.total_len);
19085 			goto handled;
19086 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SCANCFG,
19087 				    strlen(PRIV_CMD_SCANCFG)) == 0) {
19088 			/* Scan configuration */
19089 			len = woal_priv_set_get_scancfg(priv, buf,
19090 							priv_cmd.total_len);
19091 			goto handled;
19092 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETNLNUM,
19093 				    strlen(PRIV_CMD_GETNLNUM)) == 0) {
19094 			/* Scan configuration */
19095 			len = woal_priv_getnlnum(priv, buf, priv_cmd.total_len);
19096 			goto handled;
19097 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRCTRL,
19098 				    strlen(PRIV_CMD_AGGRCTRL)) == 0) {
19099 			/* aggregation control */
19100 			len = woal_priv_set_get_aggrctrl(priv, buf,
19101 							 priv_cmd.total_len);
19102 			goto handled;
19103 #ifdef USB
19104 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USBAGGRCTRL,
19105 				    strlen(PRIV_CMD_USBAGGRCTRL)) == 0) {
19106 			/* USB aggregation control */
19107 			len = woal_priv_set_get_usbaggrctrl(priv, buf,
19108 							    priv_cmd.total_len);
19109 			goto handled;
19110 #endif
19111 		} else if (strnicmp(buf + strlen(CMD_NXP),
19112 				    PRIV_CMD_SET_BSS_MODE,
19113 				    strlen(PRIV_CMD_SET_BSS_MODE)) == 0) {
19114 			/* Set bss mode */
19115 			len = woal_priv_set_bss_mode(priv, buf,
19116 						     priv_cmd.total_len);
19117 			goto handled;
19118 #ifdef STA_SUPPORT
19119 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AP,
19120 				    strlen(PRIV_CMD_SET_AP)) == 0) {
19121 			/* Set AP */
19122 			len = woal_priv_set_ap(priv, buf, priv_cmd.total_len);
19123 			goto handled;
19124 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_POWER,
19125 				    strlen(PRIV_CMD_SET_POWER)) == 0) {
19126 			/* Set power management parameters */
19127 			len = woal_priv_set_power(priv, buf,
19128 						  priv_cmd.total_len);
19129 			goto handled;
19130 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_ESSID,
19131 				    strlen(PRIV_CMD_SET_ESSID)) == 0) {
19132 			/* Set essid */
19133 			len = woal_priv_set_essid(priv, buf,
19134 						  priv_cmd.total_len);
19135 			goto handled;
19136 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AUTH,
19137 				    strlen(PRIV_CMD_SET_AUTH)) == 0) {
19138 			/* Set authentication mode parameters */
19139 			len = woal_priv_set_auth(priv, buf, priv_cmd.total_len);
19140 			goto handled;
19141 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_AP,
19142 				    strlen(PRIV_CMD_GET_AP)) == 0) {
19143 			/* Get AP */
19144 			len = woal_priv_get_ap(priv, buf, priv_cmd.total_len);
19145 			goto handled;
19146 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_POWER,
19147 				    strlen(PRIV_CMD_GET_POWER)) == 0) {
19148 			/* Get power management parameters */
19149 			len = woal_priv_get_power(priv, buf,
19150 						  priv_cmd.total_len);
19151 			goto handled;
19152 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSMODE,
19153 				    strlen(PRIV_CMD_PSMODE)) == 0) {
19154 			/* Set/Get PS mode */
19155 			len = woal_priv_set_get_psmode(priv, buf,
19156 						       priv_cmd.total_len);
19157 			goto handled;
19158 #endif
19159 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WARMRESET,
19160 				    strlen(PRIV_CMD_WARMRESET)) == 0) {
19161 			/* Performs warm reset */
19162 			len = woal_priv_warmreset(priv, buf,
19163 						  priv_cmd.total_len);
19164 			goto handled;
19165 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXPOWERCFG,
19166 				    strlen(PRIV_CMD_TXPOWERCFG)) == 0) {
19167 			/* TX power configurations */
19168 			len = woal_priv_txpowercfg(priv, buf,
19169 						   priv_cmd.total_len);
19170 			goto handled;
19171 		} else if (strnicmp(buf + strlen(CMD_NXP),
19172 				    PRIV_CMD_RX_ABORT_CFG_EXT,
19173 				    strlen(PRIV_CMD_RX_ABORT_CFG_EXT)) == 0) {
19174 			/* dynamic Rx Abort config */
19175 			len = woal_priv_rx_abort_cfg_ext(priv, buf,
19176 							 priv_cmd.total_len);
19177 			goto handled;
19178 		} else if (strnicmp(buf + strlen(CMD_NXP),
19179 				    PRIV_CMD_RX_ABORT_CFG,
19180 				    strlen(PRIV_CMD_RX_ABORT_CFG)) == 0) {
19181 			/* static Rx Abort config */
19182 			len = woal_priv_rx_abort_cfg(priv, buf,
19183 						     priv_cmd.total_len);
19184 			goto handled;
19185 		} else if (strnicmp(buf + strlen(CMD_NXP),
19186 				    PRIV_CMD_TX_AMPDU_PROT_MODE,
19187 				    strlen(PRIV_CMD_TX_AMPDU_PROT_MODE)) == 0) {
19188 			/* tx ampdu protection mode setting */
19189 			len = woal_priv_tx_ampdu_prot_mode(priv, buf,
19190 							   priv_cmd.total_len);
19191 			goto handled;
19192 		} else if (strnicmp(buf + strlen(CMD_NXP),
19193 				    PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG,
19194 				    strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG)) ==
19195 			   0) {
19196 			/* setting for dot11mc un-associated case FTM frame
19197 			 * exchange */
19198 			len = woal_priv_dot11mc_unassoc_ftm_cfg(
19199 				priv, buf, priv_cmd.total_len);
19200 			goto handled;
19201 		} else if (strnicmp(buf + strlen(CMD_NXP),
19202 				    PRIV_CMD_RATE_ADAPT_CFG,
19203 				    strlen(PRIV_CMD_RATE_ADAPT_CFG)) == 0) {
19204 			/* rate adapt config */
19205 			len = woal_priv_rate_adapt_cfg(priv, buf,
19206 						       priv_cmd.total_len);
19207 			goto handled;
19208 		} else if (strnicmp(buf + strlen(CMD_NXP),
19209 				    PRIV_CMD_CCK_DESENSE_CFG,
19210 				    strlen(PRIV_CMD_CCK_DESENSE_CFG)) == 0) {
19211 			/* cck desense config */
19212 			len = woal_priv_cck_desense_cfg(priv, buf,
19213 							priv_cmd.total_len);
19214 			goto handled;
19215 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSCFG,
19216 				    strlen(PRIV_CMD_PSCFG)) == 0) {
19217 			/* PS configurations */
19218 			len = woal_priv_pscfg(priv, buf, priv_cmd.total_len);
19219 			goto handled;
19220 		} else if (strnicmp(buf + strlen(CMD_NXP),
19221 				    PRIV_CMD_BCNTIMEOUTCFG,
19222 				    strlen(PRIV_CMD_BCNTIMEOUTCFG)) == 0) {
19223 			/* Beacon timeout configurations */
19224 			len = woal_priv_bcntimeoutcfg(priv, buf,
19225 						      priv_cmd.total_len);
19226 			goto handled;
19227 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SLEEPPD,
19228 				    strlen(PRIV_CMD_SLEEPPD)) == 0) {
19229 			/* Sleep period */
19230 			len = woal_priv_sleeppd(priv, buf, priv_cmd.total_len);
19231 			goto handled;
19232 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXCONTROL,
19233 				    strlen(PRIV_CMD_TXCONTROL)) == 0) {
19234 			/* Tx control */
19235 			len = woal_priv_txcontrol(priv, buf,
19236 						  priv_cmd.total_len);
19237 			goto handled;
19238 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGRDWR,
19239 				    strlen(PRIV_CMD_REGRDWR)) == 0) {
19240 			/* Register Read/Write */
19241 			len = woal_priv_regrdwr(priv, buf, priv_cmd.total_len);
19242 			goto handled;
19243 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RDEEPROM,
19244 				    strlen(PRIV_CMD_RDEEPROM)) == 0) {
19245 			/* Read the EEPROM contents of the card */
19246 			len = woal_priv_rdeeprom(priv, buf, priv_cmd.total_len);
19247 			goto handled;
19248 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MEMRDWR,
19249 				    strlen(PRIV_CMD_MEMRDWR)) == 0) {
19250 			/* Memory Read/Write */
19251 			len = woal_priv_memrdwr(priv, buf, priv_cmd.total_len);
19252 			goto handled;
19253 #ifdef SDIO
19254 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDCMD52RW,
19255 				    strlen(PRIV_CMD_SDCMD52RW)) == 0) {
19256 			/* Cmd52 read/write register */
19257 			len = woal_priv_sdcmd52rw(priv, buf,
19258 						  priv_cmd.total_len);
19259 			goto handled;
19260 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDIO_CLOCK,
19261 				    strlen(PRIV_CMD_SDIO_CLOCK)) == 0) {
19262 			/* Turn on/off the sdio clock */
19263 			len = woal_priv_sdio_clock_ioctl(priv, buf,
19264 							 priv_cmd.total_len);
19265 			goto handled;
19266 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MPA_CTRL,
19267 				    strlen(PRIV_CMD_MPA_CTRL)) == 0) {
19268 			/* Set SDIO Multi-point aggregation
19269 			 * control parameters */
19270 			len = woal_priv_sdio_mpa_ctrl(priv, buf,
19271 						      priv_cmd.total_len);
19272 			goto handled;
19273 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SD_CMD53_RW,
19274 				    strlen(PRIV_CMD_SD_CMD53_RW)) == 0) {
19275 			/* Cmd53 read/write register */
19276 			len = woal_priv_cmd53rdwr(priv, buf,
19277 						  priv_cmd.total_len);
19278 			goto handled;
19279 #endif
19280 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ROBUSTCOEX,
19281 				    strlen(PRIV_CMD_ROBUSTCOEX)) == 0) {
19282 			/* Set Robustcoex GPIOcfg */
19283 			pdata = buf + strlen(CMD_NXP) +
19284 				strlen(PRIV_CMD_ROBUSTCOEX);
19285 			len = priv_cmd.total_len - strlen(PRIV_CMD_ROBUSTCOEX) -
19286 			      strlen(CMD_NXP);
19287 			len = woal_priv_robustcoex(priv, pdata, len);
19288 			goto handled;
19289 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DMCS,
19290 				    strlen(PRIV_CMD_DMCS)) == 0) {
19291 			/* Set/Get DMCS config */
19292 			len = woal_priv_dmcs(priv, buf, priv_cmd.total_len);
19293 			goto handled;
19294 #if defined(PCIE)
19295 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SSU,
19296 				    strlen(PRIV_CMD_SSU)) == 0) {
19297 			/* Set SSU config */
19298 			pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_SSU);
19299 			len = priv_cmd.used_len - strlen(PRIV_CMD_SSU) -
19300 			      strlen(CMD_NXP);
19301 			len = woal_priv_ssu_cmd(priv, len, pdata,
19302 						priv_cmd.total_len);
19303 			goto handled;
19304 #endif
19305 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HAL_PHY_CFG,
19306 				    strlen(PRIV_CMD_HAL_PHY_CFG)) == 0) {
19307 			/* Set hal_phy config */
19308 			pdata = buf + strlen(CMD_NXP) +
19309 				strlen(PRIV_CMD_HAL_PHY_CFG);
19310 			len = priv_cmd.total_len -
19311 			      strlen(PRIV_CMD_HAL_PHY_CFG) - strlen(CMD_NXP);
19312 			len = woal_priv_hal_phy_cfg_cmd(priv, pdata, len);
19313 			goto handled;
19314 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CSI,
19315 				    strlen(PRIV_CMD_CSI)) == 0) {
19316 			/* Set CSI config */
19317 			pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_CSI);
19318 			len = priv_cmd.total_len - strlen(PRIV_CMD_CSI) -
19319 			      strlen(CMD_NXP);
19320 			priv->csi_seq = 0;
19321 			len = woal_priv_csi_cmd(priv, pdata, len);
19322 			goto handled;
19323 #ifdef STA_SUPPORT
19324 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARPFILTER,
19325 				    strlen(PRIV_CMD_ARPFILTER)) == 0) {
19326 			/* ARPFilter Configuration */
19327 			len = woal_priv_arpfilter(priv, buf,
19328 						  priv_cmd.total_len);
19329 			goto handled;
19330 #endif
19331 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_ARP,
19332 				    strlen(PRIV_CMD_AUTO_ARP)) == 0) {
19333 			/* Auto ARP enable/disable */
19334 			len = woal_priv_set_get_auto_arp(priv, buf,
19335 							 priv_cmd.total_len);
19336 			goto handled;
19337 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOTSPOTCFG,
19338 				    strlen(PRIV_CMD_HOTSPOTCFG)) == 0) {
19339 			/* Hotspot CFG */
19340 			len = woal_priv_hotspotcfg(priv, buf,
19341 						   priv_cmd.total_len);
19342 			goto handled;
19343 #ifdef RX_PACKET_COALESCE
19344 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RX_COAL_CFG,
19345 				    strlen(PRIV_CMD_RX_COAL_CFG)) == 0) {
19346 			/* RX packet coalescing Configuration */
19347 			len = woal_priv_rx_pkt_coalesce_cfg(priv, buf,
19348 							    priv_cmd.total_len);
19349 			goto handled;
19350 #endif
19351 
19352 		} else if (strnicmp(buf + strlen(CMD_NXP),
19353 				    PRIV_CMD_MGMT_FRAME_CTRL,
19354 				    strlen(PRIV_CMD_MGMT_FRAME_CTRL)) == 0) {
19355 			/* Mgmt Frame Passthrough Ctrl */
19356 			len = woal_priv_mgmt_frame_passthru_ctrl(
19357 				priv, buf, priv_cmd.total_len);
19358 			goto handled;
19359 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QCONFIG,
19360 				    strlen(PRIV_CMD_QCONFIG)) == 0) {
19361 			/* Queue config */
19362 			len = woal_priv_qconfig(priv, buf, priv_cmd.total_len);
19363 			goto handled;
19364 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDTS,
19365 				    strlen(PRIV_CMD_ADDTS)) == 0) {
19366 			/* Send an ADDTS TSPEC */
19367 			len = woal_priv_wmm_addts_req_ioctl(priv, buf,
19368 							    priv_cmd.total_len);
19369 			goto handled;
19370 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELTS,
19371 				    strlen(PRIV_CMD_DELTS)) == 0) {
19372 			/* Send a DELTS TSPE */
19373 			len = woal_priv_wmm_delts_req_ioctl(priv, buf,
19374 							    priv_cmd.total_len);
19375 			goto handled;
19376 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QSTATUS,
19377 				    strlen(PRIV_CMD_QSTATUS)) == 0) {
19378 			/* Get the status of the WMM queues */
19379 			len = woal_priv_wmm_queue_status_ioctl(
19380 				priv, buf, priv_cmd.total_len);
19381 			goto handled;
19382 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TS_STATUS,
19383 				    strlen(PRIV_CMD_TS_STATUS)) == 0) {
19384 			/* Get the status of the WMM Traffic Streams */
19385 			len = woal_priv_wmm_ts_status_ioctl(priv, buf,
19386 							    priv_cmd.total_len);
19387 			goto handled;
19388 #ifdef STA_SUPPORT
19389 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QOS_CFG,
19390 				    strlen(PRIV_CMD_QOS_CFG)) == 0) {
19391 			t_u32 action = MLAN_ACT_GET;
19392 			if (strlen(buf) ==
19393 			    strlen(CMD_NXP) + strlen(PRIV_CMD_QOS_CFG)) {
19394 				pdata = buf; /* GET operation */
19395 			} else {
19396 				pdata = buf + strlen(CMD_NXP) +
19397 					strlen(PRIV_CMD_QOS_CFG);
19398 				action = MLAN_ACT_SET; /* SET operation */
19399 			}
19400 			if (MLAN_STATUS_SUCCESS !=
19401 			    woal_priv_qos_cfg(priv, action, pdata)) {
19402 				ret = -EFAULT;
19403 				goto done;
19404 			}
19405 			if (action == MLAN_ACT_GET)
19406 				len = sizeof(t_u8);
19407 			goto handled;
19408 #endif
19409 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MAC_CTRL,
19410 				    strlen(PRIV_CMD_MAC_CTRL)) == 0) {
19411 			/* MAC CTRL */
19412 			len = woal_priv_macctrl(priv, buf, priv_cmd.total_len);
19413 			goto handled;
19414 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETWAP,
19415 				    strlen(PRIV_CMD_GETWAP)) == 0) {
19416 			/* Get WAP */
19417 			len = woal_priv_getwap(priv, buf, priv_cmd.total_len);
19418 			goto handled;
19419 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGION_CODE,
19420 				    strlen(PRIV_CMD_REGION_CODE)) == 0) {
19421 			/* Region Code */
19422 			len = woal_priv_region_code(priv, buf,
19423 						    priv_cmd.total_len);
19424 			goto handled;
19425 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FWMACADDR,
19426 				    strlen(PRIV_CMD_FWMACADDR)) == 0) {
19427 			/* Set FW MAC address */
19428 			len = woal_priv_fwmacaddr(priv, buf,
19429 						  priv_cmd.total_len);
19430 			goto handled;
19431 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19432 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
19433 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OFFCHANNEL,
19434 				    strlen(PRIV_CMD_OFFCHANNEL)) == 0) {
19435 			if (IS_STA_CFG80211(cfg80211_wext)) {
19436 				/* Set offchannel */
19437 				len = woal_priv_offchannel(priv, buf,
19438 							   priv_cmd.total_len);
19439 			} else
19440 				len = sprintf(buf,
19441 					      "CFG80211 is not enabled\n") +
19442 				      1;
19443 			goto handled;
19444 #endif
19445 #endif
19446 
19447 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DSCP_MAP,
19448 				    strlen(PRIV_CMD_DSCP_MAP)) == 0) {
19449 			/* Set/Get DSCP Map */
19450 			len = woal_priv_set_get_dscp_map(priv, buf,
19451 							 priv_cmd.total_len);
19452 			goto handled;
19453 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VEREXT,
19454 				    strlen(PRIV_CMD_VEREXT)) == 0) {
19455 			/* Get Extended version */
19456 			len = woal_priv_get_driver_verext(priv, buf,
19457 							  priv_cmd.total_len);
19458 			goto handled;
19459 #ifdef USB
19460 #ifdef CONFIG_USB_SUSPEND
19461 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_SUSPEND,
19462 				    strlen(PRIV_CMD_USB_SUSPEND)) == 0) {
19463 			/* Makes USB device to suspend */
19464 			len = woal_priv_enter_usb_suspend(priv, buf,
19465 							  priv_cmd.total_len);
19466 			goto handled;
19467 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_RESUME,
19468 				    strlen(PRIV_CMD_USB_RESUME)) == 0) {
19469 			/* Makes USB device to resume */
19470 			len = woal_priv_exit_usb_suspend(priv, buf,
19471 							 priv_cmd.total_len);
19472 			goto handled;
19473 #endif /* CONFIG_USB_SUSPEND */
19474 #endif
19475 #if defined(STA_SUPPORT) && defined(STA_WEXT)
19476 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RADIO_CTRL,
19477 				    strlen(PRIV_CMD_RADIO_CTRL)) == 0) {
19478 			/* Set/Get radio */
19479 			len = woal_priv_radio_ctrl(priv, buf,
19480 						   priv_cmd.total_len);
19481 			goto handled;
19482 #endif
19483 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WMM_CFG,
19484 				    strlen(PRIV_CMD_WMM_CFG)) == 0) {
19485 			/* Implement WMM enable command */
19486 			len = woal_priv_wmm_cfg(priv, buf, priv_cmd.total_len);
19487 			goto handled;
19488 		} else if (strnicmp(buf + strlen(CMD_NXP),
19489 				    PRIV_CMD_MIN_BA_THRESH_CFG,
19490 				    strlen(PRIV_CMD_MIN_BA_THRESH_CFG)) == 0) {
19491 			/* Implement Minimum BA threshold configuration command
19492 			 */
19493 			len = woal_priv_min_ba_threshold_cfg(
19494 				priv, buf, priv_cmd.total_len);
19495 			goto handled;
19496 #if defined(STA_SUPPORT)
19497 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CFG,
19498 				    strlen(PRIV_CMD_11D_CFG)) == 0) {
19499 			/* Implement 802.11D enable command */
19500 			len = woal_priv_11d_cfg(priv, buf, priv_cmd.total_len);
19501 			goto handled;
19502 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CLR_TBL,
19503 				    strlen(PRIV_CMD_11D_CLR_TBL)) == 0) {
19504 			/* Implement 802.11D clear chan table command */
19505 			len = woal_priv_11d_clr_chan_tbl(priv, buf,
19506 							 priv_cmd.total_len);
19507 			goto handled;
19508 #endif
19509 #ifndef OPCHAN
19510 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WWS_CFG,
19511 				    strlen(PRIV_CMD_WWS_CFG)) == 0) {
19512 			/* Set/Get WWS configuration */
19513 			len = woal_priv_wws_cfg(priv, buf, priv_cmd.total_len);
19514 			goto handled;
19515 #endif
19516 #if defined(REASSOCIATION)
19517 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REASSOCTRL,
19518 				    strlen(PRIV_CMD_REASSOCTRL)) == 0) {
19519 			/* Set/Get reassociation settings */
19520 			len = woal_priv_set_get_reassoc(priv, buf,
19521 							priv_cmd.total_len);
19522 			goto handled;
19523 #endif
19524 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXBUF_CFG,
19525 				    strlen(PRIV_CMD_TXBUF_CFG)) == 0) {
19526 			/* Get Transmit buffer size */
19527 			len = woal_priv_txbuf_cfg(priv, buf,
19528 						  priv_cmd.total_len);
19529 			goto handled;
19530 #ifdef STA_SUPPORT
19531 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTH_TYPE,
19532 				    strlen(PRIV_CMD_AUTH_TYPE)) == 0) {
19533 			/* Set/Get auth type */
19534 			len = woal_priv_auth_type(priv, buf,
19535 						  priv_cmd.total_len);
19536 			goto handled;
19537 #endif
19538 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_POWER_CONS,
19539 				    strlen(PRIV_CMD_POWER_CONS)) == 0) {
19540 			/* Set/get user provisioned local power constraint */
19541 			len = woal_priv_11h_local_pwr_constraint(
19542 				priv, buf, priv_cmd.total_len);
19543 			goto handled;
19544 		} else if (strnicmp(buf + strlen(CMD_NXP),
19545 				    PRIV_CMD_HT_STREAM_CFG,
19546 				    strlen(PRIV_CMD_HT_STREAM_CFG)) == 0) {
19547 			/* Set/get HT stream configurations */
19548 			len = woal_priv_ht_stream_cfg(priv, buf,
19549 						      priv_cmd.total_len);
19550 			goto handled;
19551 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MIMO_SWITCH,
19552 				    strlen(PRIV_CMD_MIMO_SWITCH)) == 0) {
19553 			/* Set mimo switch configurations */
19554 			len = woal_priv_mimo_switch(priv, buf,
19555 						    priv_cmd.total_len);
19556 			goto handled;
19557 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_THERMAL,
19558 				    strlen(PRIV_CMD_THERMAL)) == 0) {
19559 			/* Get thermal reading */
19560 			len = woal_priv_thermal(priv, buf, priv_cmd.total_len);
19561 			goto handled;
19562 		} else if (strnicmp(buf + strlen(CMD_NXP),
19563 				    PRIV_CMD_BCN_INTERVAL,
19564 				    strlen(PRIV_CMD_BCN_INTERVAL)) == 0) {
19565 			/* Set/Get beacon interval */
19566 			len = woal_priv_beacon_interval(priv, buf,
19567 							priv_cmd.total_len);
19568 			goto handled;
19569 #ifdef STA_SUPPORT
19570 		} else if (strnicmp(buf + strlen(CMD_NXP),
19571 				    PRIV_CMD_SIGNALEXT_CFG,
19572 				    strlen(PRIV_CMD_SIGNALEXT_CFG)) == 0) {
19573 			/* Set signalext flag */
19574 			len = woal_priv_signalext_cfg(priv, buf,
19575 						      priv_cmd.total_len);
19576 			goto handled;
19577 		} else if (strnicmp(buf + strlen(CMD_NXP),
19578 				    PRIV_CMD_GET_SIGNAL_EXT_V2,
19579 				    strlen(PRIV_CMD_GET_SIGNAL_EXT_V2)) == 0) {
19580 			/* Get signal info */
19581 			len = woal_priv_get_signal_ext_v2(priv, buf,
19582 							  priv_cmd.total_len);
19583 			goto handled;
19584 		} else if (strnicmp(buf + strlen(CMD_NXP),
19585 				    PRIV_CMD_GET_SIGNAL_EXT,
19586 				    strlen(PRIV_CMD_GET_SIGNAL_EXT)) == 0) {
19587 			/* Get signal info */
19588 			len = woal_priv_get_signal_ext(priv, buf,
19589 						       priv_cmd.total_len);
19590 			goto handled;
19591 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SIGNAL,
19592 				    strlen(PRIV_CMD_GET_SIGNAL)) == 0) {
19593 			/* Get signal */
19594 			len = woal_priv_get_signal(priv, buf,
19595 						   priv_cmd.total_len);
19596 			goto handled;
19597 #endif
19598 #if defined(STA_SUPPORT)
19599 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PMFCFG,
19600 				    strlen(PRIV_CMD_PMFCFG)) == 0) {
19601 			/* Configure PMF */
19602 			len = woal_priv_set_get_pmfcfg(priv, buf,
19603 						       priv_cmd.total_len);
19604 			goto handled;
19605 #endif
19606 		} else if (strnicmp(buf + strlen(CMD_NXP),
19607 				    PRIV_CMD_INACTIVITYTO,
19608 				    strlen(PRIV_CMD_INACTIVITYTO)) == 0) {
19609 			/* Get/Set inactivity timeout extend */
19610 			len = woal_priv_inactivity_timeout_ext(
19611 				priv, buf, priv_cmd.total_len);
19612 			goto handled;
19613 		} else if (strnicmp(buf + strlen(CMD_NXP),
19614 				    PRIV_CMD_AMSDU_AGGR_CTRL,
19615 				    strlen(PRIV_CMD_AMSDU_AGGR_CTRL)) == 0) {
19616 			/* Enable/Disable amsdu_aggr_ctrl */
19617 			len = woal_priv_11n_amsdu_aggr_ctrl(priv, buf,
19618 							    priv_cmd.total_len);
19619 			goto handled;
19620 		} else if (strnicmp(buf + strlen(CMD_NXP),
19621 				    PRIV_CMD_MCAST_AGGR_GROUP,
19622 				    strlen(PRIV_CMD_MCAST_AGGR_GROUP)) == 0) {
19623 			/* mcast_aggr_group cfg*/
19624 			len = woal_priv_mcast_aggr_group_cfg(
19625 				priv, buf, priv_cmd.total_len);
19626 			goto handled;
19627 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MC_AGGR_CFG,
19628 				    strlen(PRIV_CMD_MC_AGGR_CFG)) == 0) {
19629 			/* mc_aggr_cfg*/
19630 			len = woal_priv_mc_aggr_cfg(priv, buf,
19631 						    priv_cmd.total_len);
19632 			goto handled;
19633 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_STATS,
19634 				    strlen(PRIV_CMD_STATS)) == 0) {
19635 			/* stats */
19636 			len = woal_priv_stats(priv, buf, priv_cmd.total_len);
19637 			goto handled;
19638 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CH_LOAD,
19639 				    strlen(PRIV_CMD_CH_LOAD)) == 0) {
19640 			/* mc_aggr_cfg*/
19641 			len = woal_priv_get_ch_load(priv, buf,
19642 						    priv_cmd.total_len);
19643 			goto handled;
19644 		} else if (strnicmp(buf + strlen(CMD_NXP),
19645 				    PRIV_CMD_CH_LOAD_RESULTS,
19646 				    strlen(PRIV_CMD_CH_LOAD_RESULTS)) == 0) {
19647 			/* mc_aggr_cfg*/
19648 			len = woal_priv_get_ch_load_results(priv, buf,
19649 							    priv_cmd.total_len);
19650 			goto handled;
19651 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CAP,
19652 				    strlen(PRIV_CMD_TX_BF_CAP)) == 0) {
19653 			/* Set/Get Transmit beamforming capabilities */
19654 			len = woal_priv_tx_bf_cap_ioctl(priv, buf,
19655 							priv_cmd.total_len);
19656 			goto handled;
19657 		} else if (strnicmp(buf + strlen(CMD_NXP),
19658 				    PRIV_CMD_SLEEP_PARAMS,
19659 				    strlen(PRIV_CMD_SLEEP_PARAMS)) == 0) {
19660 			/* Configure sleep parameters */
19661 			len = woal_priv_sleep_params_ioctl(priv, buf,
19662 							   priv_cmd.total_len);
19663 			goto handled;
19664 #ifdef UAP_SUPPORT
19665 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_NET_MON,
19666 				    strlen(PRIV_CMD_NET_MON)) == 0) {
19667 			/* Set/Get network monitor configurations */
19668 			len = woal_priv_net_monitor_ioctl(priv, buf,
19669 							  priv_cmd.total_len);
19670 			goto handled;
19671 #endif
19672 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
19673 		} else if (strnicmp(buf + strlen(CMD_NXP),
19674 				    PRIV_CMD_MONITOR_MODE,
19675 				    strlen(PRIV_CMD_MONITOR_MODE)) == 0) {
19676 			if (IS_STA_CFG80211(cfg80211_wext)) {
19677 				/* Set/Get monitor mode */
19678 				len = woal_priv_set_get_monitor_mode(
19679 					priv, buf, priv_cmd.total_len);
19680 			} else
19681 				len = sprintf(buf,
19682 					      "CFG80211 is not enabled\n") +
19683 				      1;
19684 			goto handled;
19685 #endif
19686 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_TESTING,
19687 				    strlen(PRIV_CMD_DFS_TESTING)) == 0) {
19688 			/* Set/Get DFS Testing settings */
19689 			len = woal_priv_dfs_testing(priv, buf,
19690 						    priv_cmd.total_len);
19691 			goto handled;
19692 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CLEAR_NOP,
19693 				    strlen(PRIV_CMD_CLEAR_NOP)) == 0) {
19694 			/* Set/Get DFS Testing settings */
19695 			len = woal_priv_clear_nop(priv, buf,
19696 						  priv_cmd.total_len);
19697 			goto handled;
19698 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_NOP_LIST,
19699 				    strlen(PRIV_CMD_NOP_LIST)) == 0) {
19700 			/* Set/Get DFS Testing settings */
19701 			len = woal_priv_nop_list(priv, buf, priv_cmd.total_len);
19702 			goto handled;
19703 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FAKE_RADAR,
19704 				    strlen(PRIV_CMD_FAKE_RADAR)) == 0) {
19705 			/* mcast_aggr_group cfg*/
19706 			len = woal_priv_fake_radar(priv, buf,
19707 						   priv_cmd.total_len);
19708 			goto handled;
19709 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS53_CFG,
19710 				    strlen(PRIV_CMD_DFS53_CFG)) == 0) {
19711 			/* Set/Get DFS W53 settings */
19712 			len = woal_priv_dfs53cfg(priv, buf, priv_cmd.total_len);
19713 			goto handled;
19714 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_MODE,
19715 				    strlen(PRIV_CMD_DFS_MODE)) == 0) {
19716 			/* Set/Get DFS mode settings */
19717 			len = woal_priv_dfs_mode(priv, buf, priv_cmd.total_len);
19718 			goto handled;
19719 #ifdef UAP_SUPPORT
19720 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_CAC,
19721 				    strlen(PRIV_CMD_DFS_CAC)) == 0) {
19722 			/* perform CAC */
19723 			len = woal_priv_do_dfs_cac(priv, buf,
19724 						   priv_cmd.total_len);
19725 			goto handled;
19726 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTODFS,
19727 				    strlen(PRIV_CMD_AUTODFS)) == 0) {
19728 			len = woal_priv_auto_dfs_cfg(priv, buf,
19729 						     priv_cmd.total_len);
19730 			goto handled;
19731 #endif
19732 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARB_CFG,
19733 				    strlen(PRIV_CMD_ARB_CFG)) == 0) {
19734 			/* Set/Get CFP table codes */
19735 			len = woal_priv_arbcfg(priv, buf, priv_cmd.total_len);
19736 			goto handled;
19737 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFP_CODE,
19738 				    strlen(PRIV_CMD_CFP_CODE)) == 0) {
19739 			/* Set/Get CFP table codes */
19740 			len = woal_priv_cfp_code(priv, buf, priv_cmd.total_len);
19741 			goto handled;
19742 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CWMODE,
19743 				    strlen(PRIV_CMD_CWMODE)) == 0) {
19744 			/* Set/Get Tx CWMode */
19745 			len = woal_priv_set_get_cwmode(priv, buf,
19746 						       priv_cmd.total_len);
19747 			goto handled;
19748 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ANT_CFG,
19749 				    strlen(PRIV_CMD_ANT_CFG)) == 0) {
19750 			/* Set/Get Tx/Rx antenna */
19751 			len = woal_priv_set_get_tx_rx_ant(priv, buf,
19752 							  priv_cmd.total_len);
19753 			goto handled;
19754 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SYSCLOCK,
19755 				    strlen(PRIV_CMD_SYSCLOCK)) == 0) {
19756 			/* Get/Set system clock */
19757 			len = woal_priv_sysclock(priv, buf, priv_cmd.total_len);
19758 			goto handled;
19759 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_KEY,
19760 				    strlen(PRIV_CMD_GET_KEY)) == 0) {
19761 			/* Get GTK/PTK */
19762 			len = woal_priv_get_key(priv, buf, priv_cmd.total_len);
19763 			goto handled;
19764 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCIATE,
19765 				    strlen(PRIV_CMD_ASSOCIATE)) == 0) {
19766 			/* Associate to a specific indexed entry in the
19767 			 * ScanTable */
19768 			len = woal_priv_associate_ssid_bssid(
19769 				priv, buf, priv_cmd.total_len);
19770 			goto handled;
19771 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CFG,
19772 				    strlen(PRIV_CMD_TX_BF_CFG)) == 0) {
19773 			/* Set/Get Transmit beamforming configuration */
19774 			len = woal_priv_tx_bf_cfg(priv, buf,
19775 						  priv_cmd.total_len);
19776 			goto handled;
19777 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BOOTSLEEP,
19778 				    strlen(PRIV_CMD_BOOTSLEEP)) == 0) {
19779 			len = woal_priv_bootsleep(priv, buf,
19780 						  priv_cmd.total_len);
19781 			goto handled;
19782 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PORT_CTRL,
19783 				    strlen(PRIV_CMD_PORT_CTRL)) == 0) {
19784 			/* Set/Get Port Control mode */
19785 			len = woal_priv_port_ctrl(priv, buf,
19786 						  priv_cmd.total_len);
19787 			goto handled;
19788 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXWATCHDOG,
19789 				    strlen(PRIV_CMD_TXWATCHDOG)) == 0) {
19790 			len = woal_priv_txwatchdog(priv, buf,
19791 						   priv_cmd.total_len);
19792 			goto handled;
19793 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PB_BYPASS,
19794 				    strlen(PRIV_CMD_PB_BYPASS)) == 0) {
19795 			/* Private IOCTL entry to get the By-passed TX packet
19796 			 * from upper layer */
19797 			len = woal_priv_bypassed_packet(priv, buf,
19798 							priv_cmd.total_len);
19799 			goto handled;
19800 #ifdef WIFI_DIRECT_SUPPORT
19801 #if defined(UAP_CFG80211)
19802 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_NOA,
19803 				    strlen(PRIV_CMD_CFG_NOA)) == 0) {
19804 			/* Set/Get P2P NoA (Notice of Absence) parameters */
19805 			len = woal_priv_cfg_noa(priv, buf, priv_cmd.total_len);
19806 			goto handled;
19807 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_OPP_PS,
19808 				    strlen(PRIV_CMD_CFG_OPP_PS)) == 0) {
19809 			/* Set/Get P2P OPP-PS parameters */
19810 			len = woal_priv_cfg_opp_ps(priv, buf,
19811 						   priv_cmd.total_len);
19812 			goto handled;
19813 #endif
19814 #endif
19815 		} else if (strnicmp(buf + strlen(CMD_NXP),
19816 				    PRIV_CMD_CFG_CLOCK_SYNC,
19817 				    strlen(PRIV_CMD_CFG_CLOCK_SYNC)) == 0) {
19818 			/* Set/Get P2P NoA (Notice of Absence) parameters */
19819 			len = woal_priv_cfg_clock_sync(priv, buf,
19820 						       priv_cmd.total_len);
19821 			goto handled;
19822 		} else if (strnicmp(buf + strlen(CMD_NXP),
19823 				    PRIV_CMD_CFG_GET_TSF_INFO,
19824 				    strlen(PRIV_CMD_CFG_GET_TSF_INFO)) == 0) {
19825 			/* Get TSF info */
19826 			len = woal_priv_cfg_get_tsf_info(priv, buf,
19827 							 priv_cmd.total_len);
19828 			goto handled;
19829 #ifdef UAP_SUPPORT
19830 		} else if (strnicmp(buf + strlen(CMD_NXP),
19831 				    PRIV_CMD_TARGET_CHANNEL,
19832 				    strlen(PRIV_CMD_TARGET_CHANNEL)) == 0) {
19833 			/* Get/Set Target channel*/
19834 			len = woal_priv_target_channel(priv, buf,
19835 						       priv_cmd.total_len);
19836 			goto handled;
19837 		} else if (strnicmp(buf + strlen(CMD_NXP),
19838 				    PRIV_CMD_BACKUP_CHANNEL,
19839 				    strlen(PRIV_CMD_BACKUP_CHANNEL)) == 0) {
19840 			/* Get/Set Backup channel*/
19841 			len = woal_priv_backup_channel(priv, buf,
19842 						       priv_cmd.total_len);
19843 			goto handled;
19844 #endif
19845 		} else if (strnicmp(buf + strlen(CMD_NXP),
19846 				    PRIV_CMD_DFS_REPEATER_CFG,
19847 				    strlen(PRIV_CMD_DFS_REPEATER_CFG)) == 0) {
19848 			/* Set/Get DFS_REPEATER mode */
19849 			len = woal_priv_dfs_repeater_cfg(priv, buf,
19850 							 priv_cmd.total_len);
19851 			goto handled;
19852 #ifdef WIFI_DIRECT_SUPPORT
19853 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19854 		} else if (strnicmp(buf + strlen(CMD_NXP),
19855 				    PRIV_CMD_MIRACAST_CFG,
19856 				    strlen(PRIV_CMD_MIRACAST_CFG)) == 0) {
19857 			/* Set/Get MIRACAST configuration parameters */
19858 			len = woal_priv_miracast_cfg(priv, buf,
19859 						     priv_cmd.total_len);
19860 			goto handled;
19861 #endif
19862 #endif
19863 		} else if (strnicmp(buf + strlen(CMD_NXP),
19864 				    PRIV_CMD_COEX_RX_WINSIZE,
19865 				    strlen(PRIV_CMD_COEX_RX_WINSIZE)) == 0) {
19866 			/* Set/Get control to coex RX window size */
19867 			len = woal_priv_coex_rx_winsize(priv, buf,
19868 							priv_cmd.total_len);
19869 			goto handled;
19870 		} else if (strnicmp(buf + strlen(CMD_NXP),
19871 				    PRIV_CMD_TX_AGGR_CTRL,
19872 				    strlen(PRIV_CMD_TX_AGGR_CTRL)) == 0) {
19873 			/* Set/Get control to TX AMPDU on infra link */
19874 			len = woal_priv_txaggrctrl(priv, buf,
19875 						   priv_cmd.total_len);
19876 			goto handled;
19877 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_TDLS,
19878 				    strlen(PRIV_CMD_AUTO_TDLS)) == 0) {
19879 			/* Set/Get control to enable/disable auto TDLS */
19880 			len = woal_priv_auto_tdls(priv, buf,
19881 						  priv_cmd.total_len);
19882 			goto handled;
19883 #ifdef PCIE
19884 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PCIE_REG_RW,
19885 				    strlen(PRIV_CMD_PCIE_REG_RW)) == 0) {
19886 			/* Read/Write PCIE register */
19887 			len = woal_priv_pcie_reg_rw(priv, buf,
19888 						    priv_cmd.total_len);
19889 			goto handled;
19890 		} else if (strnicmp(buf + strlen(CMD_NXP),
19891 				    PRIV_CMD_PCIE_BAR0_REG_RW,
19892 				    strlen(PRIV_CMD_PCIE_BAR0_REG_RW)) == 0) {
19893 			/* Read/Write PCIE register/memory from BAR0 */
19894 			len = woal_priv_pcie_bar0_reg_rw(priv, buf,
19895 							 priv_cmd.total_len);
19896 			goto handled;
19897 #endif
19898 		} else if (strnicmp(buf + strlen(CMD_NXP),
19899 				    PRIV_CMD_TDLS_IDLE_TIME,
19900 				    strlen(PRIV_CMD_TDLS_IDLE_TIME)) == 0) {
19901 			/* Set/Get TDLS idle timeout value */
19902 			len = woal_priv_tdls_idle_time(priv, buf,
19903 						       priv_cmd.total_len);
19904 			goto handled;
19905 		} else if (strnicmp(buf + strlen(CMD_NXP),
19906 				    PRIV_CMD_GET_SENSOR_TEMP,
19907 				    strlen(PRIV_CMD_GET_SENSOR_TEMP)) == 0) {
19908 			/* Get SOC temperature */
19909 			len = woal_priv_get_sensor_temp(priv, buf,
19910 							priv_cmd.total_len);
19911 			goto handled;
19912 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
19913 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19914 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_OFFLOAD,
19915 				    strlen(PRIV_CMD_DFS_OFFLOAD)) == 0) {
19916 			/* Enable/disable DFS offload */
19917 			if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
19918 				len = woal_priv_dfs_offload_enable(
19919 					priv, buf, priv_cmd.total_len);
19920 			else
19921 				len = sprintf(buf,
19922 					      "CFG80211 is not enabled\n") +
19923 				      1;
19924 			goto handled;
19925 #endif
19926 #endif
19927 #if defined(UAP_SUPPORT)
19928 		} else if (strnicmp(buf + strlen(CMD_NXP),
19929 				    PRIV_CMD_EXTEND_CHAN_SWITCH,
19930 				    strlen(PRIV_CMD_EXTEND_CHAN_SWITCH)) == 0) {
19931 			/* Extended channel switch */
19932 			len = woal_priv_extend_channel_switch(
19933 				priv, buf, priv_cmd.total_len);
19934 			goto handled;
19935 #endif
19936 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DYN_BW,
19937 				    strlen(PRIV_CMD_DYN_BW)) == 0) {
19938 			/* Set/Get dynamic bandwidth */
19939 			len = woal_priv_config_dyn_bw(priv, buf,
19940 						      priv_cmd.total_len);
19941 			goto handled;
19942 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IND_RST_CFG,
19943 				    strlen(PRIV_CMD_IND_RST_CFG)) == 0) {
19944 			/* Set/Get out band independent reset */
19945 			len = woal_priv_ind_rst_cfg(priv, buf,
19946 						    priv_cmd.total_len);
19947 			goto handled;
19948 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PER_PKT_CFG,
19949 				    strlen(PRIV_CMD_PER_PKT_CFG)) == 0) {
19950 			/* Get/Set per packet Txctl and Rxinfo configuration */
19951 			len = woal_priv_per_pkt_cfg(priv, buf,
19952 						    priv_cmd.total_len);
19953 			goto handled;
19954 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH_CTRL,
19955 				    strlen(PRIV_CMD_DEAUTH_CTRL)) == 0) {
19956 			len = woal_priv_deauth_ctrl(priv, buf,
19957 						    priv_cmd.total_len);
19958 			goto handled;
19959 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCFG,
19960 				    strlen(PRIV_CMD_11AXCFG)) == 0) {
19961 			pdata = buf + strlen(CMD_NXP) +
19962 				strlen(PRIV_CMD_11AXCFG);
19963 			len = priv_cmd.used_len - strlen(PRIV_CMD_11AXCFG) -
19964 			      strlen(CMD_NXP);
19965 			len = woal_priv_11axcfg_cmd(priv, pdata, len,
19966 						    priv_cmd.total_len);
19967 			len += strlen(PRIV_CMD_11AXCFG) + strlen(CMD_NXP);
19968 			goto handled;
19969 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TWT_SETUP,
19970 				    strlen(PRIV_CMD_TWT_SETUP)) == 0) {
19971 			pdata = buf + strlen(CMD_NXP) +
19972 				strlen(PRIV_CMD_TWT_SETUP);
19973 			len = priv_cmd.used_len - strlen(PRIV_CMD_TWT_SETUP) -
19974 			      strlen(CMD_NXP);
19975 			len = woal_priv_twt_setup(priv, pdata, len,
19976 						  priv_cmd.total_len);
19977 			len += strlen(PRIV_CMD_TWT_SETUP) + strlen(CMD_NXP);
19978 			goto handled;
19979 
19980 		} else if (strnicmp(buf + strlen(CMD_NXP),
19981 				    PRIV_CMD_TWT_TEARDOWN,
19982 				    strlen(PRIV_CMD_TWT_TEARDOWN)) == 0) {
19983 			pdata = buf + strlen(CMD_NXP) +
19984 				strlen(PRIV_CMD_TWT_TEARDOWN);
19985 			len = priv_cmd.used_len -
19986 			      strlen(PRIV_CMD_TWT_TEARDOWN) - strlen(CMD_NXP);
19987 			len = woal_priv_twt_teardown(priv, pdata, len,
19988 						     priv_cmd.total_len);
19989 			len += strlen(PRIV_CMD_TWT_TEARDOWN) + strlen(CMD_NXP);
19990 			goto handled;
19991 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19992 		} else if (strnicmp(buf + strlen(CMD_NXP),
19993 				    PRIV_CMD_GET_CFG_CHAN_LIST,
19994 				    strlen(PRIV_CMD_GET_CFG_CHAN_LIST)) == 0) {
19995 			/* Get txpwrlimit */
19996 			if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
19997 				len = woal_priv_getcfgchanlist(
19998 					priv, buf, priv_cmd.total_len);
19999 			else
20000 				len = sprintf(buf,
20001 					      "CFG80211 is not enabled\n") +
20002 				      1;
20003 			goto handled;
20004 #endif
20005 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_LPM,
20006 				    strlen(PRIV_CMD_LPM)) == 0) {
20007 			/* Set/Get low power mode */
20008 			len = woal_priv_set_get_lpm(priv, buf,
20009 						    priv_cmd.total_len);
20010 			goto handled;
20011 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TP_STATE,
20012 				    strlen(PRIV_CMD_TP_STATE)) == 0) {
20013 			/* Set/Get TP accounting state */
20014 			len = woal_priv_set_tp_state(priv, buf,
20015 						     priv_cmd.total_len);
20016 			goto handled;
20017 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPS_CFG,
20018 				    strlen(PRIV_CMD_IPS_CFG)) == 0) {
20019 			len = woal_priv_ips_cfg(priv, buf, priv_cmd.total_len);
20020 			goto handled;
20021 		} else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SB_UUID,
20022 				    strlen(PRIV_CMD_GET_SB_UUID)) == 0) {
20023 			len = woal_priv_get_uuid(priv, buf, priv_cmd.total_len);
20024 			goto handled;
20025 		} else {
20026 			PRINTM(MERROR,
20027 			       "Unknown NXP PRIVATE command %s, ignored\n",
20028 			       buf);
20029 			ret = -EFAULT;
20030 			goto done;
20031 		}
20032 	}
20033 #ifdef STA_SUPPORT
20034 	if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) ==
20035 	    0) {
20036 		pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
20037 		if (MLAN_STATUS_SUCCESS !=
20038 		    woal_set_rssi_low_threshold(priv, pdata, MOAL_IOCTL_WAIT)) {
20039 			ret = -EFAULT;
20040 			goto done;
20041 		}
20042 		len = sprintf(buf, "OK\n") + 1;
20043 	} else if (strncmp(buf, "SCAN-CFG", strlen("SCAN-CFG")) == 0) {
20044 		PRINTM(MIOCTL, "Set SCAN CFG\n");
20045 		if (MLAN_STATUS_SUCCESS !=
20046 		    woal_set_scan_cfg(priv, buf, priv_cmd.total_len)) {
20047 			ret = -EFAULT;
20048 			goto done;
20049 		}
20050 		len = sprintf(buf, "OK\n") + 1;
20051 	} else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
20052 		if (MLAN_STATUS_SUCCESS !=
20053 		    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
20054 			ret = -EFAULT;
20055 			goto done;
20056 		}
20057 		if (bss_info.media_connected) {
20058 			if (MLAN_STATUS_SUCCESS !=
20059 			    woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
20060 						 &signal)) {
20061 				ret = -EFAULT;
20062 				goto done;
20063 			}
20064 			len = sprintf(buf, "%.32s rssi %d\n",
20065 				      bss_info.ssid.ssid, signal.bcn_rssi_avg) +
20066 			      1;
20067 		} else {
20068 			len = sprintf(buf, "OK\n") + 1;
20069 		}
20070 	} else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
20071 		if (MLAN_STATUS_SUCCESS !=
20072 		    woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
20073 			ret = -EFAULT;
20074 			goto done;
20075 		}
20076 		PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
20077 		len = sprintf(buf, "LinkSpeed %d\n",
20078 			      (int)(rate.rate * 500000 / 1000000)) +
20079 		      1;
20080 	} else
20081 #endif
20082 		if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
20083 		len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
20084 			      priv->current_addr[0], priv->current_addr[1],
20085 			      priv->current_addr[2], priv->current_addr[3],
20086 			      priv->current_addr[4], priv->current_addr[5]) +
20087 		      1;
20088 	}
20089 #ifdef STA_SUPPORT
20090 	else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
20091 		if (MLAN_STATUS_SUCCESS !=
20092 		    woal_get_powermode(priv, &power_mode)) {
20093 			ret = -EFAULT;
20094 			goto done;
20095 		}
20096 		len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
20097 	} else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
20098 		if (MLAN_STATUS_SUCCESS !=
20099 		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
20100 			ret = -EFAULT;
20101 			goto done;
20102 		}
20103 		priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
20104 		PRINTM(MIOCTL, "Set Active Scan\n");
20105 		len = sprintf(buf, "OK\n") + 1;
20106 	} else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
20107 		if (MLAN_STATUS_SUCCESS !=
20108 		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
20109 			ret = -EFAULT;
20110 			goto done;
20111 		}
20112 		priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
20113 		PRINTM(MIOCTL, "Set Passive Scan\n");
20114 		len = sprintf(buf, "OK\n") + 1;
20115 	} else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
20116 		pdata = buf + strlen("POWERMODE") + 1;
20117 		if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
20118 			if (MLAN_STATUS_SUCCESS !=
20119 			    woal_set_powermode(priv, pdata)) {
20120 				ret = -EFAULT;
20121 				goto done;
20122 			}
20123 		}
20124 		len = sprintf(buf, "OK\n") + 1;
20125 	} else if (strncmp(buf, "SETROAMING", strlen("SETROAMING")) == 0) {
20126 		pdata = buf + strlen("SETROAMING") + 1;
20127 #ifdef STA_CFG80211
20128 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
20129 		if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
20130 			goto done;
20131 #endif
20132 #endif
20133 #ifdef STA_CFG80211
20134 		if (*pdata == '1') {
20135 			priv->roaming_enabled = MTRUE;
20136 			PRINTM(MIOCTL, "Roaming enabled\n");
20137 		} else if (*pdata == '0') {
20138 			priv->roaming_enabled = MFALSE;
20139 			PRINTM(MIOCTL, "Roaming disabled\n");
20140 		}
20141 #endif
20142 		len = sprintf(buf, "OK\n") + 1;
20143 	} else if (strncmp(buf, "ROAM", strlen("ROAM")) == 0) {
20144 		pdata = buf + strlen("ROAM") + 1;
20145 #ifdef STA_CFG80211
20146 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
20147 		if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
20148 			goto done;
20149 #endif
20150 #endif
20151 #ifdef STA_CFG80211
20152 		if (*pdata == '1') {
20153 			priv->roaming_enabled = MTRUE;
20154 			PRINTM(MIOCTL, "Roaming enabled\n");
20155 		} else if (*pdata == '0') {
20156 			priv->roaming_enabled = MFALSE;
20157 			PRINTM(MIOCTL, "Roaming disabled\n");
20158 		}
20159 #endif
20160 		len = sprintf(buf, "OK\n") + 1;
20161 	} else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
20162 		copy_len = strlen(buf) - strlen("COUNTRY") - 1;
20163 		if (copy_len > COUNTRY_CODE_LEN || copy_len <= 0) {
20164 			PRINTM(MERROR, "Invalid country length\n");
20165 			ret = -EFAULT;
20166 			goto done;
20167 		}
20168 		memset(country_code, 0, sizeof(country_code));
20169 		moal_memcpy_ext(priv->phandle, country_code,
20170 				buf + strlen("COUNTRY") + 1, copy_len,
20171 				COUNTRY_CODE_LEN);
20172 		PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
20173 		if (priv->phandle->params.cntry_txpwr) {
20174 			if (MLAN_STATUS_SUCCESS !=
20175 			    woal_request_country_power_table(priv,
20176 							     country_code)) {
20177 				ret = -EFAULT;
20178 				goto done;
20179 			}
20180 		}
20181 #ifdef STA_CFG80211
20182 		if (IS_STA_CFG80211(cfg80211_wext)) {
20183 			PRINTM(MIOCTL, "Notify country code=%s\n",
20184 			       country_code);
20185 			if (!moal_extflg_isset(priv->phandle,
20186 					       EXT_DISABLE_REGD_BY_DRIVER))
20187 				regulatory_hint(priv->wdev->wiphy,
20188 						country_code);
20189 			len = sprintf(buf, "OK\n") + 1;
20190 			goto done;
20191 		}
20192 #endif
20193 		if (MLAN_STATUS_SUCCESS !=
20194 		    woal_set_region_code(priv, country_code)) {
20195 			ret = -EFAULT;
20196 			goto done;
20197 		}
20198 		len = sprintf(buf, "OK\n") + 1;
20199 	} else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) ==
20200 		   0) {
20201 		PRINTM(MIOCTL, "Set Combo Scan\n");
20202 		if (MLAN_STATUS_SUCCESS !=
20203 		    woal_set_combo_scan(priv, buf, priv_cmd.total_len)) {
20204 			ret = -EFAULT;
20205 			goto done;
20206 		}
20207 		len = sprintf(buf, "OK\n") + 1;
20208 	} else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
20209 		if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
20210 			ret = -EFAULT;
20211 			goto done;
20212 		}
20213 		len = sprintf(buf, "Band %d\n", band) + 1;
20214 	} else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
20215 		pband = buf + strlen("SETBAND") + 1;
20216 		if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
20217 			ret = -EFAULT;
20218 			goto done;
20219 		}
20220 		len = sprintf(buf, "OK\n") + 1;
20221 	}
20222 #endif
20223 	else if (strncmp(buf, "START", strlen("START")) == 0) {
20224 		len = sprintf(buf, "OK\n") + 1;
20225 	} else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
20226 		len = sprintf(buf, "OK\n") + 1;
20227 	}
20228 #ifdef UAP_SUPPORT
20229 	else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
20230 		ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
20231 		if (ret)
20232 			goto done;
20233 		len = sprintf(buf, "OK\n") + 1;
20234 	} else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
20235 		ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
20236 		if (ret)
20237 			goto done;
20238 		len = sprintf(buf, "OK\n") + 1;
20239 	} else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) {
20240 		if (priv_cmd.total_len <= (int)strlen("AP_SET_CFG") + 1)
20241 			goto done;
20242 		pdata = buf + strlen("AP_SET_CFG") + 1;
20243 		ret = woal_uap_set_ap_cfg(priv, pdata,
20244 					  priv_cmd.total_len -
20245 						  strlen("AP_SET_CFG") - 1);
20246 		if (ret)
20247 			goto done;
20248 		len = sprintf(buf, "OK\n") + 1;
20249 	} else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) {
20250 		len = sprintf(buf, "OK\n") + 1;
20251 	} else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) ==
20252 		   0) {
20253 		/* TODO Add STA list support */
20254 		len = sprintf(buf, "OK\n") + 1;
20255 	}
20256 #endif
20257 	else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
20258 		/* it will be done by GUI */
20259 		len = sprintf(buf, "OK\n") + 1;
20260 	} else if (strncmp(buf, "SETSUSPENDMODE", strlen("SETSUSPENDMODE")) ==
20261 		   0) {
20262 		/* it will be done by GUI */
20263 		len = sprintf(buf, "OK\n") + 1;
20264 	} else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
20265 		len = sprintf(buf, "OK\n") + 1;
20266 	} else if (strncmp(buf, "BTCOEXSCAN-START",
20267 			   strlen("BTCOEXSCAN-START")) == 0) {
20268 		len = sprintf(buf, "OK\n") + 1;
20269 	} else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
20270 		   0) {
20271 		len = sprintf(buf, "OK\n") + 1;
20272 	}
20273 #ifdef STA_SUPPORT
20274 	else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
20275 		len = sprintf(buf, "OK\n") + 1;
20276 	} else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) ==
20277 		   0) {
20278 		if (MLAN_STATUS_SUCCESS !=
20279 		    woal_set_bg_scan(priv, buf, priv_cmd.total_len)) {
20280 			ret = -EFAULT;
20281 			goto done;
20282 		}
20283 		priv->bg_scan_start = MTRUE;
20284 		priv->bg_scan_reported = MFALSE;
20285 		len = sprintf(buf, "OK\n") + 1;
20286 	} else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
20287 		if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
20288 			if (MLAN_STATUS_FAILURE ==
20289 			    woal_stop_bg_scan(priv, MOAL_NO_WAIT)) {
20290 				ret = -EFAULT;
20291 				goto done;
20292 			}
20293 			priv->bg_scan_start = MFALSE;
20294 			priv->bg_scan_reported = MFALSE;
20295 		}
20296 		len = sprintf(buf, "OK\n") + 1;
20297 	} else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
20298 		   0) {
20299 #ifdef MEF_CFG_RX_FILTER
20300 		ret = woal_set_rxfilter(priv, MTRUE);
20301 		if (ret)
20302 			goto done;
20303 #endif
20304 		len = sprintf(buf, "OK\n") + 1;
20305 	} else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) ==
20306 		   0) {
20307 #ifdef MEF_CFG_RX_FILTER
20308 		ret = woal_set_rxfilter(priv, MFALSE);
20309 		if (ret)
20310 			goto done;
20311 #endif
20312 		len = sprintf(buf, "OK\n") + 1;
20313 	}
20314 #ifdef STA_CFG80211
20315 	else if (strncmp(buf, "GET_EVENT", strlen("GET_EVENT")) == 0) {
20316 		if (IS_STA_CFG80211(cfg80211_wext)) {
20317 			if (priv->last_event & EVENT_BG_SCAN_REPORT)
20318 				woal_inform_bss_from_scan_result(
20319 					priv, NULL, MOAL_IOCTL_WAIT);
20320 		}
20321 		len = sprintf(buf, "EVENT=%d\n", priv->last_event) + 1;
20322 		priv->last_event = 0;
20323 	} else if (strncmp(buf, "GET_802_11W", strlen("GET_802_11W")) == 0) {
20324 		len = sprintf(buf, "802_11W=ENABLED\n") + 1;
20325 	}
20326 #endif /* STA_CFG80211 */
20327 	else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
20328 		pdata = buf + strlen("RXFILTER-ADD") + 1;
20329 		if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
20330 			ret = -EFAULT;
20331 			goto done;
20332 		}
20333 		len = sprintf(buf, "OK\n") + 1;
20334 	} else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
20335 		   0) {
20336 		pdata = buf + strlen("RXFILTER-REMOVE") + 1;
20337 		if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
20338 			ret = -EFAULT;
20339 			goto done;
20340 		}
20341 		len = sprintf(buf, "OK\n") + 1;
20342 	} else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
20343 		pdata = buf + strlen("QOSINFO") + 1;
20344 #ifdef STA_SUPPORT
20345 		if (MLAN_STATUS_SUCCESS !=
20346 		    woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
20347 			ret = -EFAULT;
20348 			goto done;
20349 		}
20350 #endif
20351 		len = sprintf(buf, "OK\n") + 1;
20352 	} else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
20353 		pdata = buf + strlen("SLEEPPD") + 1;
20354 		if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
20355 			ret = -EFAULT;
20356 			goto done;
20357 		}
20358 		len = sprintf(buf, "OK\n") + 1;
20359 	} else if (strncmp(buf, "SET_AP_WPS_P2P_IE",
20360 			   strlen("SET_AP_WPS_P2P_IE")) == 0) {
20361 		pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1;
20362 		/* Android cmd format:
20363 		 * "SET_AP_WPS_P2P_IE 1"  -- beacon IE
20364 		 * "SET_AP_WPS_P2P_IE 2"  -- proberesp IE
20365 		 * "SET_AP_WPS_P2P_IE 4"  -- assocresp IE
20366 		 */
20367 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
20368 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
20369 		if (MLAN_STATUS_SUCCESS !=
20370 		    woal_set_ap_wps_p2p_ie(priv, (t_u8 *)pdata,
20371 					   priv_cmd.used_len -
20372 						   strlen("SET_AP_WPS_P2P_IE") -
20373 						   1)) {
20374 			ret = -EFAULT;
20375 			goto done;
20376 		}
20377 #endif
20378 #endif
20379 		len = sprintf(buf, "OK\n") + 1;
20380 	}
20381 #endif
20382 	else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) {
20383 		memset(buf, 0x0, (size_t)priv_cmd.total_len);
20384 		moal_memcpy_ext(priv->phandle, buf, priv->current_addr,
20385 				ETH_ALEN, (t_u32)priv_cmd.total_len);
20386 		len = ETH_ALEN;
20387 	} else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) {
20388 		/* TODO
20389 		 * Just return '\0'
20390 		 */
20391 		memset(buf, 0x0, (size_t)priv_cmd.total_len);
20392 		*buf = 0;
20393 		len = 1;
20394 	} else if (strnicmp(buf, "MIRACAST", strlen("MIRACAST")) == 0) {
20395 		pdata = buf + strlen("MIRACAST");
20396 		/* Android cmd format:
20397 		 * "MIRACAST 0"  -- disabled
20398 		 * "MIRACAST 1"  -- operating as source
20399 		 * "MIRACAST 2"  -- operating as sink
20400 		 */
20401 #ifdef WIFI_DIRECT_SUPPORT
20402 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
20403 		if (MLAN_STATUS_SUCCESS !=
20404 		    woal_set_miracast_mode(priv, (t_u8 *)pdata,
20405 					   priv_cmd.used_len -
20406 						   strlen("MIRACAST"))) {
20407 			ret = -EFAULT;
20408 			goto done;
20409 		}
20410 #endif
20411 #endif
20412 		len = sprintf(buf, "OK\n") + 1;
20413 	} else if (strnicmp(buf, "SCAN_TIMING", strlen("SCAN_TIMING")) == 0) {
20414 #ifdef WIFI_DIRECT_SUPPORT
20415 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
20416 		if (MLAN_STATUS_SUCCESS !=
20417 		    woal_set_scan_chan_gap(priv, buf, priv_cmd.total_len)) {
20418 			ret = -EFAULT;
20419 			goto done;
20420 		}
20421 #endif
20422 #endif
20423 		len = sprintf(buf, "OK\n") + 1;
20424 	} else if (strnicmp(buf, "BA_WSIZE_RX", strlen("BA_WSIZE_RX")) == 0) {
20425 		pdata = buf + strlen("BA_WSIZE_RX") + 1;
20426 		len = priv_cmd.total_len - strlen("BA_WSIZE_RX") - 1;
20427 		if (MLAN_STATUS_SUCCESS !=
20428 		    woal_set_rx_ba_winsize(priv, pdata, len)) {
20429 			ret = -EFAULT;
20430 			goto done;
20431 		}
20432 		len = sprintf(buf, "OK\n") + 1;
20433 	} else if (strnicmp(buf, "BA_WSIZE_TX", strlen("BA_WSIZE_TX")) == 0) {
20434 		pdata = buf + strlen("BA_WSIZE_TX") + 1;
20435 		len = priv_cmd.total_len - strlen("BA_WSIZE_TX") - 1;
20436 		if (MLAN_STATUS_SUCCESS !=
20437 		    woal_set_tx_ba_winsize(priv, pdata, len)) {
20438 			ret = -EFAULT;
20439 			goto done;
20440 		}
20441 		len = sprintf(buf, "OK\n") + 1;
20442 	} else if (strncmp(buf, "FAKE_SCAN_COMPLETE",
20443 			   strlen("FAKE_SCAN_COMPLETE")) == 0) {
20444 		pdata = buf + strlen("FAKE_SCAN_COMPLETE") + 1;
20445 #ifdef STA_CFG80211
20446 		if (*pdata == '1') {
20447 			priv->fake_scan_complete = MTRUE;
20448 			PRINTM(MIOCTL, "fake scan complete enabled\n");
20449 		} else if (*pdata == '0') {
20450 			priv->fake_scan_complete = MFALSE;
20451 			PRINTM(MIOCTL, "fake scan complete disabled\n");
20452 		}
20453 #endif
20454 		len = sprintf(buf, "OK\n") + 1;
20455 	}
20456 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
20457 #ifdef WIFI_DIRECT_SUPPORT
20458 	else if (strncmp(buf, "P2P_PERIODIC_SLEEP",
20459 			 strlen("P2P_PERIODIC_SLEEP")) == 0) {
20460 		if (MLAN_STATUS_SUCCESS !=
20461 		    woal_p2p_ps_cfg(priv, buf, priv_cmd.total_len)) {
20462 			ret = -EFAULT;
20463 			goto done;
20464 		}
20465 		len = sprintf(buf, "OK\n") + 1;
20466 	}
20467 #endif
20468 #endif
20469 	else if (strncmp(buf, "WLS_BATCHING", strlen("WLS_BATCHING")) == 0) {
20470 		/* TODO */
20471 		len = sprintf(buf, "OK\n") + 1;
20472 	} else if (strncmp(buf, "TDLS_CS_CHAN", strlen("TDLS_CS_CHAN")) == 0) {
20473 		len = woal_priv_tdls_cs_chan(priv, buf, priv_cmd.total_len);
20474 	}
20475 #if defined(UAP_SUPPORT)
20476 	else if (strncmp(buf, "P2P_ECSA", strlen("P2P_ECSA")) == 0) {
20477 		len = woal_priv_p2p_ecsa(priv, buf, priv_cmd.total_len);
20478 	}
20479 #endif
20480 	else if (strncmp(buf, "FAKEMAC", strlen("FAKEMAC")) == 0) {
20481 		len = woal_priv_config_random_mac(priv, buf,
20482 						  priv_cmd.total_len);
20483 	} else if (strncmp(buf, "SETROAMOFFLOAD", strlen("SETROAMOFFLOAD")) ==
20484 		   0) {
20485 		len = woal_priv_set_roam_offload(priv, buf, priv_cmd.total_len);
20486 	} else if (strncmp(buf, "SETROAMOFFLAPLIST",
20487 			   strlen("SETROAMOFFLAPLIST")) == 0) {
20488 		len = woal_priv_set_roam_offload_aplist(priv, buf,
20489 							priv_cmd.total_len);
20490 	} else if (strncmp(buf, "CFGROAMOFFLOAD", strlen("CFGROAMOFFLOAD")) ==
20491 		   0) {
20492 		len = woal_priv_roam_offload_cfg(priv, buf, priv_cmd.total_len);
20493 	} else if (strncmp(buf, "SETROAMPASSPHRASE",
20494 			   strlen("SETROAMPASSPHRASE")) == 0) {
20495 		len = woal_priv_set_roam_passphrase(priv, buf,
20496 						    priv_cmd.total_len);
20497 	} else if (strncmp(buf, PRIV_CMD_CLOUD_KEEP_ALIVE,
20498 			   strlen(PRIV_CMD_CLOUD_KEEP_ALIVE)) == 0) {
20499 		len = woal_priv_cloud_keep_alive(priv, buf, priv_cmd.total_len);
20500 	} else if (strnicmp(buf, PRIV_CMD_TX_RX_HISTOGRAM,
20501 			    strlen(PRIV_CMD_TX_RX_HISTOGRAM)) == 0) {
20502 		/* Get TX/RX histogram statistic */
20503 		len = woal_priv_get_rx_tx_histogram(priv, buf,
20504 						    priv_cmd.total_len);
20505 		goto handled;
20506 	} else if (strnicmp(buf, PRIV_CMD_GET_CHNRGPWR,
20507 			    strlen(PRIV_CMD_GET_CHNRGPWR)) == 0) {
20508 		/* Get chnrgpwr */
20509 		len = woal_priv_get_chnrgpwr(priv, buf, priv_cmd.total_len);
20510 		goto handled;
20511 	} else if (strnicmp(buf, PRIV_CMD_GET_TXPWR_LIMIT,
20512 			    strlen(PRIV_CMD_GET_TXPWR_LIMIT)) == 0) {
20513 		/* Get txpwrlimit */
20514 		len = woal_priv_get_txpwrlimit(priv, buf, priv_cmd.total_len);
20515 		goto handled;
20516 	} else {
20517 		PRINTM(MIOCTL, "Unknown PRIVATE command: %s, ignored\n", buf);
20518 		ret = -EFAULT;
20519 		goto done;
20520 	}
20521 
20522 handled:
20523 	PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
20524 
20525 	if (len > 0) {
20526 		priv_cmd.used_len = len;
20527 		if (priv_cmd.used_len <= priv_cmd.total_len) {
20528 			memset(buf + priv_cmd.used_len, 0,
20529 			       (size_t)(CMD_BUF_LEN - priv_cmd.used_len));
20530 			if (copy_to_user((void __user *)cmd_buf, buf,
20531 					 priv_cmd.total_len)) {
20532 				PRINTM(MERROR,
20533 				       "%s: failed to copy data to user buffer\n",
20534 				       __FUNCTION__);
20535 				ret = -EFAULT;
20536 				goto done;
20537 			}
20538 			if (copy_to_user(req->ifr_data, &priv_cmd,
20539 					 sizeof(android_wifi_priv_cmd))) {
20540 				PRINTM(MERROR,
20541 				       "%s: failed to copy command header to user buffer\n",
20542 				       __FUNCTION__);
20543 				ret = -EFAULT;
20544 			}
20545 		} else {
20546 			PRINTM(MERROR,
20547 			       "%s: the buffer supplied by appl is too small (supplied: %d, used: %d)\n",
20548 			       __FUNCTION__, priv_cmd.total_len,
20549 			       priv_cmd.used_len);
20550 			ret = -EFAULT;
20551 		}
20552 	} else {
20553 		ret = len;
20554 	}
20555 
20556 done:
20557 	kfree(buf);
20558 	LEAVE();
20559 	return ret;
20560 }
20561 
20562 /********************************************************
20563 			Global Functions
20564 ********************************************************/
20565 /**
20566  *  @brief Create a brief scan resp to relay basic BSS info to the app layer
20567  *
20568  *  When the beacon/probe response has not been buffered, use the saved BSS
20569  *    information available to provide a minimum response for the application
20570  *    ioctl retrieval routines.  Include:
20571  *        - Timestamp
20572  *        - Beacon Period
20573  *        - Capabilities (including WMM Element if available)
20574  *        - SSID
20575  *
20576  *  @param ppbuffer  Output parameter: Buffer used to create basic scan rsp
20577  *  @param pbss_desc Pointer to a BSS entry in the scan table to create
20578  *                   scan response from for delivery to the application layer
20579  *
20580  *  @return          N/A
20581  */
wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer,BSSDescriptor_t * pbss_desc)20582 void wlan_scan_create_brief_table_entry(t_u8 **ppbuffer,
20583 					BSSDescriptor_t *pbss_desc)
20584 {
20585 	t_u8 *ptmp_buf = *ppbuffer;
20586 	t_u8 tmp_ssid_hdr[2];
20587 	t_u8 ie_len = 0;
20588 
20589 	ENTER();
20590 
20591 	moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->time_stamp,
20592 			sizeof(pbss_desc->time_stamp),
20593 			sizeof(pbss_desc->time_stamp));
20594 	ptmp_buf += sizeof(pbss_desc->time_stamp);
20595 
20596 	moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->beacon_period,
20597 			sizeof(pbss_desc->beacon_period),
20598 			sizeof(pbss_desc->beacon_period));
20599 	ptmp_buf += sizeof(pbss_desc->beacon_period);
20600 
20601 	moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->cap_info,
20602 			sizeof(pbss_desc->cap_info),
20603 			sizeof(pbss_desc->cap_info));
20604 	ptmp_buf += sizeof(pbss_desc->cap_info);
20605 
20606 	tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */
20607 	tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len;
20608 	moal_memcpy_ext(NULL, ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr),
20609 			sizeof(tmp_ssid_hdr));
20610 	ptmp_buf += sizeof(tmp_ssid_hdr);
20611 
20612 	moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->ssid.ssid,
20613 			pbss_desc->ssid.ssid_len, pbss_desc->ssid.ssid_len);
20614 	ptmp_buf += pbss_desc->ssid.ssid_len;
20615 
20616 	if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
20617 		ie_len = sizeof(IEEEtypes_Header_t) +
20618 			 pbss_desc->wmm_ie.vend_hdr.len;
20619 		moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->wmm_ie, ie_len,
20620 				ie_len);
20621 		ptmp_buf += ie_len;
20622 	}
20623 
20624 	if (pbss_desc->pwpa_ie) {
20625 		if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
20626 			ie_len = sizeof(IEEEtypes_Header_t) +
20627 				 (*(pbss_desc->pwpa_ie)).vend_hdr.len;
20628 			moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->pwpa_ie,
20629 					ie_len, ie_len);
20630 		}
20631 
20632 		ptmp_buf += ie_len;
20633 	}
20634 	if (pbss_desc->prsn_ie) {
20635 		if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
20636 			ie_len = sizeof(IEEEtypes_Header_t) +
20637 				 (*(pbss_desc->prsn_ie)).ieee_hdr.len;
20638 			moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->prsn_ie,
20639 					ie_len, ie_len);
20640 		}
20641 
20642 		ptmp_buf += ie_len;
20643 	}
20644 	*ppbuffer = ptmp_buf;
20645 	LEAVE();
20646 }
20647 
20648 /**
20649  *  @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
20650  *         Descriptor for inclusion in the ioctl response to the user space
20651  *         application.
20652  *
20653  *
20654  *  @param pbss_desc   Pointer to a BSS entry in the scan table to form
20655  *                     scan response from for delivery to the application layer
20656  *  @param ppbuffer    Output parameter: Buffer used to output scan return
20657  * struct
20658  *  @param pspace_left Output parameter: Number of bytes available in the
20659  *                     response buffer.
20660  *
20661  *  @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
20662  */
wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc,t_u8 ** ppbuffer,int * pspace_left)20663 int wlan_get_scan_table_ret_entry(BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer,
20664 				  int *pspace_left)
20665 {
20666 	wlan_ioctl_get_scan_table_entry *prsp_entry;
20667 	wlan_ioctl_get_scan_table_entry tmp_rsp_entry;
20668 	int space_needed;
20669 	t_u8 *pcurrent;
20670 	int variable_size;
20671 
20672 	const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry);
20673 
20674 	ENTER();
20675 
20676 	pcurrent = *ppbuffer;
20677 
20678 	/* The variable size returned is the stored beacon size */
20679 	variable_size = pbss_desc->beacon_buf_size;
20680 
20681 	/* If we stored a beacon and its size was zero, set the variable
20682 	 *  size return value to the size of the brief scan response
20683 	 *  wlan_scan_create_brief_table_entry creates.  Also used if
20684 	 *  we are not configured to store beacons in the first place
20685 	 */
20686 	if (!variable_size) {
20687 		variable_size = pbss_desc->ssid.ssid_len + 2;
20688 		variable_size += (sizeof(pbss_desc->beacon_period) +
20689 				  sizeof(pbss_desc->time_stamp) +
20690 				  sizeof(pbss_desc->cap_info));
20691 		if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
20692 			variable_size += (sizeof(IEEEtypes_Header_t) +
20693 					  pbss_desc->wmm_ie.vend_hdr.len);
20694 		}
20695 
20696 		if (pbss_desc->pwpa_ie) {
20697 			if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
20698 			    WPA_IE) {
20699 				variable_size +=
20700 					(sizeof(IEEEtypes_Header_t) +
20701 					 (*(pbss_desc->pwpa_ie)).vend_hdr.len);
20702 			}
20703 		}
20704 
20705 		if (pbss_desc->prsn_ie) {
20706 			if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
20707 			    RSN_IE) {
20708 				variable_size +=
20709 					(sizeof(IEEEtypes_Header_t) +
20710 					 (*(pbss_desc->prsn_ie)).ieee_hdr.len);
20711 			}
20712 		}
20713 	}
20714 
20715 	space_needed = fixed_size + variable_size;
20716 
20717 	PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n", space_needed,
20718 	       *pspace_left);
20719 
20720 	if (space_needed >= *pspace_left) {
20721 		*pspace_left = 0;
20722 		LEAVE();
20723 		return -E2BIG;
20724 	}
20725 
20726 	*pspace_left -= space_needed;
20727 
20728 	tmp_rsp_entry.fixed_field_length =
20729 		(sizeof(tmp_rsp_entry) -
20730 		 sizeof(tmp_rsp_entry.fixed_field_length) -
20731 		 sizeof(tmp_rsp_entry.bss_info_length));
20732 
20733 	moal_memcpy_ext(NULL, tmp_rsp_entry.fixed_fields.bssid,
20734 			pbss_desc->mac_address,
20735 			sizeof(prsp_entry->fixed_fields.bssid),
20736 			sizeof(prsp_entry->fixed_fields.bssid));
20737 
20738 	tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi;
20739 	tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel;
20740 	tmp_rsp_entry.fixed_fields.chan_load = pbss_desc->chan_load;
20741 	tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf;
20742 	tmp_rsp_entry.bss_info_length = variable_size;
20743 
20744 	/*
20745 	 *  Copy fixed fields to user space
20746 	 */
20747 	moal_memcpy_ext(NULL, pcurrent, &tmp_rsp_entry, fixed_size, fixed_size);
20748 	pcurrent += fixed_size;
20749 
20750 	if (pbss_desc->pbeacon_buf) {
20751 		/*
20752 		 *  Copy variable length elements to user space
20753 		 */
20754 		moal_memcpy_ext(NULL, pcurrent, pbss_desc->pbeacon_buf,
20755 				pbss_desc->beacon_buf_size,
20756 				pbss_desc->beacon_buf_size);
20757 
20758 		pcurrent += pbss_desc->beacon_buf_size;
20759 	} else {
20760 		wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc);
20761 	}
20762 
20763 	*ppbuffer = pcurrent;
20764 
20765 	LEAVE();
20766 
20767 	return MLAN_STATUS_SUCCESS;
20768 }
20769 
20770 /**
20771  *  @brief ioctl function - entry point
20772  *
20773  *  @param dev      A pointer to net_device structure
20774  *  @param req      A pointer to ifreq structure
20775  *  @param cmd      Command
20776  *
20777  *  @return          0 --success, otherwise fail
20778  */
20779 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
woal_do_ioctl(struct net_device * dev,struct ifreq * req,void __user * data,int cmd)20780 int woal_do_ioctl(struct net_device *dev, struct ifreq *req, void __user *data,
20781 		  int cmd)
20782 #else
20783 int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
20784 #endif
20785 
20786 {
20787 	int ret = 0;
20788 
20789 	ENTER();
20790 
20791 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
20792 	if (in_compat_syscall()) /* not implemented yet */
20793 		return -EOPNOTSUPP;
20794 #endif
20795 
20796 	PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd);
20797 	switch (cmd) {
20798 	case WOAL_ANDROID_DEF_CMD:
20799 		/** android default ioctl ID is SIOCDEVPRIVATE + 1 */
20800 		ret = woal_android_priv_cmd(dev, req);
20801 		break;
20802 	case WOAL_CUSTOM_IE_CFG:
20803 		ret = woal_custom_ie_ioctl(dev, req);
20804 		break;
20805 	case WOAL_MGMT_FRAME_TX:
20806 		ret = woal_send_host_packet(dev, req);
20807 		break;
20808 	case WOAL_TDLS_CONFIG:
20809 		ret = woal_tdls_config_ioctl(dev, req);
20810 		break;
20811 	case WOAL_ANDROID_PRIV_CMD:
20812 		ret = woal_android_priv_cmd(dev, req);
20813 		break;
20814 	case WOAL_GET_BSS_TYPE:
20815 		ret = woal_get_bss_type(dev, req);
20816 		break;
20817 	default:
20818 #if defined(STA_WEXT)
20819 #ifdef STA_SUPPORT
20820 		ret = woal_wext_do_ioctl(dev, req, cmd);
20821 #else
20822 		ret = -EINVAL;
20823 #endif
20824 #else
20825 		ret = -EINVAL;
20826 #endif
20827 		break;
20828 	}
20829 
20830 	LEAVE();
20831 	return ret;
20832 }
20833