xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlinux/moal_priv.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file  moal_priv.c
2   *
3   * @brief This file contains standard ioctl functions
4   *
5   * Copyright (C) 2008-2017, Marvell International Ltd.
6   *
7   * This software file (the "File") is distributed by Marvell International
8   * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9   * (the "License").  You may use, redistribute and/or modify this File in
10   * accordance with the terms and conditions of the License, a copy of which
11   * is available by writing to the Free Software Foundation, Inc.,
12   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13   * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14   *
15   * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16   * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17   * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
18   * this warranty disclaimer.
19   *
20   */
21 
22 /************************************************************************
23 Change log:
24     10/30/2008: initial version
25 ************************************************************************/
26 
27 #include	"moal_main.h"
28 #include	"moal_sdio.h"
29 
30 #include    "moal_eth_ioctl.h"
31 
32 /********************************************************
33 			Local Variables
34 ********************************************************/
35 /** Bands supported in Infra mode */
36 static t_u8 SupportedInfraBand[] = {
37 	BAND_B,
38 	BAND_B | BAND_G, BAND_G,
39 	BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
40 	BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A,
41 	BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
42 		BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN,
43 };
44 
45 /** Bands supported in Ad-Hoc mode */
46 static t_u8 SupportedAdhocBand[] = {
47 	BAND_B, BAND_B | BAND_G, BAND_G,
48 	BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
49 	BAND_A,
50 	BAND_AN, BAND_A | BAND_AN,
51 };
52 
53 /********************************************************
54 			Global Variables
55 ********************************************************/
56 
57 extern int cfg80211_wext;
58 
59 /********************************************************
60 			Local Functions
61 ********************************************************/
62 
63 /**
64  * @brief Associated to a specific indexed entry in the ScanTable
65  *
66  * @param priv         A pointer to moal_private structure
67  * @param wrq          A pointer to iwreq structure
68  *
69  * @return             0 --success, otherwise fail
70  */
71 static int
woal_associate_ssid_bssid(moal_private * priv,struct iwreq * wrq)72 woal_associate_ssid_bssid(moal_private *priv, struct iwreq *wrq)
73 {
74 	mlan_ssid_bssid ssid_bssid;
75 #ifdef REASSOCIATION
76 	mlan_bss_info bss_info;
77 #endif
78 	char buf[64];
79 	t_u8 buflen;
80 	t_u8 mac_idx;
81 	t_u8 i;
82 
83 	ENTER();
84 
85 	memset(&ssid_bssid, 0, sizeof(ssid_bssid));
86 	mac_idx = 0;
87 	buflen = MIN(wrq->u.data.length, (sizeof(buf) - 1));
88 	memset(buf, 0, sizeof(buf));
89 
90 	if (buflen < (3 * ETH_ALEN) + 2) {
91 		PRINTM(MERROR,
92 		       "Associate: Insufficient length in IOCTL input\n");
93 
94 		/* buffer should be at least 3 characters per BSSID octet "00:"
95 		 **   plus a space separater and at least 1 char in the SSID
96 		 */
97 		LEAVE();
98 		return -EINVAL;
99 	}
100 
101 	if (copy_from_user(buf, wrq->u.data.pointer, buflen) != 0) {
102 		/* copy_from_user failed  */
103 		PRINTM(MERROR, "Associate: copy from user failed\n");
104 		LEAVE();
105 		return -EINVAL;
106 	}
107 
108 	for (i = 0; (i < buflen) && (buf[i] == ' '); i++) {
109 		/* Skip white space */
110 	}
111 
112 	/* Copy/Convert the BSSID */
113 	for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); i++) {
114 		if (buf[i] == ':') {
115 			mac_idx++;
116 		} else {
117 			if (mac_idx < ETH_ALEN)
118 				ssid_bssid.bssid[mac_idx] =
119 					(t_u8)woal_atox(buf + i);
120 
121 			while ((i < buflen) && (isxdigit(buf[i + 1]))) {
122 				/* Skip entire hex value */
123 				i++;
124 			}
125 		}
126 	}
127 
128 	/* Skip one space between the BSSID and start of the SSID */
129 	i++;
130 
131 	/* Copy the SSID */
132 	ssid_bssid.ssid.ssid_len = buflen - i - 1;
133 	memcpy(ssid_bssid.ssid.ssid, buf + i, sizeof(ssid_bssid.ssid.ssid));
134 
135 	PRINTM(MCMND, "iwpriv assoc: AP=[" MACSTR "], ssid(%d)=[%s]\n",
136 	       MAC2STR(ssid_bssid.bssid),
137 	       (int)ssid_bssid.ssid.ssid_len, ssid_bssid.ssid.ssid);
138 
139 	if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
140 						  MOAL_IOCTL_WAIT,
141 						  &ssid_bssid)) {
142 		LEAVE();
143 		return -EFAULT;
144 	}
145 #ifdef REASSOCIATION
146 	memset(&bss_info, 0x00, sizeof(bss_info));
147 	if (MLAN_STATUS_SUCCESS == woal_get_bss_info(priv,
148 						     MOAL_IOCTL_WAIT,
149 						     &bss_info)) {
150 		memcpy(&priv->prev_ssid_bssid.ssid,
151 		       &bss_info.ssid, sizeof(mlan_802_11_ssid));
152 		memcpy(&priv->prev_ssid_bssid.bssid,
153 		       &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
154 	}
155 #endif /* REASSOCIATION */
156 
157 	LEAVE();
158 	return 0;
159 }
160 
161 /**
162  *  @brief Copy Rates
163  *
164  *  @param dest    A pointer to destination buffer
165  *  @param pos     The position for copy
166  *  @param src     A pointer to source buffer
167  *  @param len     Length of the source buffer
168  *
169  *  @return        Number of rates copied
170  */
171 static inline int
woal_copy_rates(t_u8 * dest,int pos,t_u8 * src,int len)172 woal_copy_rates(t_u8 *dest, int pos, t_u8 *src, int len)
173 {
174 	int i;
175 
176 	for (i = 0; i < len && src[i]; i++, pos++) {
177 		if (pos >= MLAN_SUPPORTED_RATES)
178 			break;
179 		dest[pos] = src[i];
180 	}
181 	return pos;
182 }
183 
184 /**
185  *  @brief Performs warm reset
186  *
187  *  @param priv         A pointer to moal_private structure
188  *
189  *  @return             0/MLAN_STATUS_SUCCESS --success, otherwise fail
190  */
191 static int
woal_warm_reset(moal_private * priv)192 woal_warm_reset(moal_private *priv)
193 {
194 	int ret = 0;
195 	int intf_num;
196 	moal_handle *handle = priv->phandle;
197 	mlan_ioctl_req *req = NULL;
198 	mlan_ds_misc_cfg *misc = NULL;
199 #if defined(WIFI_DIRECT_SUPPORT)
200 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
201 #if defined(STA_WEXT) || defined(UAP_WEXT)
202 	t_u8 bss_role = MLAN_BSS_ROLE_STA;
203 #endif
204 #endif
205 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
206 	mlan_status status = MLAN_STATUS_SUCCESS;
207 
208 	ENTER();
209 
210 	woal_cancel_cac_block(priv);
211 
212 	/* Reset all interfaces */
213 	ret = woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
214 
215 	/* Initialize private structures */
216 	for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
217 		woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
218 #if defined(WIFI_DIRECT_SUPPORT)
219 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
220 #if defined(STA_WEXT) || defined(UAP_WEXT)
221 		if ((handle->priv[intf_num]->bss_type ==
222 		     MLAN_BSS_TYPE_WIFIDIRECT) &&
223 		    (GET_BSS_ROLE(handle->priv[intf_num]) ==
224 		     MLAN_BSS_ROLE_UAP)) {
225 			if (MLAN_STATUS_SUCCESS !=
226 			    woal_bss_role_cfg(handle->priv[intf_num],
227 					      MLAN_ACT_SET, MOAL_IOCTL_WAIT,
228 					      &bss_role)) {
229 				ret = -EFAULT;
230 				goto done;
231 			}
232 		}
233 #endif /* STA_WEXT || UAP_WEXT */
234 #endif /* STA_SUPPORT && UAP_SUPPORT */
235 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
236 	}
237 
238 	/* Restart the firmware */
239 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
240 	if (req) {
241 		misc = (mlan_ds_misc_cfg *)req->pbuf;
242 		misc->sub_command = MLAN_OID_MISC_WARM_RESET;
243 		req->req_id = MLAN_IOCTL_MISC_CFG;
244 		req->action = MLAN_ACT_SET;
245 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
246 		if (status != MLAN_STATUS_SUCCESS) {
247 			ret = -EFAULT;
248 			if (status != MLAN_STATUS_PENDING)
249 				kfree(req);
250 			goto done;
251 		}
252 		kfree(req);
253 	}
254 
255 	/* Enable interfaces */
256 	for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
257 		netif_device_attach(handle->priv[intf_num]->netdev);
258 		woal_start_queue(handle->priv[intf_num]->netdev);
259 	}
260 
261 done:
262 	LEAVE();
263 	return ret;
264 }
265 
266 /**
267  *  @brief Get signal
268  *
269  *  @param priv         A pointer to moal_private structure
270  *  @param wrq          A pointer to iwreq structure
271  *
272  *  @return             0 --success, otherwise fail
273  */
274 static int
woal_get_signal(moal_private * priv,struct iwreq * wrq)275 woal_get_signal(moal_private *priv, struct iwreq *wrq)
276 {
277 /** Input data size */
278 #define IN_DATA_SIZE	2
279 /** Output data size */
280 #define OUT_DATA_SIZE	12
281 	int ret = 0;
282 	int in_data[IN_DATA_SIZE];
283 	int out_data[OUT_DATA_SIZE];
284 	mlan_ds_get_signal signal;
285 	int data_length = 0;
286 	int buflen = 0;
287 
288 	ENTER();
289 
290 	memset(in_data, 0, sizeof(in_data));
291 	memset(out_data, 0, sizeof(out_data));
292 	buflen = MIN(wrq->u.data.length, IN_DATA_SIZE);
293 
294 	if (priv->media_connected == MFALSE) {
295 		PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
296 		ret = -ENOTSUPP;
297 		goto done;
298 	}
299 
300 	if (wrq->u.data.length) {
301 		if (sizeof(int) * wrq->u.data.length > sizeof(in_data)) {
302 			PRINTM(MERROR, "Too many arguments\n");
303 			ret = -EINVAL;
304 			goto done;
305 		}
306 		if (copy_from_user
307 		    (in_data, wrq->u.data.pointer, sizeof(int) * buflen)) {
308 			PRINTM(MERROR, "Copy from user failed\n");
309 			ret = -EFAULT;
310 			goto done;
311 		}
312 	}
313 
314 	switch (wrq->u.data.length) {
315 	case 0:		/* No checking, get everything */
316 		break;
317 	case 2:		/* Check subtype range */
318 		if (in_data[1] < 1 || in_data[1] > 4) {
319 			ret = -EINVAL;
320 			goto done;
321 		}
322 		/* Fall through */
323 	case 1:		/* Check type range */
324 		if (in_data[0] < 1 || in_data[0] > 3) {
325 			ret = -EINVAL;
326 			goto done;
327 		}
328 		break;
329 	default:
330 		ret = -EINVAL;
331 		goto done;
332 	}
333 
334 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
335 	if (MLAN_STATUS_SUCCESS !=
336 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
337 		ret = -EFAULT;
338 		goto done;
339 	}
340 	PRINTM(MINFO, "RSSI Beacon Last   : %d\n", (int)signal.bcn_rssi_last);
341 	PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int)signal.bcn_rssi_avg);
342 	PRINTM(MINFO, "RSSI Data Last     : %d\n", (int)signal.data_rssi_last);
343 	PRINTM(MINFO, "RSSI Data Average  : %d\n", (int)signal.data_rssi_avg);
344 	PRINTM(MINFO, "SNR Beacon Last    : %d\n", (int)signal.bcn_snr_last);
345 	PRINTM(MINFO, "SNR Beacon Average : %d\n", (int)signal.bcn_snr_avg);
346 	PRINTM(MINFO, "SNR Data Last      : %d\n", (int)signal.data_snr_last);
347 	PRINTM(MINFO, "SNR Data Average   : %d\n", (int)signal.data_snr_avg);
348 	PRINTM(MINFO, "NF Beacon Last     : %d\n", (int)signal.bcn_nf_last);
349 	PRINTM(MINFO, "NF Beacon Average  : %d\n", (int)signal.bcn_nf_avg);
350 	PRINTM(MINFO, "NF Data Last       : %d\n", (int)signal.data_nf_last);
351 	PRINTM(MINFO, "NF Data Average    : %d\n", (int)signal.data_nf_avg);
352 
353 	/* Check type */
354 	switch (in_data[0]) {
355 	case 0:		/* Send everything */
356 		out_data[data_length++] = signal.bcn_rssi_last;
357 		out_data[data_length++] = signal.bcn_rssi_avg;
358 		out_data[data_length++] = signal.data_rssi_last;
359 		out_data[data_length++] = signal.data_rssi_avg;
360 		out_data[data_length++] = signal.bcn_snr_last;
361 		out_data[data_length++] = signal.bcn_snr_avg;
362 		out_data[data_length++] = signal.data_snr_last;
363 		out_data[data_length++] = signal.data_snr_avg;
364 		out_data[data_length++] = signal.bcn_nf_last;
365 		out_data[data_length++] = signal.bcn_nf_avg;
366 		out_data[data_length++] = signal.data_nf_last;
367 		out_data[data_length++] = signal.data_nf_avg;
368 		break;
369 	case 1:		/* RSSI */
370 		/* Check subtype */
371 		switch (in_data[1]) {
372 		case 0:	/* Everything */
373 			out_data[data_length++] = signal.bcn_rssi_last;
374 			out_data[data_length++] = signal.bcn_rssi_avg;
375 			out_data[data_length++] = signal.data_rssi_last;
376 			out_data[data_length++] = signal.data_rssi_avg;
377 			break;
378 		case 1:	/* bcn last */
379 			out_data[data_length++] = signal.bcn_rssi_last;
380 			break;
381 		case 2:	/* bcn avg */
382 			out_data[data_length++] = signal.bcn_rssi_avg;
383 			break;
384 		case 3:	/* data last */
385 			out_data[data_length++] = signal.data_rssi_last;
386 			break;
387 		case 4:	/* data avg */
388 			out_data[data_length++] = signal.data_rssi_avg;
389 			break;
390 		default:
391 			break;
392 		}
393 		break;
394 	case 2:		/* SNR */
395 		/* Check subtype */
396 		switch (in_data[1]) {
397 		case 0:	/* Everything */
398 			out_data[data_length++] = signal.bcn_snr_last;
399 			out_data[data_length++] = signal.bcn_snr_avg;
400 			out_data[data_length++] = signal.data_snr_last;
401 			out_data[data_length++] = signal.data_snr_avg;
402 			break;
403 		case 1:	/* bcn last */
404 			out_data[data_length++] = signal.bcn_snr_last;
405 			break;
406 		case 2:	/* bcn avg */
407 			out_data[data_length++] = signal.bcn_snr_avg;
408 			break;
409 		case 3:	/* data last */
410 			out_data[data_length++] = signal.data_snr_last;
411 			break;
412 		case 4:	/* data avg */
413 			out_data[data_length++] = signal.data_snr_avg;
414 			break;
415 		default:
416 			break;
417 		}
418 		break;
419 	case 3:		/* NF */
420 		/* Check subtype */
421 		switch (in_data[1]) {
422 		case 0:	/* Everything */
423 			out_data[data_length++] = signal.bcn_nf_last;
424 			out_data[data_length++] = signal.bcn_nf_avg;
425 			out_data[data_length++] = signal.data_nf_last;
426 			out_data[data_length++] = signal.data_nf_avg;
427 			break;
428 		case 1:	/* bcn last */
429 			out_data[data_length++] = signal.bcn_nf_last;
430 			break;
431 		case 2:	/* bcn avg */
432 			out_data[data_length++] = signal.bcn_nf_avg;
433 			break;
434 		case 3:	/* data last */
435 			out_data[data_length++] = signal.data_nf_last;
436 			break;
437 		case 4:	/* data avg */
438 			out_data[data_length++] = signal.data_nf_avg;
439 			break;
440 		default:
441 			break;
442 		}
443 		break;
444 	default:
445 		break;
446 	}
447 
448 	wrq->u.data.length = data_length;
449 	if (copy_to_user(wrq->u.data.pointer, out_data,
450 			 wrq->u.data.length * sizeof(out_data[0]))) {
451 		PRINTM(MERROR, "Copy to user failed\n");
452 		ret = -EFAULT;
453 		goto done;
454 	}
455 done:
456 	LEAVE();
457 	return ret;
458 }
459 
460 /**
461  *  @brief Get/Set DeepSleep mode
462  *
463  *  @param priv     Pointer to the moal_private driver data struct
464  *  @param wreq	    A pointer to iwreq structure
465  *
466  *  @return          0 --success, otherwise fail
467  */
468 static int
woal_deep_sleep_ioctl(moal_private * priv,struct iwreq * wrq)469 woal_deep_sleep_ioctl(moal_private *priv, struct iwreq *wrq)
470 {
471 	int ret = 0;
472 	int user_data_len;
473 	t_u32 deep_sleep = DEEP_SLEEP_OFF;
474 	t_u32 data[2];
475 	int copy_len;
476 	t_u16 idletime = DEEP_SLEEP_IDLE_TIME;
477 
478 	ENTER();
479 
480 	user_data_len = wrq->u.data.length;
481 	copy_len = MIN(sizeof(data), sizeof(int) * user_data_len);
482 	if (user_data_len == 1 || user_data_len == 2) {
483 		if (copy_from_user(&data, wrq->u.data.pointer, copy_len)) {
484 			PRINTM(MERROR, "Copy from user failed\n");
485 			LEAVE();
486 			return -EFAULT;
487 		}
488 		deep_sleep = data[0];
489 		if (deep_sleep == DEEP_SLEEP_OFF) {
490 			PRINTM(MINFO, "Exit Deep Sleep Mode\n");
491 			ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE,
492 						  0);
493 			if (ret != MLAN_STATUS_SUCCESS) {
494 				LEAVE();
495 				return -EINVAL;
496 			}
497 		} else if (deep_sleep == DEEP_SLEEP_ON) {
498 			PRINTM(MINFO, "Enter Deep Sleep Mode\n");
499 			if (user_data_len == 2)
500 				idletime = data[1];
501 			else
502 				idletime = 0;
503 			ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE,
504 						  idletime);
505 			if (ret != MLAN_STATUS_SUCCESS) {
506 				LEAVE();
507 				return -EINVAL;
508 			}
509 		} else {
510 			PRINTM(MERROR, "Unknown option = %u\n", deep_sleep);
511 			LEAVE();
512 			return -EINVAL;
513 		}
514 	} else if (user_data_len > 2) {
515 		PRINTM(MERROR, "Invalid number of arguments %d\n",
516 		       user_data_len);
517 		LEAVE();
518 		return -EINVAL;
519 	} else {		/* Display Deep Sleep settings */
520 		PRINTM(MINFO, "Get Deep Sleep Mode\n");
521 		if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
522 			LEAVE();
523 			return -EFAULT;
524 		}
525 		if (data[0] == 0)
526 			wrq->u.data.length = 1;
527 		else
528 			wrq->u.data.length = 2;
529 	}
530 
531 	/* Copy the Deep Sleep setting to user */
532 	if (copy_to_user
533 	    (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) {
534 		PRINTM(MERROR, "Copy to user failed\n");
535 		LEAVE();
536 		return -EINVAL;
537 	}
538 
539 	LEAVE();
540 	return 0;
541 }
542 
543 /**
544  *  @brief Set/Get Usr 11n configuration request
545  *
546  *  @param priv     Pointer to the moal_private driver data struct
547  *  @param wrq      A pointer to iwreq structure
548  *
549  *  @return         0 --success, otherwise fail
550  */
551 static int
woal_11n_htcap_cfg(moal_private * priv,struct iwreq * wrq)552 woal_11n_htcap_cfg(moal_private *priv, struct iwreq *wrq)
553 {
554 	int data[2], copy_len;
555 	mlan_ioctl_req *req = NULL;
556 	mlan_ds_11n_cfg *cfg_11n = NULL;
557 	int ret = 0;
558 	int data_length = wrq->u.data.length;
559 	mlan_status status = MLAN_STATUS_SUCCESS;
560 
561 	ENTER();
562 
563 	if (data_length > 2) {
564 		PRINTM(MERROR, "Invalid number of arguments\n");
565 		ret = -EINVAL;
566 		goto done;
567 	}
568 
569 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
570 	if (req == NULL) {
571 		ret = -ENOMEM;
572 		goto done;
573 	}
574 
575 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
576 	cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
577 	req->req_id = MLAN_IOCTL_11N_CFG;
578 
579 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
580 	if (data_length == 0) {
581 		/* Get 11n tx parameters from MLAN */
582 		req->action = MLAN_ACT_GET;
583 		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
584 	} else {
585 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
586 			PRINTM(MERROR, "Copy from user failed\n");
587 			ret = -EFAULT;
588 			goto done;
589 		}
590 
591 		cfg_11n->param.htcap_cfg.htcap = data[0];
592 		PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
593 		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
594 		if (data_length == 2) {
595 			if (data[1] != BAND_SELECT_BG &&
596 			    data[1] != BAND_SELECT_A &&
597 			    data[1] != BAND_SELECT_BOTH) {
598 				PRINTM(MERROR, "Invalid band selection\n");
599 				ret = -EINVAL;
600 				goto done;
601 			}
602 			cfg_11n->param.htcap_cfg.misc_cfg = data[1];
603 			PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
604 		}
605 		/* Update 11n tx parameters in MLAN */
606 		req->action = MLAN_ACT_SET;
607 	}
608 
609 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
610 	if (status != MLAN_STATUS_SUCCESS) {
611 		ret = -EFAULT;
612 		goto done;
613 	}
614 	data[0] = cfg_11n->param.htcap_cfg.htcap;
615 
616 	if (req->action == MLAN_ACT_GET) {
617 		data_length = 1;
618 		cfg_11n->param.htcap_cfg.htcap = 0;
619 		cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
620 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
621 		if (status != MLAN_STATUS_SUCCESS) {
622 			ret = -EFAULT;
623 			goto done;
624 		}
625 		if (cfg_11n->param.htcap_cfg.htcap != data[0]) {
626 			data_length = 2;
627 			data[1] = cfg_11n->param.htcap_cfg.htcap;
628 			PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n",
629 			       data[0]);
630 			PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n",
631 			       data[1]);
632 		} else
633 			PRINTM(MINFO, "GET: htcapinfo:0x%x\n", data[0]);
634 	}
635 
636 	if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
637 		PRINTM(MERROR, "Copy to user failed\n");
638 		ret = -EFAULT;
639 		goto done;
640 	}
641 
642 	wrq->u.data.length = data_length;
643 
644 done:
645 	if (status != MLAN_STATUS_PENDING)
646 		kfree(req);
647 	LEAVE();
648 	return ret;
649 }
650 
651 /**
652  *  @brief Enable/Disable amsdu_aggr_ctrl
653  *
654  *  @param priv     Pointer to the moal_private driver data struct
655  *  @param wrq      A pointer to iwreq structure
656  *
657  *  @return         0 --success, otherwise fail
658  */
659 static int
woal_11n_amsdu_aggr_ctrl(moal_private * priv,struct iwreq * wrq)660 woal_11n_amsdu_aggr_ctrl(moal_private *priv, struct iwreq *wrq)
661 {
662 	int data[2], copy_len;
663 	mlan_ioctl_req *req = NULL;
664 	mlan_ds_11n_cfg *cfg_11n = NULL;
665 	int ret = 0;
666 	int data_length = wrq->u.data.length;
667 	mlan_status status = MLAN_STATUS_SUCCESS;
668 
669 	ENTER();
670 
671 	if ((data_length != 0) && (data_length != 1)) {
672 		PRINTM(MERROR, "Invalid number of arguments\n");
673 		ret = -EINVAL;
674 		goto done;
675 	}
676 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
677 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
678 	if (req == NULL) {
679 		ret = -ENOMEM;
680 		goto done;
681 	}
682 
683 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
684 	cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
685 	req->req_id = MLAN_IOCTL_11N_CFG;
686 
687 	if (data_length == 0) {
688 		/* Get 11n tx parameters from MLAN */
689 		req->action = MLAN_ACT_GET;
690 	} else if (data_length == 1) {
691 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
692 			PRINTM(MERROR, "Copy from user failed\n");
693 			ret = -EFAULT;
694 			goto done;
695 		}
696 		cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
697 		/* Update 11n tx parameters in MLAN */
698 		req->action = MLAN_ACT_SET;
699 	}
700 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
701 	if (status != MLAN_STATUS_SUCCESS) {
702 		ret = -EFAULT;
703 		goto done;
704 	}
705 	data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
706 	data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
707 
708 	if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
709 		PRINTM(MERROR, "Copy to user failed\n");
710 		ret = -EFAULT;
711 		goto done;
712 	}
713 	wrq->u.data.length = 2;
714 done:
715 	if (status != MLAN_STATUS_PENDING)
716 		kfree(req);
717 	LEAVE();
718 	return ret;
719 }
720 
721 /**
722  *  @brief Set/Get 11n configuration request
723  *
724  *  @param priv     Pointer to the moal_private driver data struct
725  *  @param wrq      A pointer to iwreq structure
726  *
727  *  @return         0 --success, otherwise fail
728  */
729 static int
woal_11n_tx_cfg(moal_private * priv,struct iwreq * wrq)730 woal_11n_tx_cfg(moal_private *priv, struct iwreq *wrq)
731 {
732 	int data[2], copy_len;
733 	mlan_ioctl_req *req = NULL;
734 	mlan_ds_11n_cfg *cfg_11n = NULL;
735 	int ret = 0;
736 	int data_length = wrq->u.data.length;
737 	mlan_status status = MLAN_STATUS_SUCCESS;
738 
739 	ENTER();
740 
741 	if (data_length > 2) {
742 		PRINTM(MERROR, "Invalid number of arguments\n");
743 		ret = -EINVAL;
744 		goto done;
745 	}
746 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
747 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
748 	if (req == NULL) {
749 		ret = -ENOMEM;
750 		goto done;
751 	}
752 
753 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
754 	cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
755 	req->req_id = MLAN_IOCTL_11N_CFG;
756 
757 	if (data_length == 0) {
758 		/* Get 11n tx parameters from MLAN */
759 		req->action = MLAN_ACT_GET;
760 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
761 	} else {
762 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
763 			PRINTM(MERROR, "Copy from user failed\n");
764 			ret = -EFAULT;
765 			goto done;
766 		}
767 
768 		cfg_11n->param.tx_cfg.httxcap = data[0];
769 		PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
770 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
771 		if (data_length == 2) {
772 			if (data[1] != BAND_SELECT_BG &&
773 			    data[1] != BAND_SELECT_A &&
774 			    data[1] != BAND_SELECT_BOTH) {
775 				PRINTM(MERROR, "Invalid band selection\n");
776 				ret = -EINVAL;
777 				goto done;
778 			}
779 			cfg_11n->param.tx_cfg.misc_cfg = data[1];
780 			PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
781 		}
782 		/* Update 11n tx parameters in MLAN */
783 		req->action = MLAN_ACT_SET;
784 	}
785 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
786 	if (status != MLAN_STATUS_SUCCESS) {
787 		ret = -EFAULT;
788 		goto done;
789 	}
790 	data[0] = cfg_11n->param.tx_cfg.httxcap;
791 
792 	if (req->action == MLAN_ACT_GET) {
793 		data_length = 1;
794 		cfg_11n->param.tx_cfg.httxcap = 0;
795 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
796 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
797 		if (status != MLAN_STATUS_SUCCESS) {
798 			ret = -EFAULT;
799 			goto done;
800 		}
801 		if (cfg_11n->param.tx_cfg.httxcap != data[0]) {
802 			data_length = 2;
803 			data[1] = cfg_11n->param.tx_cfg.httxcap;
804 			PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n",
805 			       data[0]);
806 			PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
807 		} else
808 			PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
809 	}
810 
811 	if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
812 		PRINTM(MERROR, "Copy to user failed\n");
813 		ret = -EFAULT;
814 		goto done;
815 	}
816 	wrq->u.data.length = data_length;
817 
818 done:
819 	if (status != MLAN_STATUS_PENDING)
820 		kfree(req);
821 	LEAVE();
822 	return ret;
823 }
824 
825 /**
826  *  @brief Enable/Disable TX Aggregation
827  *
828  *  @param priv     Pointer to the moal_private driver data struct
829  *  @param wrq      A pointer to iwreq structure
830  *
831  *  @return         0 --success, otherwise fail
832  */
833 static int
woal_11n_prio_tbl(moal_private * priv,struct iwreq * wrq)834 woal_11n_prio_tbl(moal_private *priv, struct iwreq *wrq)
835 {
836 	int data[MAX_NUM_TID * 2], i, j, copy_len;
837 	mlan_ioctl_req *req = NULL;
838 	mlan_ds_11n_cfg *cfg_11n = NULL;
839 	int ret = 0;
840 	int data_length = wrq->u.data.length;
841 	mlan_status status = MLAN_STATUS_SUCCESS;
842 
843 	ENTER();
844 
845 	if ((wrq->u.data.pointer == NULL)) {
846 		LEAVE();
847 		return -EINVAL;
848 	}
849 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
850 
851 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
852 	if (req == NULL) {
853 		LEAVE();
854 		return -ENOMEM;
855 	}
856 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
857 	cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
858 	req->req_id = MLAN_IOCTL_11N_CFG;
859 
860 	if (data_length == 0) {
861 		/* Get aggr priority table from MLAN */
862 		req->action = MLAN_ACT_GET;
863 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
864 		if (status != MLAN_STATUS_SUCCESS) {
865 			ret = -EFAULT;
866 			goto error;
867 		}
868 		wrq->u.data.length = MAX_NUM_TID * 2;
869 		for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
870 			data[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
871 			data[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
872 		}
873 
874 		if (copy_to_user(wrq->u.data.pointer, data,
875 				 sizeof(int) * wrq->u.data.length)) {
876 			PRINTM(MERROR, "Copy to user failed\n");
877 			ret = -EFAULT;
878 			goto error;
879 		}
880 	} else if (data_length == 16) {
881 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
882 			PRINTM(MERROR, "Copy from user failed\n");
883 			ret = -EFAULT;
884 			goto error;
885 		}
886 		for (i = 0, j = 0; i < (data_length); i = i + 2, ++j) {
887 			if ((data[i] > 7 && data[i] != 0xff) ||
888 			    (data[i + 1] > 7 && data[i + 1] != 0xff)) {
889 				PRINTM(MERROR,
890 				       "Invalid priority, valid value 0-7 or 0xff.\n");
891 				ret = -EFAULT;
892 				goto error;
893 			}
894 			cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
895 			cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
896 		}
897 
898 		/* Update aggr priority table in MLAN */
899 		req->action = MLAN_ACT_SET;
900 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
901 		if (status != MLAN_STATUS_SUCCESS) {
902 			ret = -EFAULT;
903 			goto error;
904 		}
905 	} else {
906 		PRINTM(MERROR, "Invalid number of arguments\n");
907 		ret = -EINVAL;
908 		goto error;
909 	}
910 
911 error:
912 	if (status != MLAN_STATUS_PENDING)
913 		kfree(req);
914 	LEAVE();
915 	return ret;
916 }
917 
918 /**
919  *  @brief Set/Get add BA Reject parameters
920  *
921  *  @param priv     Pointer to the moal_private driver data struct
922  *  @param wrq      A pointer to iwreq structure
923  *
924  *  @return         0 --success, otherwise fail
925  */
926 static int
woal_addba_reject(moal_private * priv,struct iwreq * wrq)927 woal_addba_reject(moal_private *priv, struct iwreq *wrq)
928 {
929 	int data[MAX_NUM_TID], ret = 0, i, copy_len;
930 	mlan_ioctl_req *req = NULL;
931 	mlan_ds_11n_cfg *cfg_11n = NULL;
932 	int data_length = wrq->u.data.length;
933 	mlan_status status = MLAN_STATUS_SUCCESS;
934 	ENTER();
935 
936 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
937 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
938 	if (req == NULL) {
939 		LEAVE();
940 		return -ENOMEM;
941 	}
942 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
943 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
944 	req->req_id = MLAN_IOCTL_11N_CFG;
945 
946 	if (data_length == 0) {
947 		PRINTM(MERROR, "Addba reject moal\n");
948 		/* Get aggr priority table from MLAN */
949 		req->action = MLAN_ACT_GET;
950 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
951 		if (status != MLAN_STATUS_SUCCESS) {
952 			ret = -EFAULT;
953 			goto error;
954 		}
955 
956 		wrq->u.data.length = MAX_NUM_TID;
957 		for (i = 0; i < (wrq->u.data.length); ++i)
958 			data[i] = cfg_11n->param.addba_reject[i];
959 
960 		if (copy_to_user(wrq->u.data.pointer, data,
961 				 sizeof(int) * wrq->u.data.length)) {
962 			PRINTM(MERROR, "Copy to user failed\n");
963 			ret = -EFAULT;
964 			goto error;
965 		}
966 	} else if (data_length == 8) {
967 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
968 			PRINTM(MERROR, "Copy from user failed\n");
969 			ret = -EFAULT;
970 			goto error;
971 		}
972 		for (i = 0; i < (data_length); ++i) {
973 			if (data[i] != 0 && data[i] != 1) {
974 				PRINTM(MERROR,
975 				       "addba reject only takes argument as 0 or 1\n");
976 				ret = -EFAULT;
977 				goto error;
978 			}
979 			cfg_11n->param.addba_reject[i] = data[i];
980 		}
981 
982 		/* Update aggr priority table in MLAN */
983 		req->action = MLAN_ACT_SET;
984 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
985 		if (status != MLAN_STATUS_SUCCESS) {
986 			ret = -EFAULT;
987 			goto error;
988 		}
989 	} else {
990 		PRINTM(MERROR, "Invalid number of arguments\n");
991 		ret = -EINVAL;
992 		goto error;
993 	}
994 error:
995 	if (status != MLAN_STATUS_PENDING)
996 		kfree(req);
997 	LEAVE();
998 	return ret;
999 }
1000 
1001 /**
1002  *  @brief Set/Get add BA parameters
1003  *
1004  *  @param priv     Pointer to the moal_private driver data struct
1005  *  @param wrq      A pointer to iwreq structure
1006  *
1007  *  @return         0 --success, otherwise fail
1008  */
1009 static int
woal_addba_para_updt(moal_private * priv,struct iwreq * wrq)1010 woal_addba_para_updt(moal_private *priv, struct iwreq *wrq)
1011 {
1012 	int data[5], ret = 0, copy_len;
1013 	mlan_ioctl_req *req = NULL;
1014 	mlan_ds_11n_cfg *cfg_11n = NULL;
1015 	int data_length = wrq->u.data.length;
1016 	mlan_status status = MLAN_STATUS_SUCCESS;
1017 
1018 	ENTER();
1019 
1020 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
1021 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1022 	if (req == NULL) {
1023 		LEAVE();
1024 		return -ENOMEM;
1025 	}
1026 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1027 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
1028 	req->req_id = MLAN_IOCTL_11N_CFG;
1029 
1030 	if (data_length == 0) {
1031 		/* Get Add BA parameters from MLAN */
1032 		req->action = MLAN_ACT_GET;
1033 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1034 		if (status != MLAN_STATUS_SUCCESS) {
1035 			ret = -EFAULT;
1036 			goto error;
1037 		}
1038 		data[0] = cfg_11n->param.addba_param.timeout;
1039 		data[1] = cfg_11n->param.addba_param.txwinsize;
1040 		data[2] = cfg_11n->param.addba_param.rxwinsize;
1041 		data[3] = cfg_11n->param.addba_param.txamsdu;
1042 		data[4] = cfg_11n->param.addba_param.rxamsdu;
1043 		PRINTM(MINFO,
1044 		       "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
1045 		       data[0], data[1], data[2], data[3], data[4]);
1046 		wrq->u.data.length = 5;
1047 		if (copy_to_user(wrq->u.data.pointer, data,
1048 				 wrq->u.data.length * sizeof(int))) {
1049 			PRINTM(MERROR, "Copy to user failed\n");
1050 			ret = -EFAULT;
1051 			goto error;
1052 		}
1053 	} else if (data_length == 5) {
1054 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1055 			PRINTM(MERROR, "Copy from user failed\n");
1056 			ret = -EFAULT;
1057 			goto error;
1058 		}
1059 		if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
1060 			PRINTM(MERROR, "Incorrect addba timeout value.\n");
1061 			ret = -EFAULT;
1062 			goto error;
1063 		}
1064 		if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE ||
1065 		    data[2] <= 0 || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
1066 			PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
1067 			ret = -EFAULT;
1068 			goto error;
1069 		}
1070 		cfg_11n->param.addba_param.timeout = data[0];
1071 		cfg_11n->param.addba_param.txwinsize = data[1];
1072 		cfg_11n->param.addba_param.rxwinsize = data[2];
1073 		if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
1074 			PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
1075 			ret = -EFAULT;
1076 			goto error;
1077 		}
1078 		cfg_11n->param.addba_param.txamsdu = data[3];
1079 		cfg_11n->param.addba_param.rxamsdu = data[4];
1080 		PRINTM(MINFO,
1081 		       "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
1082 		       data[0], data[1], data[2], data[3], data[4]);
1083 		/* Update Add BA parameters in MLAN */
1084 		req->action = MLAN_ACT_SET;
1085 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1086 		if (status != MLAN_STATUS_SUCCESS) {
1087 			ret = MLAN_STATUS_FAILURE;
1088 			goto error;
1089 		}
1090 	} else {
1091 		PRINTM(MERROR, "Invalid number of arguments\n");
1092 		ret = -EINVAL;
1093 		goto error;
1094 	}
1095 
1096 error:
1097 	if (status != MLAN_STATUS_PENDING)
1098 		kfree(req);
1099 	LEAVE();
1100 	return ret;
1101 }
1102 
1103 /**
1104  *  @brief Set/Get Transmit buffer size
1105  *
1106  *  @param priv     Pointer to the moal_private driver data struct
1107  *  @param wrq      A pointer to iwreq structure
1108  *
1109  *  @return         0 --success, otherwise fail
1110  */
1111 static int
woal_txbuf_cfg(moal_private * priv,struct iwreq * wrq)1112 woal_txbuf_cfg(moal_private *priv, struct iwreq *wrq)
1113 {
1114 	int buf_size;
1115 	mlan_ioctl_req *req = NULL;
1116 	mlan_ds_11n_cfg *cfg_11n = NULL;
1117 	int ret = 0;
1118 	mlan_status status = MLAN_STATUS_SUCCESS;
1119 
1120 	ENTER();
1121 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1122 	if (req == NULL) {
1123 		ret = -ENOMEM;
1124 		goto done;
1125 	}
1126 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1127 	cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
1128 	req->req_id = MLAN_IOCTL_11N_CFG;
1129 
1130 	if (wrq->u.data.length == 0) {
1131 		/* Get Tx buffer size from MLAN */
1132 		req->action = MLAN_ACT_GET;
1133 	} else {
1134 		ret = -EINVAL;
1135 		PRINTM(MERROR,
1136 		       "Don't support set Tx buffer size after driver loaded!\n");
1137 		goto done;
1138 	}
1139 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1140 	if (status != MLAN_STATUS_SUCCESS) {
1141 		ret = -EFAULT;
1142 		goto done;
1143 	}
1144 	buf_size = cfg_11n->param.tx_buf_size;
1145 	if (copy_to_user(wrq->u.data.pointer, &buf_size, sizeof(buf_size))) {
1146 		PRINTM(MERROR, "Copy to user failed\n");
1147 		ret = -EFAULT;
1148 		goto done;
1149 	}
1150 	wrq->u.data.length = 1;
1151 done:
1152 	if (status != MLAN_STATUS_PENDING)
1153 		kfree(req);
1154 	LEAVE();
1155 	return ret;
1156 }
1157 
1158 /**
1159  *  @brief Set/Get Host Sleep configuration
1160  *
1161  *  @param priv             A pointer to moal_private structure
1162  *  @param wrq              A pointer to iwreq structure
1163  *  @param invoke_hostcmd   MTRUE --invoke HostCmd, otherwise MFALSE
1164  *
1165  *  @return                 0 --success, otherwise fail
1166  */
1167 static int
woal_hs_cfg(moal_private * priv,struct iwreq * wrq,BOOLEAN invoke_hostcmd)1168 woal_hs_cfg(moal_private *priv, struct iwreq *wrq, BOOLEAN invoke_hostcmd)
1169 {
1170 	int data[3], copy_len;
1171 	int ret = 0;
1172 	mlan_ds_hs_cfg hscfg;
1173 	t_u16 action;
1174 	mlan_bss_info bss_info;
1175 	int data_length = wrq->u.data.length;
1176 
1177 	ENTER();
1178 
1179 	memset(data, 0, sizeof(data));
1180 	memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
1181 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
1182 
1183 	if (data_length == 0) {
1184 		action = MLAN_ACT_GET;
1185 	} else {
1186 		action = MLAN_ACT_SET;
1187 		if (data_length >= 1 && data_length <= 3) {
1188 			if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1189 				PRINTM(MERROR, "Copy from user failed\n");
1190 				ret = -EFAULT;
1191 				goto done;
1192 			}
1193 		} else {
1194 			PRINTM(MERROR, "Invalid arguments\n");
1195 			ret = -EINVAL;
1196 			goto done;
1197 		}
1198 	}
1199 
1200 	/* HS config is blocked if HS is already activated */
1201 	if (data_length &&
1202 	    (data[0] != HOST_SLEEP_CFG_CANCEL || invoke_hostcmd == MFALSE)) {
1203 		memset(&bss_info, 0, sizeof(bss_info));
1204 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1205 		if (bss_info.is_hs_configured) {
1206 			PRINTM(MERROR, "HS already configured\n");
1207 			ret = -EFAULT;
1208 			goto done;
1209 		}
1210 	}
1211 
1212 	/* Do a GET first if some arguments are not provided */
1213 	if (data_length >= 1 && data_length < 3) {
1214 		woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
1215 				       &hscfg);
1216 	}
1217 
1218 	if (data_length)
1219 		hscfg.conditions = data[0];
1220 	if (data_length >= 2)
1221 		hscfg.gpio = data[1];
1222 	if (data_length == 3)
1223 		hscfg.gap = data[2];
1224 
1225 	if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
1226 		/* Need to issue an extra IOCTL first to set up parameters */
1227 		hscfg.is_invoke_hostcmd = MFALSE;
1228 		if (MLAN_STATUS_SUCCESS !=
1229 		    woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
1230 					   &hscfg)) {
1231 			ret = -EFAULT;
1232 			goto done;
1233 		}
1234 	}
1235 	hscfg.is_invoke_hostcmd = invoke_hostcmd;
1236 	if (MLAN_STATUS_SUCCESS !=
1237 	    woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
1238 		ret = -EFAULT;
1239 		goto done;
1240 	}
1241 
1242 	if (action == MLAN_ACT_GET) {
1243 		data[0] = hscfg.conditions;
1244 		data[1] = hscfg.gpio;
1245 		data[2] = hscfg.gap;
1246 		wrq->u.data.length = 3;
1247 		if (copy_to_user
1248 		    (wrq->u.data.pointer, data,
1249 		     sizeof(int) * wrq->u.data.length)) {
1250 			PRINTM(MERROR, "Copy to user failed\n");
1251 			ret = -EFAULT;
1252 			goto done;
1253 		}
1254 	}
1255 done:
1256 	LEAVE();
1257 	return ret;
1258 }
1259 
1260 /**
1261  *  @brief Set Host Sleep parameters
1262  *
1263  *  @param priv         A pointer to moal_private structure
1264  *  @param wrq          A pointer to iwreq structure
1265  *
1266  *  @return             0 --success, otherwise fail
1267  */
1268 static int
woal_hs_setpara(moal_private * priv,struct iwreq * wrq)1269 woal_hs_setpara(moal_private *priv, struct iwreq *wrq)
1270 {
1271 	int ret = 0;
1272 	int data_length = wrq->u.data.length;
1273 
1274 	ENTER();
1275 
1276 	if (data_length >= 1 && data_length <= 3) {
1277 		ret = woal_hs_cfg(priv, wrq, MFALSE);
1278 		goto done;
1279 	} else {
1280 		PRINTM(MERROR, "Invalid arguments\n");
1281 		ret = -EINVAL;
1282 		goto done;
1283 	}
1284 done:
1285 	LEAVE();
1286 	return ret;
1287 }
1288 
1289 /**
1290  *  @brief Get/Set inactivity timeout extend
1291  *
1292  *  @param priv         A pointer to moal_private structure
1293  *  @param wrq          A pointer to iwreq structure
1294  *
1295  *  @return             0 --success, otherwise fail
1296  */
1297 static int
woal_inactivity_timeout_ext(moal_private * priv,struct iwreq * wrq)1298 woal_inactivity_timeout_ext(moal_private *priv, struct iwreq *wrq)
1299 {
1300 	int data[4], copy_len;
1301 	int ret = 0;
1302 	mlan_ioctl_req *req = NULL;
1303 	mlan_ds_pm_cfg *pmcfg = NULL;
1304 	pmlan_ds_inactivity_to inac_to = NULL;
1305 	int data_length = wrq->u.data.length;
1306 	mlan_status status = MLAN_STATUS_SUCCESS;
1307 
1308 	ENTER();
1309 
1310 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
1311 	memset(data, 0, sizeof(data));
1312 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
1313 	if (req == NULL) {
1314 		ret = -ENOMEM;
1315 		goto done;
1316 	}
1317 
1318 	pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
1319 	inac_to = &pmcfg->param.inactivity_to;
1320 	pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
1321 	req->req_id = MLAN_IOCTL_PM_CFG;
1322 
1323 	if ((data_length != 0 && data_length != 3 && data_length != 4) ||
1324 	    sizeof(int) * data_length > sizeof(data)) {
1325 		PRINTM(MERROR, "Invalid number of parameters\n");
1326 		ret = -EINVAL;
1327 		goto done;
1328 	}
1329 
1330 	req->action = MLAN_ACT_GET;
1331 	if (data_length) {
1332 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1333 			PRINTM(MERROR, "Copy from user failed\n");
1334 			ret = -EFAULT;
1335 			goto done;
1336 		}
1337 		req->action = MLAN_ACT_SET;
1338 		inac_to->timeout_unit = data[0];
1339 		inac_to->unicast_timeout = data[1];
1340 		inac_to->mcast_timeout = data[2];
1341 		inac_to->ps_entry_timeout = data[3];
1342 	}
1343 
1344 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1345 	if (status != MLAN_STATUS_SUCCESS) {
1346 		ret = -EFAULT;
1347 		goto done;
1348 	}
1349 
1350 	/* Copy back current values regardless of GET/SET */
1351 	data[0] = inac_to->timeout_unit;
1352 	data[1] = inac_to->unicast_timeout;
1353 	data[2] = inac_to->mcast_timeout;
1354 	data[3] = inac_to->ps_entry_timeout;
1355 
1356 	if (req->action == MLAN_ACT_GET) {
1357 		wrq->u.data.length = 4;
1358 		if (copy_to_user
1359 		    (wrq->u.data.pointer, data,
1360 		     wrq->u.data.length * sizeof(int))) {
1361 			PRINTM(MERROR, "Copy to user failed\n");
1362 			ret = -EFAULT;
1363 			goto done;
1364 		}
1365 	}
1366 
1367 done:
1368 	if (status != MLAN_STATUS_PENDING)
1369 		kfree(req);
1370 	LEAVE();
1371 	return ret;
1372 }
1373 
1374 /**
1375  *  @brief Set/Get system clock
1376  *
1377  *  @param priv         A pointer to moal_private structure
1378  *  @param wrq          A pointer to iwreq structure
1379  *
1380  *  @return             0 --success, otherwise fail
1381  */
1382 static int
woal_ecl_sys_clock(moal_private * priv,struct iwreq * wrq)1383 woal_ecl_sys_clock(moal_private *priv, struct iwreq *wrq)
1384 {
1385 	int data[64], copy_len;
1386 	int ret = 0;
1387 	mlan_ioctl_req *req = NULL;
1388 	mlan_ds_misc_cfg *cfg = NULL;
1389 	int data_length = wrq->u.data.length;
1390 	int i = 0;
1391 	mlan_status status = MLAN_STATUS_SUCCESS;
1392 
1393 	ENTER();
1394 
1395 	memset(data, 0, sizeof(data));
1396 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
1397 
1398 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1399 	if (req == NULL) {
1400 		ret = -ENOMEM;
1401 		goto done;
1402 	}
1403 
1404 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
1405 	cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
1406 	req->req_id = MLAN_IOCTL_MISC_CFG;
1407 
1408 	if (!data_length)
1409 		req->action = MLAN_ACT_GET;
1410 	else if (data_length <= MLAN_MAX_CLK_NUM) {
1411 		req->action = MLAN_ACT_SET;
1412 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1413 			PRINTM(MERROR, "Copy from user failed\n");
1414 			ret = -EFAULT;
1415 			goto done;
1416 		}
1417 	} else {
1418 		PRINTM(MERROR, "Invalid arguments\n");
1419 		ret = -EINVAL;
1420 		goto done;
1421 	}
1422 
1423 	if (req->action == MLAN_ACT_GET) {
1424 		/* Get configurable clocks */
1425 		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
1426 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1427 		if (status != MLAN_STATUS_SUCCESS) {
1428 			ret = -EFAULT;
1429 			goto done;
1430 		}
1431 
1432 		/* Current system clock */
1433 		data[0] = (int)cfg->param.sys_clock.cur_sys_clk;
1434 		wrq->u.data.length = 1;
1435 
1436 		data_length =
1437 			MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
1438 
1439 		/* Configurable clocks */
1440 		for (i = 0; i < data_length; i++) {
1441 			data[i + wrq->u.data.length] =
1442 				(int)cfg->param.sys_clock.sys_clk[i];
1443 		}
1444 		wrq->u.data.length += data_length;
1445 
1446 		/* Get supported clocks */
1447 		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
1448 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1449 		if (status != MLAN_STATUS_SUCCESS) {
1450 			ret = -EFAULT;
1451 			goto done;
1452 		}
1453 
1454 		data_length =
1455 			MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
1456 
1457 		/* Supported clocks */
1458 		for (i = 0; i < data_length; i++) {
1459 			data[i + wrq->u.data.length] =
1460 				(int)cfg->param.sys_clock.sys_clk[i];
1461 		}
1462 
1463 		wrq->u.data.length += data_length;
1464 
1465 		if (copy_to_user
1466 		    (wrq->u.data.pointer, data,
1467 		     sizeof(int) * wrq->u.data.length)) {
1468 			PRINTM(MERROR, "Copy to user failed\n");
1469 			ret = -EFAULT;
1470 			goto done;
1471 		}
1472 	} else {
1473 		/* Set configurable clocks */
1474 		cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
1475 		cfg->param.sys_clock.sys_clk_num =
1476 			MIN(MLAN_MAX_CLK_NUM, data_length);
1477 		for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++)
1478 			cfg->param.sys_clock.sys_clk[i] = (t_u16)data[i];
1479 
1480 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1481 		if (status != MLAN_STATUS_SUCCESS) {
1482 			ret = -EFAULT;
1483 			goto done;
1484 		}
1485 	}
1486 done:
1487 	if (status != MLAN_STATUS_PENDING)
1488 		kfree(req);
1489 	LEAVE();
1490 	return ret;
1491 }
1492 
1493 /**
1494  *  @brief Set/Get Band and Adhoc-band setting
1495  *
1496  *  @param priv         A pointer to moal_private structure
1497  *  @param wrq          A pointer to iwreq structure
1498  *
1499  *  @return             0 --success, otherwise fail
1500  */
1501 static int
woal_band_cfg(moal_private * priv,struct iwreq * wrq)1502 woal_band_cfg(moal_private *priv, struct iwreq *wrq)
1503 {
1504 	int ret = 0;
1505 	unsigned int i;
1506 	int data[4];
1507 	int user_data_len = wrq->u.data.length, copy_len;
1508 	t_u32 infra_band = 0;
1509 	t_u32 adhoc_band = 0;
1510 	t_u32 adhoc_channel = 0;
1511 	t_u32 adhoc_chan_bandwidth = 0;
1512 	mlan_ioctl_req *req = NULL;
1513 	mlan_ds_radio_cfg *radio_cfg = NULL;
1514 	mlan_status status = MLAN_STATUS_SUCCESS;
1515 
1516 	ENTER();
1517 
1518 	if (sizeof(int) * user_data_len > sizeof(data)) {
1519 		PRINTM(MERROR, "Too many arguments\n");
1520 		LEAVE();
1521 		return -EINVAL;
1522 	}
1523 
1524 	if (user_data_len > 0) {
1525 		if (priv->media_connected == MTRUE) {
1526 			LEAVE();
1527 			return -EOPNOTSUPP;
1528 		}
1529 	}
1530 
1531 	copy_len = MIN(sizeof(data), sizeof(int) * user_data_len);
1532 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
1533 	if (req == NULL) {
1534 		ret = -ENOMEM;
1535 		goto error;
1536 	}
1537 	radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
1538 	radio_cfg->sub_command = MLAN_OID_BAND_CFG;
1539 	req->req_id = MLAN_IOCTL_RADIO_CFG;
1540 
1541 	if (wrq->u.data.length == 0) {
1542 		/* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN */
1543 		req->action = MLAN_ACT_GET;
1544 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1545 		if (status != MLAN_STATUS_SUCCESS) {
1546 			ret = -EFAULT;
1547 			goto error;
1548 		}
1549 		/* Infra Band */
1550 		data[0] = radio_cfg->param.band_cfg.config_bands;
1551 		/* Adhoc Band */
1552 		data[1] = radio_cfg->param.band_cfg.adhoc_start_band;
1553 		/* Adhoc Channel */
1554 		data[2] = radio_cfg->param.band_cfg.adhoc_channel;
1555 		wrq->u.data.length = 3;
1556 		if (radio_cfg->param.band_cfg.adhoc_start_band & BAND_GN
1557 		    || radio_cfg->param.band_cfg.adhoc_start_band & BAND_AN) {
1558 			/* secondary bandwidth */
1559 			data[3] =
1560 				radio_cfg->param.band_cfg.adhoc_chan_bandwidth;
1561 			wrq->u.data.length = 4;
1562 		}
1563 
1564 		if (copy_to_user
1565 		    (wrq->u.data.pointer, data,
1566 		     sizeof(int) * wrq->u.data.length)) {
1567 			ret = -EFAULT;
1568 			goto error;
1569 		}
1570 	} else {
1571 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1572 			PRINTM(MERROR, "Copy from user failed\n");
1573 			ret = -EFAULT;
1574 			goto error;
1575 		}
1576 
1577 		/* To support only <b/bg/bgn/n> */
1578 		infra_band = data[0];
1579 		for (i = 0; i < sizeof(SupportedInfraBand); i++)
1580 			if (infra_band == SupportedInfraBand[i])
1581 				break;
1582 		if (i == sizeof(SupportedInfraBand)) {
1583 			ret = -EINVAL;
1584 			goto error;
1585 		}
1586 
1587 		/* Set Adhoc band */
1588 		if (user_data_len >= 2) {
1589 			adhoc_band = data[1];
1590 			for (i = 0; i < sizeof(SupportedAdhocBand); i++)
1591 				if (adhoc_band == SupportedAdhocBand[i])
1592 					break;
1593 			if (i == sizeof(SupportedAdhocBand)) {
1594 				ret = -EINVAL;
1595 				goto error;
1596 			}
1597 		}
1598 
1599 		/* Set Adhoc channel */
1600 		if (user_data_len >= 3) {
1601 			adhoc_channel = data[2];
1602 			if (adhoc_channel == 0) {
1603 				/* Check if specified adhoc channel is non-zero */
1604 				ret = -EINVAL;
1605 				goto error;
1606 			}
1607 		}
1608 		if (user_data_len == 4) {
1609 			if (!(adhoc_band & (BAND_GN | BAND_AN))) {
1610 				PRINTM(MERROR,
1611 				       "11n is not enabled for adhoc, can not set HT/VHT channel bandwidth\n");
1612 				ret = -EINVAL;
1613 				goto error;
1614 			}
1615 			adhoc_chan_bandwidth = data[3];
1616 			if ((adhoc_chan_bandwidth != CHANNEL_BW_20MHZ) &&
1617 			    (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_ABOVE) &&
1618 			    (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_BELOW)
1619 				) {
1620 				PRINTM(MERROR,
1621 				       "Invalid secondary channel bandwidth, only allowed 0, 1, 3 or 4\n");
1622 				ret = -EINVAL;
1623 				goto error;
1624 			}
1625 		}
1626 		/* Set config_bands and adhoc_start_band values to MLAN */
1627 		req->action = MLAN_ACT_SET;
1628 		radio_cfg->param.band_cfg.config_bands = infra_band;
1629 		radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
1630 		radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
1631 		radio_cfg->param.band_cfg.adhoc_chan_bandwidth =
1632 			adhoc_chan_bandwidth;
1633 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1634 		if (status != MLAN_STATUS_SUCCESS) {
1635 			ret = -EFAULT;
1636 			goto error;
1637 		}
1638 	}
1639 
1640 error:
1641 	if (status != MLAN_STATUS_PENDING)
1642 		kfree(req);
1643 	LEAVE();
1644 	return ret;
1645 }
1646 
1647 /**
1648  *  @brief Read/Write adapter registers value
1649  *
1650  *  @param priv         A pointer to moal_private structure
1651  *  @param wrq          A pointer to iwreq structure
1652  *
1653  *  @return             0 --success, otherwise fail
1654  */
1655 static int
woal_reg_read_write(moal_private * priv,struct iwreq * wrq)1656 woal_reg_read_write(moal_private *priv, struct iwreq *wrq)
1657 {
1658 	int data[3], copy_len;
1659 	int ret = 0;
1660 	mlan_ioctl_req *req = NULL;
1661 	mlan_ds_reg_mem *reg = NULL;
1662 	int data_length = wrq->u.data.length;
1663 	mlan_status status = MLAN_STATUS_SUCCESS;
1664 
1665 	ENTER();
1666 
1667 	memset(data, 0, sizeof(data));
1668 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
1669 
1670 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
1671 	if (req == NULL) {
1672 		ret = -ENOMEM;
1673 		goto done;
1674 	}
1675 
1676 	reg = (mlan_ds_reg_mem *)req->pbuf;
1677 	reg->sub_command = MLAN_OID_REG_RW;
1678 	req->req_id = MLAN_IOCTL_REG_MEM;
1679 
1680 	if (data_length == 2) {
1681 		req->action = MLAN_ACT_GET;
1682 	} else if (data_length == 3) {
1683 		req->action = MLAN_ACT_SET;
1684 	} else {
1685 		ret = -EINVAL;
1686 		goto done;
1687 	}
1688 	if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1689 		PRINTM(MERROR, "Copy from user failed\n");
1690 		ret = -EFAULT;
1691 		goto done;
1692 	}
1693 	reg->param.reg_rw.type = (t_u32)data[0];
1694 	reg->param.reg_rw.offset = (t_u32)data[1];
1695 	if (data_length == 3)
1696 		reg->param.reg_rw.value = (t_u32)data[2];
1697 
1698 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1699 	if (status != MLAN_STATUS_SUCCESS) {
1700 		ret = -EFAULT;
1701 		goto done;
1702 	}
1703 
1704 	if (req->action == MLAN_ACT_GET) {
1705 		if (copy_to_user
1706 		    (wrq->u.data.pointer, &reg->param.reg_rw.value,
1707 		     sizeof(int))) {
1708 			PRINTM(MERROR, "Copy to user failed\n");
1709 			ret = -EFAULT;
1710 			goto done;
1711 		}
1712 		wrq->u.data.length = 1;
1713 	}
1714 
1715 done:
1716 	if (status != MLAN_STATUS_PENDING)
1717 		kfree(req);
1718 	LEAVE();
1719 	return ret;
1720 }
1721 
1722 /**
1723  *  @brief Read the EEPROM contents of the card
1724  *
1725  *  @param priv         A pointer to moal_private structure
1726  *  @param wrq          A pointer to iwreq structure
1727  *
1728  *  @return             0 --success, otherwise fail
1729  */
1730 static int
woal_read_eeprom(moal_private * priv,struct iwreq * wrq)1731 woal_read_eeprom(moal_private *priv, struct iwreq *wrq)
1732 {
1733 	int data[2], copy_len;
1734 	int ret = 0;
1735 	mlan_ioctl_req *req = NULL;
1736 	mlan_ds_reg_mem *reg = NULL;
1737 	int data_length = wrq->u.data.length;
1738 	mlan_status status = MLAN_STATUS_SUCCESS;
1739 
1740 	ENTER();
1741 
1742 	memset(data, 0, sizeof(data));
1743 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
1744 
1745 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
1746 	if (req == NULL) {
1747 		ret = -ENOMEM;
1748 		goto done;
1749 	}
1750 
1751 	reg = (mlan_ds_reg_mem *)req->pbuf;
1752 	reg->sub_command = MLAN_OID_EEPROM_RD;
1753 	req->req_id = MLAN_IOCTL_REG_MEM;
1754 
1755 	if (data_length == 2) {
1756 		req->action = MLAN_ACT_GET;
1757 	} else {
1758 		ret = -EINVAL;
1759 		goto done;
1760 	}
1761 	if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1762 		PRINTM(MERROR, "Copy from user failed\n");
1763 		ret = -EFAULT;
1764 		goto done;
1765 	}
1766 
1767 	reg->param.rd_eeprom.offset = (t_u16)data[0];
1768 	reg->param.rd_eeprom.byte_count = (t_u16)data[1];
1769 
1770 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1771 	if (status != MLAN_STATUS_SUCCESS) {
1772 		ret = -EFAULT;
1773 		goto done;
1774 	}
1775 
1776 	if (req->action == MLAN_ACT_GET) {
1777 		wrq->u.data.length = reg->param.rd_eeprom.byte_count;
1778 		if (copy_to_user
1779 		    (wrq->u.data.pointer, reg->param.rd_eeprom.value,
1780 		     MIN(wrq->u.data.length, MAX_EEPROM_DATA))) {
1781 			PRINTM(MERROR, "Copy to user failed\n");
1782 			ret = -EFAULT;
1783 			goto done;
1784 		}
1785 	}
1786 
1787 done:
1788 	if (status != MLAN_STATUS_PENDING)
1789 		kfree(req);
1790 	LEAVE();
1791 	return ret;
1792 }
1793 
1794 /**
1795  *  @brief Read/Write device memory value
1796  *
1797  *  @param priv         A pointer to moal_private structure
1798  *  @param wrq          A pointer to iwreq structure
1799  *
1800  *  @return             0 --success, otherwise fail
1801  */
1802 static int
woal_mem_read_write(moal_private * priv,struct iwreq * wrq)1803 woal_mem_read_write(moal_private *priv, struct iwreq *wrq)
1804 {
1805 	t_u32 data[2];
1806 	int ret = 0;
1807 	mlan_ioctl_req *req = NULL;
1808 	mlan_ds_reg_mem *reg_mem = NULL;
1809 	int data_length = wrq->u.data.length, copy_len;
1810 	mlan_status status = MLAN_STATUS_SUCCESS;
1811 
1812 	ENTER();
1813 
1814 	memset(data, 0, sizeof(data));
1815 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
1816 
1817 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
1818 	if (req == NULL) {
1819 		ret = -ENOMEM;
1820 		goto done;
1821 	}
1822 
1823 	reg_mem = (mlan_ds_reg_mem *)req->pbuf;
1824 	reg_mem->sub_command = MLAN_OID_MEM_RW;
1825 	req->req_id = MLAN_IOCTL_REG_MEM;
1826 
1827 	if (data_length == 1) {
1828 		PRINTM(MINFO, "MEM_RW: GET\n");
1829 		req->action = MLAN_ACT_GET;
1830 	} else if (data_length == 2) {
1831 		PRINTM(MINFO, "MEM_RW: SET\n");
1832 		req->action = MLAN_ACT_SET;
1833 	} else {
1834 		ret = -EINVAL;
1835 		goto done;
1836 	}
1837 	if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1838 		PRINTM(MERROR, "Copy from user failed\n");
1839 		ret = -EFAULT;
1840 		goto done;
1841 	}
1842 
1843 	reg_mem->param.mem_rw.addr = (t_u32)data[0];
1844 	if (data_length == 2)
1845 		reg_mem->param.mem_rw.value = (t_u32)data[1];
1846 
1847 	PRINTM(MINFO, "MEM_RW: Addr=0x%x, Value=0x%x\n",
1848 	       (int)reg_mem->param.mem_rw.addr,
1849 	       (int)reg_mem->param.mem_rw.value);
1850 
1851 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1852 	if (status != MLAN_STATUS_SUCCESS) {
1853 		ret = -EFAULT;
1854 		goto done;
1855 	}
1856 
1857 	if (req->action == MLAN_ACT_GET) {
1858 		if (copy_to_user
1859 		    (wrq->u.data.pointer, &reg_mem->param.mem_rw.value,
1860 		     sizeof(int))) {
1861 			PRINTM(MERROR, "Copy to user failed\n");
1862 			ret = -EFAULT;
1863 			goto done;
1864 		}
1865 		wrq->u.data.length = 1;
1866 	}
1867 
1868 done:
1869 	if (status != MLAN_STATUS_PENDING)
1870 		kfree(req);
1871 	LEAVE();
1872 	return ret;
1873 }
1874 
1875 /**
1876  *  @brief Set/Get network monitor configurations
1877  *
1878  *  @param priv         A pointer to moal_private structure
1879  *  @param wrq          A pointer to iwreq structure
1880  *
1881  *  @return             0 --success, otherwise fail
1882  */
1883 static int
woal_net_monitor_ioctl(moal_private * priv,struct iwreq * wrq)1884 woal_net_monitor_ioctl(moal_private *priv, struct iwreq *wrq)
1885 {
1886 	int user_data_len = wrq->u.data.length;
1887 	int data[5] = { 0 }, copy_len;
1888 	int ret = 0;
1889 	mlan_ioctl_req *req = NULL;
1890 	mlan_ds_misc_cfg *misc = NULL;
1891 	mlan_ds_misc_net_monitor *net_mon = NULL;
1892 	mlan_status status = MLAN_STATUS_SUCCESS;
1893 
1894 	ENTER();
1895 
1896 	copy_len = MIN(sizeof(data), sizeof(int) * user_data_len);
1897 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1898 	if (req == NULL) {
1899 		LEAVE();
1900 		return -ENOMEM;
1901 	}
1902 	misc = (mlan_ds_misc_cfg *)req->pbuf;
1903 	net_mon = (mlan_ds_misc_net_monitor *)&misc->param.net_mon;
1904 	misc->sub_command = MLAN_OID_MISC_NET_MONITOR;
1905 	req->req_id = MLAN_IOCTL_MISC_CFG;
1906 
1907 	if (!user_data_len) {
1908 		req->action = MLAN_ACT_GET;
1909 	} else if (user_data_len == 1 || user_data_len == 4
1910 		   || user_data_len == 5) {
1911 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
1912 			PRINTM(MERROR, "Copy from user failed\n");
1913 			ret = -EFAULT;
1914 			goto done;
1915 		}
1916 		if (data[0] != MTRUE && data[0] != MFALSE) {
1917 			PRINTM(MERROR,
1918 			       "NET_MON: Activity should be enable(=1)/disable(=0)\n");
1919 			ret = -EINVAL;
1920 			goto done;
1921 		}
1922 		net_mon->enable_net_mon = data[0];
1923 		if (data[0] == MTRUE) {
1924 			int i;
1925 			if (user_data_len != 4 && user_data_len != 5) {
1926 				PRINTM(MERROR,
1927 				       "NET_MON: Invalid number of args!\n");
1928 				ret = -EINVAL;
1929 				goto done;
1930 			}
1931 			/* Supported filter flags */
1932 			if (!data[1] || data[1] &
1933 			    ~(MLAN_NETMON_DATA_FRAME |
1934 			      MLAN_NETMON_MANAGEMENT_FRAME |
1935 			      MLAN_NETMON_CONTROL_FRAME)) {
1936 				PRINTM(MERROR,
1937 				       "NET_MON: Invalid filter flag\n");
1938 				ret = -EINVAL;
1939 				goto done;
1940 			}
1941 			/* Supported bands */
1942 			for (i = 0; i < sizeof(SupportedAdhocBand); i++)
1943 				if (data[2] == SupportedAdhocBand[i])
1944 					break;
1945 			if (i == sizeof(SupportedAdhocBand)) {
1946 				PRINTM(MERROR, "NET_MON: Invalid band\n");
1947 				ret = -EINVAL;
1948 				goto done;
1949 			}
1950 			/* Supported channel */
1951 			if (data[3] < 1 || data[3] > MLAN_MAX_CHANNEL) {
1952 				PRINTM(MERROR,
1953 				       "NET_MON: Invalid channel number\n");
1954 				ret = -EINVAL;
1955 				goto done;
1956 			}
1957 			if (user_data_len == 5) {
1958 				/* Secondary channel offset */
1959 				if (!(data[2] & (BAND_GN | BAND_AN))) {
1960 					PRINTM(MERROR,
1961 					       "No 11n in band, can not set "
1962 					       "secondary channel offset\n");
1963 					ret = -EINVAL;
1964 					goto done;
1965 				}
1966 				if ((data[4] != CHANNEL_BW_20MHZ) &&
1967 				    (data[4] != CHANNEL_BW_40MHZ_ABOVE) &&
1968 				    (data[4] != CHANNEL_BW_40MHZ_BELOW)
1969 					) {
1970 					PRINTM(MERROR,
1971 					       "Invalid secondary channel bandwidth, "
1972 					       "only allowed 0, 1, 3 or 4\n");
1973 					ret = -EINVAL;
1974 					goto done;
1975 				}
1976 				net_mon->chan_bandwidth = data[4];
1977 			}
1978 			net_mon->filter_flag = data[1];
1979 			net_mon->band = data[2];
1980 			net_mon->channel = data[3];
1981 		}
1982 		req->action = MLAN_ACT_SET;
1983 	} else {
1984 		PRINTM(MERROR, "NET_MON: Invalid number of args!\n");
1985 		ret = -EINVAL;
1986 		goto done;
1987 	}
1988 
1989 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1990 	if (status != MLAN_STATUS_SUCCESS) {
1991 		ret = -EFAULT;
1992 		goto done;
1993 	}
1994 
1995 	data[0] = net_mon->enable_net_mon;
1996 	data[1] = net_mon->filter_flag;
1997 	data[2] = net_mon->band;
1998 	data[3] = net_mon->channel;
1999 	data[4] = net_mon->chan_bandwidth;
2000 	wrq->u.data.length = 5;
2001 	if (copy_to_user
2002 	    (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
2003 		PRINTM(MERROR, "Copy to user failed\n");
2004 		ret = -EFAULT;
2005 		goto done;
2006 	}
2007 
2008 done:
2009 	if (status != MLAN_STATUS_PENDING)
2010 		kfree(req);
2011 	LEAVE();
2012 	return ret;
2013 }
2014 
2015 /**
2016  *  @brief Get LOG
2017  *
2018  *  @param priv         A pointer to moal_private structure
2019  *  @param wrq          A pointer to iwreq structure
2020  *
2021  *  @return             0 --success, otherwise fail
2022  */
2023 static int
woal_get_log(moal_private * priv,struct iwreq * wrq)2024 woal_get_log(moal_private *priv, struct iwreq *wrq)
2025 {
2026 	int ret = 0;
2027 	mlan_ds_get_stats stats;
2028 	char *buf = NULL;
2029 	int i = 0;
2030 
2031 	ENTER();
2032 
2033 	PRINTM(MINFO, " GET STATS\n");
2034 	buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL);
2035 	if (!buf) {
2036 		PRINTM(MERROR, "kmalloc failed!\n");
2037 		ret = -ENOMEM;
2038 		goto done;
2039 	}
2040 
2041 	memset(&stats, 0, sizeof(mlan_ds_get_stats));
2042 	if (MLAN_STATUS_SUCCESS !=
2043 	    woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
2044 		ret = -EFAULT;
2045 		goto done;
2046 	}
2047 
2048 	if (wrq->u.data.pointer) {
2049 		sprintf(buf, "\n"
2050 			"mcasttxframe     %u\n"
2051 			"failed           %u\n"
2052 			"retry            %u\n"
2053 			"multiretry       %u\n"
2054 			"framedup         %u\n"
2055 			"rtssuccess       %u\n"
2056 			"rtsfailure       %u\n"
2057 			"ackfailure       %u\n"
2058 			"rxfrag           %u\n"
2059 			"mcastrxframe     %u\n"
2060 			"fcserror         %u\n"
2061 			"txframe          %u\n"
2062 			"wepicverrcnt-1   %u\n"
2063 			"wepicverrcnt-2   %u\n"
2064 			"wepicverrcnt-3   %u\n"
2065 			"wepicverrcnt-4   %u\n"
2066 			"beacon_rcnt      %u\n"
2067 			"beacon_mcnt      %u\n",
2068 			stats.mcast_tx_frame,
2069 			stats.failed,
2070 			stats.retry,
2071 			stats.multi_retry,
2072 			stats.frame_dup,
2073 			stats.rts_success,
2074 			stats.rts_failure,
2075 			stats.ack_failure,
2076 			stats.rx_frag,
2077 			stats.mcast_rx_frame,
2078 			stats.fcs_error,
2079 			stats.tx_frame,
2080 			stats.wep_icv_error[0],
2081 			stats.wep_icv_error[1],
2082 			stats.wep_icv_error[2],
2083 			stats.wep_icv_error[3],
2084 			stats.bcn_rcv_cnt, stats.bcn_miss_cnt);
2085 		if (priv->phandle->fw_getlog_enable) {
2086 			sprintf(buf + strlen(buf), "tx_frag_cnt       %u\n",
2087 				stats.tx_frag_cnt);
2088 			sprintf(buf + strlen(buf), "qos_tx_frag_cnt        ");
2089 			for (i = 0; i < 8; i++) {
2090 				sprintf(buf + strlen(buf), "%u ",
2091 					stats.qos_tx_frag_cnt[i]);
2092 			}
2093 			sprintf(buf + strlen(buf), "\nqos_failed_cnt         ");
2094 			for (i = 0; i < 8; i++) {
2095 				sprintf(buf + strlen(buf), "%u ",
2096 					stats.qos_failed_cnt[i]);
2097 			}
2098 			sprintf(buf + strlen(buf), "\nqos_retry_cnt          ");
2099 			for (i = 0; i < 8; i++) {
2100 				sprintf(buf + strlen(buf), "%u ",
2101 					stats.qos_retry_cnt[i]);
2102 			}
2103 			sprintf(buf + strlen(buf), "\nqos_multi_retry_cnt    ");
2104 			for (i = 0; i < 8; i++) {
2105 				sprintf(buf + strlen(buf), "%u ",
2106 					stats.qos_multi_retry_cnt[i]);
2107 			}
2108 			sprintf(buf + strlen(buf), "\nqos_frm_dup_cnt        ");
2109 			for (i = 0; i < 8; i++) {
2110 				sprintf(buf + strlen(buf), "%u ",
2111 					stats.qos_frm_dup_cnt[i]);
2112 			}
2113 			sprintf(buf + strlen(buf), "\nqos_rts_suc_cnt        ");
2114 			for (i = 0; i < 8; i++) {
2115 				sprintf(buf + strlen(buf), "%u ",
2116 					stats.qos_rts_suc_cnt[i]);
2117 			}
2118 			sprintf(buf + strlen(buf),
2119 				"\nqos_rts_failure_cnt        ");
2120 			for (i = 0; i < 8; i++) {
2121 				sprintf(buf + strlen(buf), "%u ",
2122 					stats.qos_rts_failure_cnt[i]);
2123 			}
2124 			sprintf(buf + strlen(buf), "\nqos_ack_failure_cnt    ");
2125 			for (i = 0; i < 8; i++) {
2126 				sprintf(buf + strlen(buf), "%u ",
2127 					stats.qos_ack_failure_cnt[i]);
2128 			}
2129 			sprintf(buf + strlen(buf), "\nqos_rx_frag_cnt        ");
2130 			for (i = 0; i < 8; i++) {
2131 				sprintf(buf + strlen(buf), "%u ",
2132 					stats.qos_rx_frag_cnt[i]);
2133 			}
2134 			sprintf(buf + strlen(buf), "\nqos_tx_frm_cnt         ");
2135 			for (i = 0; i < 8; i++) {
2136 				sprintf(buf + strlen(buf), "%u ",
2137 					stats.qos_tx_frm_cnt[i]);
2138 			}
2139 			sprintf(buf + strlen(buf), "\nqos_discarded_frm_cnt  ");
2140 			for (i = 0; i < 8; i++) {
2141 				sprintf(buf + strlen(buf), "%u ",
2142 					stats.qos_discarded_frm_cnt[i]);
2143 			}
2144 			sprintf(buf + strlen(buf), "\nqos_mpdus_rx_cnt       ");
2145 			for (i = 0; i < 8; i++) {
2146 				sprintf(buf + strlen(buf), "%u ",
2147 					stats.qos_mpdus_rx_cnt[i]);
2148 			}
2149 			sprintf(buf + strlen(buf), "\nqos_retries_rx_cnt     ");
2150 			for (i = 0; i < 8; i++) {
2151 				sprintf(buf + strlen(buf), "%u ",
2152 					stats.qos_retries_rx_cnt[i]);
2153 			}
2154 			sprintf(buf + strlen(buf),
2155 				"\nmgmt_ccmp_replays      %u\n"
2156 				"tx_amsdu_cnt           %u\n"
2157 				"failed_amsdu_cnt       %u\n"
2158 				"retry_amsdu_cnt        %u\n"
2159 				"multi_retry_amsdu_cnt  %u\n"
2160 				"tx_octets_in_amsdu_cnt %llu\n"
2161 				"amsdu_ack_failure_cnt  %u\n"
2162 				"rx_amsdu_cnt           %u\n"
2163 				"rx_octets_in_amsdu_cnt %llu\n"
2164 				"tx_ampdu_cnt           %u\n"
2165 				"tx_mpdus_in_ampdu_cnt  %u\n"
2166 				"tx_octets_in_ampdu_cnt %llu\n"
2167 				"ampdu_rx_cnt           %u\n"
2168 				"mpdu_in_rx_ampdu_cnt   %u\n"
2169 				"rx_octets_in_ampdu_cnt %llu\n"
2170 				"ampdu_delimiter_crc_error_cnt      %u\n",
2171 				stats.mgmt_ccmp_replays, stats.tx_amsdu_cnt,
2172 				stats.failed_amsdu_cnt, stats.retry_amsdu_cnt,
2173 				stats.multi_retry_amsdu_cnt,
2174 				stats.tx_octets_in_amsdu_cnt,
2175 				stats.amsdu_ack_failure_cnt, stats.rx_amsdu_cnt,
2176 				stats.rx_octets_in_amsdu_cnt,
2177 				stats.tx_ampdu_cnt, stats.tx_mpdus_in_ampdu_cnt,
2178 				stats.tx_octets_in_ampdu_cnt,
2179 				stats.ampdu_rx_cnt, stats.mpdu_in_rx_ampdu_cnt,
2180 				stats.rx_octets_in_ampdu_cnt,
2181 				stats.ampdu_delimiter_crc_error_cnt);
2182 
2183 		}
2184 		wrq->u.data.length = strlen(buf) + 1;
2185 		if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
2186 			PRINTM(MERROR, "Copy to user failed\n");
2187 			ret = -EFAULT;
2188 		}
2189 	}
2190 done:
2191 	kfree(buf);
2192 	LEAVE();
2193 	return ret;
2194 }
2195 
2196 /**
2197  *  @brief Deauthenticate
2198  *
2199  *  @param priv         A pointer to moal_private structure
2200  *  @param wrq          A pointer to iwreq structure
2201  *
2202  *  @return             0 --success, otherwise fail
2203  */
2204 static int
woal_deauth(moal_private * priv,struct iwreq * wrq)2205 woal_deauth(moal_private *priv, struct iwreq *wrq)
2206 {
2207 	int ret = 0;
2208 	struct sockaddr saddr;
2209 
2210 	ENTER();
2211 	if (wrq->u.data.length) {
2212 		/* Deauth mentioned BSSID */
2213 		if (copy_from_user(&saddr, wrq->u.data.pointer, sizeof(saddr))) {
2214 			PRINTM(MERROR, "Copy from user failed\n");
2215 			ret = -EFAULT;
2216 			goto done;
2217 		}
2218 		if (MLAN_STATUS_SUCCESS !=
2219 		    woal_disconnect(priv, MOAL_IOCTL_WAIT,
2220 				    (t_u8 *)saddr.sa_data,
2221 				    DEF_DEAUTH_REASON_CODE)) {
2222 			ret = -EFAULT;
2223 			goto done;
2224 		}
2225 	} else {
2226 		if (MLAN_STATUS_SUCCESS !=
2227 		    woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
2228 				    DEF_DEAUTH_REASON_CODE))
2229 			ret = -EFAULT;
2230 	}
2231 done:
2232 	LEAVE();
2233 	return ret;
2234 }
2235 
2236 /**
2237  *  @brief Set/Get TX power configurations
2238  *
2239  *  @param priv     A pointer to moal_private structure
2240  *  @param wrq      A pointer to iwreq structure
2241  *
2242  *  @return         0 --success, otherwise fail
2243  */
2244 static int
woal_tx_power_cfg(moal_private * priv,struct iwreq * wrq)2245 woal_tx_power_cfg(moal_private *priv, struct iwreq *wrq)
2246 {
2247 	int data[5], user_data_len, copy_len;
2248 	int ret = 0;
2249 	mlan_bss_info bss_info;
2250 	mlan_ds_power_cfg *pcfg = NULL;
2251 	mlan_ioctl_req *req = NULL;
2252 	int power_data[MAX_POWER_TABLE_SIZE];
2253 	int i, power_ext_len = 0;
2254 	int *ptr = power_data;
2255 	mlan_power_group *pwr_grp = NULL;
2256 	mlan_status status = MLAN_STATUS_SUCCESS;
2257 	ENTER();
2258 
2259 	memset(&bss_info, 0, sizeof(bss_info));
2260 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2261 
2262 	memset(data, 0, sizeof(data));
2263 	user_data_len = wrq->u.data.length;
2264 	copy_len = MIN(sizeof(data), sizeof(int) * user_data_len);
2265 
2266 	if (user_data_len) {
2267 		if (sizeof(int) * user_data_len > sizeof(data)) {
2268 			PRINTM(MERROR, "Too many arguments\n");
2269 			ret = -EINVAL;
2270 			goto done;
2271 		}
2272 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
2273 			PRINTM(MERROR, "Copy from user failed\n");
2274 			ret = -EFAULT;
2275 			goto done;
2276 		}
2277 		switch (user_data_len) {
2278 		case 1:
2279 			if (data[0] != 0xFF)
2280 				ret = -EINVAL;
2281 			break;
2282 		case 2:
2283 		case 4:
2284 			if (data[0] == 0xFF) {
2285 				ret = -EINVAL;
2286 				break;
2287 			}
2288 			if (data[1] < bss_info.min_power_level) {
2289 				PRINTM(MERROR,
2290 				       "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
2291 				       data[1], (int)bss_info.min_power_level,
2292 				       (int)bss_info.max_power_level);
2293 				ret = -EINVAL;
2294 				break;
2295 			}
2296 			if (user_data_len == 4) {
2297 				if (data[1] > data[2]) {
2298 					PRINTM(MERROR,
2299 					       "Min power should be less than maximum!\n");
2300 					ret = -EINVAL;
2301 					break;
2302 				}
2303 				if (data[3] < 0) {
2304 					PRINTM(MERROR,
2305 					       "Step should not less than 0!\n");
2306 					ret = -EINVAL;
2307 					break;
2308 				}
2309 				if (data[2] > bss_info.max_power_level) {
2310 					PRINTM(MERROR,
2311 					       "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
2312 					       data[2],
2313 					       (int)bss_info.min_power_level,
2314 					       (int)bss_info.max_power_level);
2315 					ret = -EINVAL;
2316 					break;
2317 				}
2318 				if (data[3] > data[2] - data[1]) {
2319 					PRINTM(MERROR,
2320 					       "Step should not greater than power difference!\n");
2321 					ret = -EINVAL;
2322 					break;
2323 				}
2324 			}
2325 			break;
2326 		default:
2327 			ret = -EINVAL;
2328 			break;
2329 		}
2330 		if (ret)
2331 			goto done;
2332 	}
2333 
2334 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
2335 	if (req == NULL) {
2336 		ret = -ENOMEM;
2337 		goto done;
2338 	}
2339 	pcfg = (mlan_ds_power_cfg *)req->pbuf;
2340 	pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
2341 	req->req_id = MLAN_IOCTL_POWER_CFG;
2342 	if (!user_data_len)
2343 		req->action = MLAN_ACT_GET;
2344 	else {
2345 		req->action = MLAN_ACT_SET;
2346 		if (data[0] == 0xFF)
2347 			pcfg->param.power_ext.power_group[0].rate_format =
2348 				TX_PWR_CFG_AUTO_CTRL_OFF;
2349 		else {
2350 			pcfg->param.power_ext.power_group[0].power_step = 0;
2351 			pcfg->param.power_ext.power_group[0].first_rate_ind =
2352 				data[0];
2353 			pcfg->param.power_ext.power_group[0].last_rate_ind =
2354 				data[0];
2355 			if (data[0] <= 11) {
2356 				pcfg->param.power_ext.power_group[0].
2357 					rate_format = MLAN_RATE_FORMAT_LG;
2358 				pcfg->param.power_ext.power_group[0].bandwidth =
2359 					MLAN_HT_BW20;
2360 			} else if (data[0] <= 27) {
2361 				pcfg->param.power_ext.power_group[0].
2362 					rate_format = MLAN_RATE_FORMAT_HT;
2363 				pcfg->param.power_ext.power_group[0].bandwidth =
2364 					MLAN_HT_BW20;
2365 				pcfg->param.power_ext.power_group[0].
2366 					first_rate_ind -= 12;
2367 				pcfg->param.power_ext.power_group[0].
2368 					last_rate_ind -= 12;
2369 			} else if ((140 <= data[0]) && (data[0] <= 155)) {
2370 				pcfg->param.power_ext.power_group[0].
2371 					rate_format = MLAN_RATE_FORMAT_HT;
2372 				pcfg->param.power_ext.power_group[0].bandwidth =
2373 					MLAN_HT_BW40;
2374 				pcfg->param.power_ext.power_group[0].
2375 					first_rate_ind -= 140;
2376 				pcfg->param.power_ext.power_group[0].
2377 					last_rate_ind -= 140;
2378 			}
2379 			if (user_data_len == 2) {
2380 				pcfg->param.power_ext.power_group[0].power_min =
2381 					data[1];
2382 				pcfg->param.power_ext.power_group[0].power_max =
2383 					data[1];
2384 			} else if (user_data_len == 4) {
2385 				pcfg->param.power_ext.power_group[0].power_min =
2386 					data[1];
2387 				pcfg->param.power_ext.power_group[0].power_max =
2388 					data[2];
2389 				pcfg->param.power_ext.power_group[0].
2390 					power_step = data[3];
2391 			}
2392 			pcfg->param.power_ext.num_pwr_grp = 1;
2393 		}
2394 	}
2395 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2396 	if (status != MLAN_STATUS_SUCCESS) {
2397 		ret = -EFAULT;
2398 		goto done;
2399 	}
2400 	if (!user_data_len) {
2401 		/* GET operation */
2402 		i = 0;
2403 		power_ext_len = 0;
2404 		ptr = power_data;
2405 		while ((i < pcfg->param.power_ext.num_pwr_grp) &&
2406 		       (power_ext_len < MAX_POWER_TABLE_SIZE)) {
2407 			pwr_grp = &pcfg->param.power_ext.power_group[i];
2408 			if (pwr_grp->rate_format == MLAN_RATE_FORMAT_HT) {
2409 				if (pwr_grp->bandwidth == MLAN_HT_BW20) {
2410 					pwr_grp->first_rate_ind += 12;
2411 					pwr_grp->last_rate_ind += 12;
2412 				} else if (pwr_grp->bandwidth == MLAN_HT_BW40) {
2413 					pwr_grp->first_rate_ind += 140;
2414 					pwr_grp->last_rate_ind += 140;
2415 				}
2416 			}
2417 
2418 			if ((pwr_grp->rate_format == MLAN_RATE_FORMAT_LG) ||
2419 			    (pwr_grp->rate_format == MLAN_RATE_FORMAT_HT)) {
2420 				*ptr = pwr_grp->first_rate_ind;
2421 				ptr++;
2422 				*ptr = pwr_grp->last_rate_ind;
2423 				ptr++;
2424 				*ptr = pwr_grp->power_min;
2425 				ptr++;
2426 				*ptr = pwr_grp->power_max;
2427 				ptr++;
2428 				*ptr = pwr_grp->power_step;
2429 				ptr++;
2430 				power_ext_len += 5;
2431 			}
2432 			i++;
2433 		}
2434 		if (copy_to_user(wrq->u.data.pointer, (t_u8 *)power_data,
2435 				 sizeof(int) * power_ext_len)) {
2436 			ret = -EFAULT;
2437 			goto done;
2438 		}
2439 		wrq->u.data.length = power_ext_len;
2440 	}
2441 done:
2442 	if (status != MLAN_STATUS_PENDING)
2443 		kfree(req);
2444 	LEAVE();
2445 	return ret;
2446 }
2447 
2448 /**
2449  *  @brief Get Tx/Rx data rates
2450  *
2451  *  @param priv     A pointer to moal_private structure
2452  *  @param wrq      A pointer to iwreq structure
2453  *
2454  *  @return         0 --success, otherwise fail
2455  */
2456 static int
woal_get_txrx_rate(moal_private * priv,struct iwreq * wrq)2457 woal_get_txrx_rate(moal_private *priv, struct iwreq *wrq)
2458 {
2459 	int ret = 0;
2460 	mlan_ds_rate *rate = NULL;
2461 	mlan_ioctl_req *req = NULL;
2462 	mlan_status status = MLAN_STATUS_SUCCESS;
2463 
2464 	ENTER();
2465 
2466 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2467 	if (req == NULL) {
2468 		ret = -ENOMEM;
2469 		goto done;
2470 	}
2471 	rate = (mlan_ds_rate *)req->pbuf;
2472 	rate->sub_command = MLAN_OID_GET_DATA_RATE;
2473 	req->req_id = MLAN_IOCTL_RATE;
2474 	req->action = MLAN_ACT_GET;
2475 
2476 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2477 	if (status != MLAN_STATUS_SUCCESS) {
2478 		ret = -EFAULT;
2479 		goto done;
2480 	}
2481 
2482 	if (copy_to_user
2483 	    (wrq->u.data.pointer, (t_u8 *)&rate->param.data_rate,
2484 	     sizeof(int) * 2)) {
2485 		ret = -EFAULT;
2486 		goto done;
2487 	}
2488 	wrq->u.data.length = 2;
2489 done:
2490 	if (status != MLAN_STATUS_PENDING)
2491 		kfree(req);
2492 	LEAVE();
2493 	return ret;
2494 }
2495 
2496 /**
2497  *  @brief Turn on/off the sdio clock
2498  *
2499  *  @param priv     A pointer to moal_private structure
2500  *  @param wrq      A pointer to iwreq structure
2501  *
2502  *  @return         0/MLAN_STATUS_SUCCESS --success, otherwise fail
2503  */
2504 static int
woal_sdio_clock_ioctl(moal_private * priv,struct iwreq * wrq)2505 woal_sdio_clock_ioctl(moal_private *priv, struct iwreq *wrq)
2506 {
2507 	int ret = 0;
2508 	int data = 2;
2509 	/* Initialize the clock state as on */
2510 	static int clock_state = 1;
2511 
2512 	ENTER();
2513 
2514 	if (wrq->u.data.length) {
2515 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
2516 			PRINTM(MERROR, "Copy from user failed\n");
2517 			ret = -EFAULT;
2518 			goto done;
2519 		}
2520 	} else {
2521 		wrq->u.data.length = sizeof(clock_state) / sizeof(int);
2522 		if (copy_to_user
2523 		    (wrq->u.data.pointer, &clock_state, sizeof(int))) {
2524 			PRINTM(MERROR, "Copy from user failed\n");
2525 			ret = -EFAULT;
2526 			goto done;
2527 		}
2528 
2529 		goto done;
2530 	}
2531 	switch (data) {
2532 	case CMD_DISABLED:
2533 		PRINTM(MINFO, "SDIO clock is turned off\n");
2534 		ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
2535 		clock_state = data;
2536 		break;
2537 	case CMD_ENABLED:
2538 		PRINTM(MINFO, "SDIO clock is turned on\n");
2539 		ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
2540 		clock_state = data;
2541 		break;
2542 	default:
2543 		ret = -EINVAL;
2544 		PRINTM(MINFO, "sdioclock: wrong parameter\n");
2545 		break;
2546 	}
2547 done:
2548 	LEAVE();
2549 	return ret;
2550 }
2551 
2552 /**
2553  *  @brief Set/Get beacon interval
2554  *
2555  *  @param priv     A pointer to moal_private structure
2556  *  @param wrq      A pointer to iwreq structure
2557  *
2558  *  @return         0 --success, otherwise fail
2559  */
2560 static int
woal_beacon_interval(moal_private * priv,struct iwreq * wrq)2561 woal_beacon_interval(moal_private *priv, struct iwreq *wrq)
2562 {
2563 	int ret = 0;
2564 	mlan_ds_bss *bss = NULL;
2565 	mlan_ioctl_req *req = NULL;
2566 	int bcn = 0;
2567 	mlan_status status = MLAN_STATUS_SUCCESS;
2568 
2569 	ENTER();
2570 
2571 	if (wrq->u.data.length) {
2572 		if (copy_from_user(&bcn, wrq->u.data.pointer, sizeof(int))) {
2573 			PRINTM(MERROR, "Copy from user failed\n");
2574 			ret = -EFAULT;
2575 			goto done;
2576 		}
2577 		if ((bcn < MLAN_MIN_BEACON_INTERVAL) ||
2578 		    (bcn > MLAN_MAX_BEACON_INTERVAL)) {
2579 			ret = -EINVAL;
2580 			goto done;
2581 		}
2582 	}
2583 
2584 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2585 	if (req == NULL) {
2586 		ret = -ENOMEM;
2587 		goto done;
2588 	}
2589 	bss = (mlan_ds_bss *)req->pbuf;
2590 	bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
2591 	req->req_id = MLAN_IOCTL_BSS;
2592 	if (!wrq->u.data.length)
2593 		req->action = MLAN_ACT_GET;
2594 	else {
2595 		req->action = MLAN_ACT_SET;
2596 		bss->param.bcn_interval = bcn;
2597 	}
2598 
2599 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2600 	if (status != MLAN_STATUS_SUCCESS) {
2601 		ret = -EFAULT;
2602 		goto done;
2603 	}
2604 
2605 	if (copy_to_user
2606 	    (wrq->u.data.pointer, (t_u8 *)&bss->param.bcn_interval,
2607 	     sizeof(int))) {
2608 		ret = -EFAULT;
2609 		goto done;
2610 	}
2611 	wrq->u.data.length = 1;
2612 done:
2613 	if (status != MLAN_STATUS_PENDING)
2614 		kfree(req);
2615 	LEAVE();
2616 	return ret;
2617 }
2618 
2619 /**
2620  *  @brief Set/Get ATIM window
2621  *
2622  *  @param priv     A pointer to moal_private structure
2623  *  @param wrq      A pointer to iwreq structure
2624  *
2625  *  @return         0 --success, otherwise fail
2626  */
2627 static int
woal_atim_window(moal_private * priv,struct iwreq * wrq)2628 woal_atim_window(moal_private *priv, struct iwreq *wrq)
2629 {
2630 	int ret = 0;
2631 	mlan_ds_bss *bss = NULL;
2632 	mlan_ioctl_req *req = NULL;
2633 	int atim = 0;
2634 	mlan_status status = MLAN_STATUS_SUCCESS;
2635 
2636 	ENTER();
2637 
2638 	if (wrq->u.data.length) {
2639 		if (copy_from_user(&atim, wrq->u.data.pointer, sizeof(int))) {
2640 			PRINTM(MERROR, "Copy from user failed\n");
2641 			ret = -EFAULT;
2642 			goto done;
2643 		}
2644 		if ((atim < 0) || (atim > MLAN_MAX_ATIM_WINDOW)) {
2645 			ret = -EINVAL;
2646 			goto done;
2647 		}
2648 	}
2649 
2650 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2651 	if (req == NULL) {
2652 		ret = -ENOMEM;
2653 		goto done;
2654 	}
2655 	bss = (mlan_ds_bss *)req->pbuf;
2656 	bss->sub_command = MLAN_OID_IBSS_ATIM_WINDOW;
2657 	req->req_id = MLAN_IOCTL_BSS;
2658 	if (!wrq->u.data.length)
2659 		req->action = MLAN_ACT_GET;
2660 	else {
2661 		req->action = MLAN_ACT_SET;
2662 		bss->param.atim_window = atim;
2663 	}
2664 
2665 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2666 	if (status != MLAN_STATUS_SUCCESS) {
2667 		ret = -EFAULT;
2668 		goto done;
2669 	}
2670 
2671 	if (copy_to_user
2672 	    (wrq->u.data.pointer, (t_u8 *)&bss->param.atim_window,
2673 	     sizeof(int))) {
2674 		ret = -EFAULT;
2675 		goto done;
2676 	}
2677 	wrq->u.data.length = 1;
2678 done:
2679 	if (status != MLAN_STATUS_PENDING)
2680 		kfree(req);
2681 	LEAVE();
2682 	return ret;
2683 }
2684 
2685 /**
2686  * @brief Set/Get TX data rate
2687  *
2688  * @param priv      A pointer to moal_private structure
2689  * @param wrq       A pointer to iwreq structure
2690  *
2691  * @return          0 --success, otherwise fail
2692  */
2693 static int
woal_set_get_txrate(moal_private * priv,struct iwreq * wrq)2694 woal_set_get_txrate(moal_private *priv, struct iwreq *wrq)
2695 {
2696 	int ret = 0;
2697 	mlan_ds_rate *rate = NULL;
2698 	mlan_ioctl_req *req = NULL;
2699 	int rateindex = 0;
2700 	mlan_status status = MLAN_STATUS_SUCCESS;
2701 
2702 	ENTER();
2703 	if (wrq->u.data.length) {
2704 		if (copy_from_user
2705 		    (&rateindex, wrq->u.data.pointer, sizeof(int))) {
2706 			PRINTM(MERROR, "Copy from user failed\n");
2707 			ret = -EFAULT;
2708 			goto done;
2709 		}
2710 	}
2711 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2712 	if (req == NULL) {
2713 		ret = -ENOMEM;
2714 		goto done;
2715 	}
2716 
2717 	rate = (mlan_ds_rate *)req->pbuf;
2718 	rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
2719 	rate->sub_command = MLAN_OID_RATE_CFG;
2720 	req->req_id = MLAN_IOCTL_RATE;
2721 	if (!wrq->u.data.length)
2722 		req->action = MLAN_ACT_GET;
2723 	else {
2724 		req->action = MLAN_ACT_SET;
2725 		if (rateindex == AUTO_RATE)
2726 			rate->param.rate_cfg.is_rate_auto = 1;
2727 		else {
2728 			if ((rateindex != MLAN_RATE_INDEX_MCS32) &&
2729 			    ((rateindex < 0) ||
2730 			     (rateindex > MLAN_RATE_INDEX_MCS7))) {
2731 				ret = -EINVAL;
2732 				goto done;
2733 			}
2734 		}
2735 		rate->param.rate_cfg.rate = rateindex;
2736 	}
2737 
2738 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2739 	if (status != MLAN_STATUS_SUCCESS) {
2740 		ret = -EFAULT;
2741 		goto done;
2742 	} else {
2743 		if (wrq->u.data.length)
2744 			priv->rate_index = rateindex;
2745 	}
2746 	if (!wrq->u.data.length) {
2747 		if (rate->param.rate_cfg.is_rate_auto)
2748 			rateindex = AUTO_RATE;
2749 		else
2750 			rateindex = rate->param.rate_cfg.rate;
2751 		wrq->u.data.length = 1;
2752 		if (copy_to_user(wrq->u.data.pointer, &rateindex, sizeof(int)))
2753 			ret = -EFAULT;
2754 	}
2755 done:
2756 	if (status != MLAN_STATUS_PENDING)
2757 		kfree(req);
2758 	LEAVE();
2759 	return ret;
2760 }
2761 
2762 /**
2763  * @brief Set/Get region code
2764  *
2765  * @param priv      A pointer to moal_private structure
2766  * @param wrq       A pointer to iwreq structure
2767  *
2768  * @return          0 --success, otherwise fail
2769  */
2770 static int
woal_set_get_regioncode(moal_private * priv,struct iwreq * wrq)2771 woal_set_get_regioncode(moal_private *priv, struct iwreq *wrq)
2772 {
2773 	int ret = 0;
2774 	mlan_ds_misc_cfg *cfg = NULL;
2775 	mlan_ioctl_req *req = NULL;
2776 	int region = 0;
2777 	mlan_status status = MLAN_STATUS_SUCCESS;
2778 
2779 	ENTER();
2780 
2781 	if (wrq->u.data.length) {
2782 		if (copy_from_user(&region, wrq->u.data.pointer, sizeof(int))) {
2783 			PRINTM(MERROR, "Copy from user failed\n");
2784 			ret = -EFAULT;
2785 			goto done;
2786 		}
2787 	}
2788 
2789 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
2790 	if (req == NULL) {
2791 		ret = -ENOMEM;
2792 		goto done;
2793 	}
2794 
2795 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
2796 	cfg->sub_command = MLAN_OID_MISC_REGION;
2797 	req->req_id = MLAN_IOCTL_MISC_CFG;
2798 	if (!wrq->u.data.length)
2799 		req->action = MLAN_ACT_GET;
2800 	else {
2801 		req->action = MLAN_ACT_SET;
2802 		cfg->param.region_code = region;
2803 	}
2804 
2805 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2806 	if (status != MLAN_STATUS_SUCCESS) {
2807 		ret = -EFAULT;
2808 		goto done;
2809 	}
2810 
2811 	if (!wrq->u.data.length) {
2812 		wrq->u.data.length = 1;
2813 		if (copy_to_user
2814 		    (wrq->u.data.pointer, &cfg->param.region_code, sizeof(int)))
2815 			ret = -EFAULT;
2816 	}
2817 done:
2818 	if (status != MLAN_STATUS_PENDING)
2819 		kfree(req);
2820 	LEAVE();
2821 	return ret;
2822 }
2823 
2824 /**
2825  * @brief Set/Get radio
2826  *
2827  * @param priv      A pointer to moal_private structure
2828  * @param wrq       A pointer to iwreq structure
2829  *
2830  * @return          0 --success, otherwise fail
2831  */
2832 static int
woal_set_get_radio(moal_private * priv,struct iwreq * wrq)2833 woal_set_get_radio(moal_private *priv, struct iwreq *wrq)
2834 {
2835 	int ret = 0;
2836 	mlan_bss_info bss_info;
2837 	int option = 0;
2838 
2839 	ENTER();
2840 
2841 	memset(&bss_info, 0, sizeof(bss_info));
2842 
2843 	if (wrq->u.data.length) {
2844 		/* Set radio */
2845 		if (copy_from_user(&option, wrq->u.data.pointer, sizeof(int))) {
2846 			PRINTM(MERROR, "Copy from user failed\n");
2847 			ret = -EFAULT;
2848 			goto done;
2849 		}
2850 		if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8)option))
2851 			ret = -EFAULT;
2852 	} else {
2853 		/* Get radio status */
2854 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2855 		wrq->u.data.length = 1;
2856 		if (copy_to_user
2857 		    (wrq->u.data.pointer, &bss_info.radio_on,
2858 		     sizeof(bss_info.radio_on))) {
2859 			PRINTM(MERROR, "Copy to user failed\n");
2860 			ret = -EFAULT;
2861 		}
2862 	}
2863 done:
2864 	LEAVE();
2865 	return ret;
2866 }
2867 
2868 #ifdef DEBUG_LEVEL1
2869 /**
2870  *  @brief Get/Set the bit mask of driver debug message control
2871  *
2872  *  @param priv         A pointer to moal_private structure
2873  *  @param wrq          A pointer to wrq structure
2874  *
2875  *  @return             0 --success, otherwise fail
2876  */
2877 static int
woal_drv_dbg(moal_private * priv,struct iwreq * wrq)2878 woal_drv_dbg(moal_private *priv, struct iwreq *wrq)
2879 {
2880 	int data[4], copy_len;
2881 	int ret = 0;
2882 	int data_length = wrq->u.data.length;
2883 	ENTER();
2884 
2885 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
2886 	if (!data_length) {
2887 		data[0] = drvdbg;
2888 		/* Return the current driver debug bit masks */
2889 		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
2890 			PRINTM(MERROR, "Copy to user failed\n");
2891 			ret = -EFAULT;
2892 			goto drvdbgexit;
2893 		}
2894 		wrq->u.data.length = 1;
2895 	} else if (data_length < 3) {
2896 		/* Get the driver debug bit masks from user */
2897 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
2898 			PRINTM(MERROR, "Copy from user failed\n");
2899 			ret = -EFAULT;
2900 			goto drvdbgexit;
2901 		}
2902 		drvdbg = data[0];
2903 		/* Set the driver debug bit masks into mlan */
2904 		woal_set_drvdbg(priv, drvdbg);
2905 	} else {
2906 		PRINTM(MERROR, "Invalid parameter number\n");
2907 		goto drvdbgexit;
2908 	}
2909 
2910 	printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
2911 #ifdef DEBUG_LEVEL2
2912 	printk(KERN_ALERT "MINFO  (%08x) %s\n", MINFO,
2913 	       (drvdbg & MINFO) ? "X" : "");
2914 	printk(KERN_ALERT "MWARN  (%08x) %s\n", MWARN,
2915 	       (drvdbg & MWARN) ? "X" : "");
2916 	printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
2917 	       (drvdbg & MENTRY) ? "X" : "");
2918 #endif
2919 	printk(KERN_ALERT "MMPA_D (%08x) %s\n", MMPA_D,
2920 	       (drvdbg & MMPA_D) ? "X" : "");
2921 	printk(KERN_ALERT "MIF_D  (%08x) %s\n", MIF_D,
2922 	       (drvdbg & MIF_D) ? "X" : "");
2923 	printk(KERN_ALERT "MFW_D  (%08x) %s\n", MFW_D,
2924 	       (drvdbg & MFW_D) ? "X" : "");
2925 	printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
2926 	       (drvdbg & MEVT_D) ? "X" : "");
2927 	printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
2928 	       (drvdbg & MCMD_D) ? "X" : "");
2929 	printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
2930 	       (drvdbg & MDAT_D) ? "X" : "");
2931 	printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
2932 	       (drvdbg & MIOCTL) ? "X" : "");
2933 	printk(KERN_ALERT "MINTR  (%08x) %s\n", MINTR,
2934 	       (drvdbg & MINTR) ? "X" : "");
2935 	printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
2936 	       (drvdbg & MEVENT) ? "X" : "");
2937 	printk(KERN_ALERT "MCMND  (%08x) %s\n", MCMND,
2938 	       (drvdbg & MCMND) ? "X" : "");
2939 	printk(KERN_ALERT "MDATA  (%08x) %s\n", MDATA,
2940 	       (drvdbg & MDATA) ? "X" : "");
2941 	printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
2942 	       (drvdbg & MERROR) ? "X" : "");
2943 	printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
2944 	       (drvdbg & MFATAL) ? "X" : "");
2945 	printk(KERN_ALERT "MMSG   (%08x) %s\n", MMSG,
2946 	       (drvdbg & MMSG) ? "X" : "");
2947 
2948 drvdbgexit:
2949 	LEAVE();
2950 	return ret;
2951 }
2952 #endif /* DEBUG_LEVEL1 */
2953 
2954 /**
2955  * @brief Set/Get QoS configuration
2956  *
2957  * @param priv     A pointer to moal_private structure
2958  * @param wrq      A pointer to iwreq structure
2959  *
2960  * @return         0 --success, otherwise fail
2961  */
2962 static int
woal_set_get_qos_cfg(moal_private * priv,struct iwreq * wrq)2963 woal_set_get_qos_cfg(moal_private *priv, struct iwreq *wrq)
2964 {
2965 	int ret = 0;
2966 	mlan_ds_wmm_cfg *cfg = NULL;
2967 	mlan_ioctl_req *req = NULL;
2968 	int data = 0;
2969 	mlan_status status = MLAN_STATUS_SUCCESS;
2970 
2971 	ENTER();
2972 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
2973 	if (req == NULL) {
2974 		ret = -ENOMEM;
2975 		goto done;
2976 	}
2977 	cfg = (mlan_ds_wmm_cfg *)req->pbuf;
2978 	cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
2979 	req->req_id = MLAN_IOCTL_WMM_CFG;
2980 	if (wrq->u.data.length) {
2981 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
2982 			PRINTM(MERROR, "Copy from user failed\n");
2983 			ret = -EFAULT;
2984 			goto done;
2985 		}
2986 		req->action = MLAN_ACT_SET;
2987 		cfg->param.qos_cfg = (t_u8)data;
2988 	} else
2989 		req->action = MLAN_ACT_GET;
2990 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2991 	if (status != MLAN_STATUS_SUCCESS) {
2992 		ret = -EFAULT;
2993 		goto done;
2994 	}
2995 	if (!wrq->u.data.length) {
2996 		data = (int)cfg->param.qos_cfg;
2997 		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
2998 			ret = -EFAULT;
2999 			goto done;
3000 		}
3001 		wrq->u.data.length = 1;
3002 	}
3003 done:
3004 	if (status != MLAN_STATUS_PENDING)
3005 		kfree(req);
3006 	LEAVE();
3007 	return ret;
3008 }
3009 
3010 /**
3011  * @brief Set/Get WWS mode
3012  *
3013  * @param priv      A pointer to moal_private structure
3014  * @param wrq       A pointer to iwreq structure
3015  *
3016  * @return          0 --success, otherwise fail
3017  */
3018 static int
woal_wws_cfg(moal_private * priv,struct iwreq * wrq)3019 woal_wws_cfg(moal_private *priv, struct iwreq *wrq)
3020 {
3021 	int ret = 0;
3022 	mlan_ds_misc_cfg *wws = NULL;
3023 	mlan_ioctl_req *req = NULL;
3024 	int data = 0;
3025 	mlan_status status = MLAN_STATUS_SUCCESS;
3026 
3027 	ENTER();
3028 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3029 	if (req == NULL) {
3030 		ret = -ENOMEM;
3031 		goto done;
3032 	}
3033 	wws = (mlan_ds_misc_cfg *)req->pbuf;
3034 	wws->sub_command = MLAN_OID_MISC_WWS;
3035 	req->req_id = MLAN_IOCTL_MISC_CFG;
3036 	if (wrq->u.data.length) {
3037 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
3038 			PRINTM(MERROR, "Copy from user failed\n");
3039 			ret = -EFAULT;
3040 			goto done;
3041 		}
3042 		if (data != CMD_DISABLED && data != CMD_ENABLED) {
3043 			ret = -EINVAL;
3044 			goto done;
3045 		}
3046 		req->action = MLAN_ACT_SET;
3047 		wws->param.wws_cfg = data;
3048 	} else
3049 		req->action = MLAN_ACT_GET;
3050 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3051 	if (status != MLAN_STATUS_SUCCESS) {
3052 		ret = -EFAULT;
3053 		goto done;
3054 	}
3055 	if (!wrq->u.data.length) {
3056 		data = wws->param.wws_cfg;
3057 		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
3058 			ret = -EFAULT;
3059 			goto done;
3060 		}
3061 		wrq->u.data.length = 1;
3062 	}
3063 done:
3064 	if (status != MLAN_STATUS_PENDING)
3065 		kfree(req);
3066 	LEAVE();
3067 	return ret;
3068 }
3069 
3070 /**
3071  * @brief Set/Get sleep period
3072  *
3073  * @param priv     A pointer to moal_private structure
3074  * @param wrq      A pointer to iwreq structure
3075  *
3076  * @return         0 --success, otherwise fail
3077  */
3078 static int
woal_sleep_pd(moal_private * priv,struct iwreq * wrq)3079 woal_sleep_pd(moal_private *priv, struct iwreq *wrq)
3080 {
3081 	int ret = 0;
3082 	mlan_ds_pm_cfg *pm_cfg = NULL;
3083 	mlan_ioctl_req *req = NULL;
3084 	int data = 0;
3085 	mlan_status status = MLAN_STATUS_SUCCESS;
3086 
3087 	ENTER();
3088 
3089 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
3090 	if (req == NULL) {
3091 		ret = -ENOMEM;
3092 		goto done;
3093 	}
3094 	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
3095 	pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
3096 	req->req_id = MLAN_IOCTL_PM_CFG;
3097 	if (wrq->u.data.length) {
3098 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
3099 			PRINTM(MERROR, "Copy from user failed\n");
3100 			ret = -EFAULT;
3101 			goto done;
3102 		}
3103 		if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
3104 		    (data == 0)
3105 		    || (data == SLEEP_PERIOD_RESERVED_FF)
3106 			) {
3107 			req->action = MLAN_ACT_SET;
3108 			pm_cfg->param.sleep_period = data;
3109 		} else {
3110 			ret = -EINVAL;
3111 			goto done;
3112 		}
3113 	} else
3114 		req->action = MLAN_ACT_GET;
3115 
3116 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3117 	if (status != MLAN_STATUS_SUCCESS) {
3118 		ret = -EFAULT;
3119 		goto done;
3120 	}
3121 	if (!wrq->u.data.length) {
3122 		data = pm_cfg->param.sleep_period;
3123 		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
3124 			ret = -EFAULT;
3125 			goto done;
3126 		}
3127 		wrq->u.data.length = 1;
3128 	}
3129 
3130 done:
3131 	if (status != MLAN_STATUS_PENDING)
3132 		kfree(req);
3133 	LEAVE();
3134 	return ret;
3135 }
3136 
3137 /**
3138  * @brief Set/Get module configuration
3139  *
3140  * @param priv     A pointer to moal_private structure
3141  * @param wrq      A pointer to iwreq structure
3142  *
3143  * @return         0 --success, otherwise fail
3144  */
3145 static int
woal_fw_wakeup_method(moal_private * priv,struct iwreq * wrq)3146 woal_fw_wakeup_method(moal_private *priv, struct iwreq *wrq)
3147 {
3148 	int ret = 0, data[2];
3149 	mlan_ds_pm_cfg *pm_cfg = NULL;
3150 	mlan_ioctl_req *req = NULL;
3151 	mlan_status status = MLAN_STATUS_SUCCESS;
3152 
3153 	ENTER();
3154 
3155 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
3156 	if (req == NULL) {
3157 		ret = -ENOMEM;
3158 		goto done;
3159 	}
3160 	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
3161 
3162 	if (wrq->u.data.length > 2) {
3163 		ret = -EINVAL;
3164 		goto done;
3165 	}
3166 	if (!wrq->u.data.length) {
3167 		req->action = MLAN_ACT_GET;
3168 	} else {
3169 		req->action = MLAN_ACT_SET;
3170 		if (copy_from_user
3171 		    (data, wrq->u.data.pointer,
3172 		     sizeof(int) * wrq->u.data.length)) {
3173 			PRINTM(MINFO, "Copy from user failed\n");
3174 			ret = -EFAULT;
3175 			goto done;
3176 		}
3177 		if (data[0] != FW_WAKEUP_METHOD_INTERFACE &&
3178 		    data[0] != FW_WAKEUP_METHOD_GPIO) {
3179 			PRINTM(MERROR, "Invalid FW wake up method:%d\n",
3180 			       data[0]);
3181 			ret = -EINVAL;
3182 			goto done;
3183 		}
3184 		if (data[0] == FW_WAKEUP_METHOD_GPIO) {
3185 			if (wrq->u.data.length == 1) {
3186 				PRINTM(MERROR,
3187 				       "Please provide gpio pin number for FW_WAKEUP_METHOD gpio\n");
3188 				ret = -EINVAL;
3189 				goto done;
3190 			}
3191 			pm_cfg->param.fw_wakeup_params.gpio_pin = data[1];
3192 		}
3193 
3194 		pm_cfg->param.fw_wakeup_params.method = data[0];
3195 	}
3196 
3197 	pm_cfg->sub_command = MLAN_OID_PM_CFG_FW_WAKEUP_METHOD;
3198 	req->req_id = MLAN_IOCTL_PM_CFG;
3199 
3200 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3201 	if (status != MLAN_STATUS_SUCCESS) {
3202 		ret = -EFAULT;
3203 		goto done;
3204 	}
3205 
3206 	data[0] = ((mlan_ds_pm_cfg *)req->pbuf)->param.fw_wakeup_params.method;
3207 	data[1] =
3208 		((mlan_ds_pm_cfg *)req->pbuf)->param.fw_wakeup_params.gpio_pin;
3209 
3210 	if (data[0] == FW_WAKEUP_METHOD_INTERFACE)
3211 		wrq->u.data.length = 1;
3212 	else
3213 		wrq->u.data.length = 2;
3214 	if (copy_to_user
3215 	    (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
3216 		ret = -EFAULT;
3217 		goto done;
3218 	}
3219 
3220 done:
3221 	if (status != MLAN_STATUS_PENDING)
3222 		kfree(req);
3223 	LEAVE();
3224 	return ret;
3225 }
3226 
3227 /**
3228  * @brief Configure sleep parameters
3229  *
3230  * @param priv         A pointer to moal_private structure
3231  * @param wrq         A pointer to iwreq structure
3232  *
3233  * @return             0 --success, otherwise fail
3234  */
3235 static int
woal_sleep_params_ioctl(moal_private * priv,struct iwreq * wrq)3236 woal_sleep_params_ioctl(moal_private *priv, struct iwreq *wrq)
3237 {
3238 	int ret = 0;
3239 	mlan_ioctl_req *req = NULL;
3240 	mlan_ds_pm_cfg *pm = NULL;
3241 	mlan_ds_sleep_params *psleep_params = NULL;
3242 	int data[6] = { 0 }, i, copy_len;
3243 	int data_length = wrq->u.data.length;
3244 #ifdef DEBUG_LEVEL1
3245 	char err_str[][35] = { {"sleep clock error in ppm"},
3246 	{"wakeup offset in usec"},
3247 	{"clock stabilization time in usec"},
3248 	{"value of reserved for debug"}
3249 	};
3250 #endif
3251 	mlan_status status = MLAN_STATUS_SUCCESS;
3252 
3253 	ENTER();
3254 
3255 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
3256 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
3257 	if (req == NULL) {
3258 		LEAVE();
3259 		return -ENOMEM;
3260 	}
3261 
3262 	pm = (mlan_ds_pm_cfg *)req->pbuf;
3263 	pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
3264 	req->req_id = MLAN_IOCTL_PM_CFG;
3265 	psleep_params = (pmlan_ds_sleep_params)&pm->param.sleep_params;
3266 
3267 	if (data_length == 0) {
3268 		req->action = MLAN_ACT_GET;
3269 	} else if (data_length == 6) {
3270 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
3271 			/* copy_from_user failed  */
3272 			PRINTM(MERROR, "S_PARAMS: copy from user failed\n");
3273 			LEAVE();
3274 			return -EINVAL;
3275 		}
3276 #define MIN_VAL 0x0000
3277 #define MAX_VAL 0xFFFF
3278 		for (i = 0; i < 6; i++) {
3279 			if ((i == 3) || (i == 4)) {
3280 				/* These two cases are handled below the loop */
3281 				continue;
3282 			}
3283 			if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
3284 				PRINTM(MERROR, "Invalid %s (0-65535)!\n",
3285 				       err_str[i]);
3286 				ret = -EINVAL;
3287 				goto done;
3288 			}
3289 		}
3290 		if (data[3] < 0 || data[3] > 2) {
3291 			PRINTM(MERROR,
3292 			       "Invalid control periodic calibration (0-2)!\n");
3293 			ret = -EINVAL;
3294 			goto done;
3295 		}
3296 		if (data[4] < 0 || data[4] > 2) {
3297 			PRINTM(MERROR,
3298 			       "Invalid control of external sleep clock (0-2)!\n");
3299 			ret = -EINVAL;
3300 			goto done;
3301 		}
3302 		req->action = MLAN_ACT_SET;
3303 		psleep_params->error = data[0];
3304 		psleep_params->offset = data[1];
3305 		psleep_params->stable_time = data[2];
3306 		psleep_params->cal_control = data[3];
3307 		psleep_params->ext_sleep_clk = data[4];
3308 		psleep_params->reserved = data[5];
3309 	} else {
3310 		ret = -EINVAL;
3311 		goto done;
3312 	}
3313 
3314 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3315 	if (status != MLAN_STATUS_SUCCESS) {
3316 		ret = -EFAULT;
3317 		goto done;
3318 	}
3319 
3320 	data[0] = psleep_params->error;
3321 	data[1] = psleep_params->offset;
3322 	data[2] = psleep_params->stable_time;
3323 	data[3] = psleep_params->cal_control;
3324 	data[4] = psleep_params->ext_sleep_clk;
3325 	data[5] = psleep_params->reserved;
3326 	wrq->u.data.length = 6;
3327 
3328 	if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) *
3329 			 wrq->u.data.length)) {
3330 		PRINTM(MERROR, "QCONFIG: copy to user failed\n");
3331 		ret = -EFAULT;
3332 		goto done;
3333 	}
3334 
3335 done:
3336 	if (status != MLAN_STATUS_PENDING)
3337 		kfree(req);
3338 	LEAVE();
3339 	return ret;
3340 }
3341 
3342 /**
3343  *  @brief Control Coalescing status Enable/Disable
3344  *
3345  *  @param priv     Pointer to the moal_private driver data struct
3346  *  @param wrq      Pointer to user data
3347  *
3348  *  @return         0 --success, otherwise fail
3349  */
3350 static int
woal_coalescing_status_ioctl(moal_private * priv,struct iwreq * wrq)3351 woal_coalescing_status_ioctl(moal_private *priv, struct iwreq *wrq)
3352 {
3353 	int ret = 0;
3354 	mlan_ds_misc_cfg *pcoal = NULL;
3355 	mlan_ioctl_req *req = NULL;
3356 	char buf[8];
3357 	struct iwreq *wreq = (struct iwreq *)wrq;
3358 	mlan_status status = MLAN_STATUS_SUCCESS;
3359 
3360 	ENTER();
3361 
3362 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3363 	if (req == NULL) {
3364 		ret = -ENOMEM;
3365 		goto done;
3366 	}
3367 	pcoal = (mlan_ds_misc_cfg *)req->pbuf;
3368 
3369 	memset(buf, 0, sizeof(buf));
3370 	if (!wrq->u.data.length) {
3371 		req->action = MLAN_ACT_GET;
3372 	} else {
3373 		req->action = MLAN_ACT_SET;
3374 		if (copy_from_user(buf, wrq->u.data.pointer,
3375 				   MIN(sizeof(buf) - 1, wreq->u.data.length))) {
3376 			PRINTM(MINFO, "Copy from user failed\n");
3377 			ret = -EFAULT;
3378 			goto done;
3379 		}
3380 		if (buf[0] == 1)
3381 			pcoal->param.coalescing_status =
3382 				MLAN_MISC_COALESCING_ENABLE;
3383 		else
3384 			pcoal->param.coalescing_status =
3385 				MLAN_MISC_COALESCING_DISABLE;
3386 	}
3387 
3388 	req->req_id = MLAN_IOCTL_MISC_CFG;
3389 	pcoal->sub_command = MLAN_OID_MISC_COALESCING_STATUS;
3390 
3391 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3392 	if (status != MLAN_STATUS_SUCCESS) {
3393 		ret = -EFAULT;
3394 		goto done;
3395 	}
3396 	buf[0] = ((mlan_ds_misc_cfg *)req->pbuf)->param.coalescing_status;
3397 
3398 	if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
3399 		ret = -EFAULT;
3400 		goto done;
3401 	}
3402 
3403 done:
3404 	if (status != MLAN_STATUS_PENDING)
3405 		kfree(req);
3406 	LEAVE();
3407 	return ret;
3408 }
3409 
3410 /**
3411  *  @brief Set/get user provisioned local power constraint
3412  *
3413  *  @param priv     A pointer to moal_private structure
3414  *  @param wrq      A pointer to iwreq structure
3415  *  @return         0 --success, otherwise fail
3416  */
3417 static int
woal_set_get_11h_local_pwr_constraint(moal_private * priv,struct iwreq * wrq)3418 woal_set_get_11h_local_pwr_constraint(moal_private *priv, struct iwreq *wrq)
3419 {
3420 	int ret = 0, data = 0;
3421 	mlan_ioctl_req *req = NULL;
3422 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
3423 	mlan_status status = MLAN_STATUS_SUCCESS;
3424 
3425 	ENTER();
3426 
3427 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
3428 	if (req == NULL) {
3429 		ret = -ENOMEM;
3430 		goto done;
3431 	}
3432 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
3433 	if (wrq->u.data.length) {
3434 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
3435 			PRINTM(MINFO, "Copy from user failed\n");
3436 			ret = -EFAULT;
3437 			goto done;
3438 		}
3439 		ds_11hcfg->param.usr_local_power_constraint = (t_s8)data;
3440 		req->action = MLAN_ACT_SET;
3441 	} else
3442 		req->action = MLAN_ACT_GET;
3443 
3444 	ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
3445 	req->req_id = MLAN_IOCTL_11H_CFG;
3446 
3447 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3448 	if (status != MLAN_STATUS_SUCCESS) {
3449 		ret = -EFAULT;
3450 		goto done;
3451 	}
3452 
3453 	/* Copy response to user */
3454 	if (req->action == MLAN_ACT_GET) {
3455 		data = (int)ds_11hcfg->param.usr_local_power_constraint;
3456 		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
3457 			PRINTM(MINFO, "Copy to user failed\n");
3458 			ret = -EFAULT;
3459 			goto done;
3460 		}
3461 		wrq->u.data.length = 1;
3462 	}
3463 
3464 done:
3465 	if (status != MLAN_STATUS_PENDING)
3466 		kfree(req);
3467 	LEAVE();
3468 	return ret;
3469 }
3470 
3471 /**
3472  *  @brief Set/get MAC control configuration
3473  *
3474  *  @param priv     A pointer to moal_private structure
3475  *  @param wrq      A pointer to iwreq structure
3476  *  @return         0 --success, otherwise fail
3477  */
3478 static int
woal_mac_control_ioctl(moal_private * priv,struct iwreq * wrq)3479 woal_mac_control_ioctl(moal_private *priv, struct iwreq *wrq)
3480 {
3481 	int ret = 0, data = 0;
3482 	mlan_ioctl_req *req = NULL;
3483 	mlan_ds_misc_cfg *cfg = NULL;
3484 	mlan_status status = MLAN_STATUS_SUCCESS;
3485 
3486 	ENTER();
3487 
3488 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3489 	if (req == NULL) {
3490 		ret = -ENOMEM;
3491 		goto done;
3492 	}
3493 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
3494 	if (wrq->u.data.length) {
3495 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
3496 			PRINTM(MINFO, "Copy from user failed\n");
3497 			ret = -EFAULT;
3498 			goto done;
3499 		}
3500 		/* Validation will be done later */
3501 		cfg->param.mac_ctrl = data;
3502 		req->action = MLAN_ACT_SET;
3503 	} else
3504 		req->action = MLAN_ACT_GET;
3505 
3506 	cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
3507 	req->req_id = MLAN_IOCTL_MISC_CFG;
3508 
3509 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3510 	if (status != MLAN_STATUS_SUCCESS) {
3511 		ret = -EFAULT;
3512 		goto done;
3513 	}
3514 
3515 	/* Copy response to user */
3516 	data = (int)cfg->param.mac_ctrl;
3517 	if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
3518 		PRINTM(MINFO, "Copy to user failed\n");
3519 		ret = -EFAULT;
3520 		goto done;
3521 	}
3522 	wrq->u.data.length = 1;
3523 
3524 done:
3525 	if (status != MLAN_STATUS_PENDING)
3526 		kfree(req);
3527 	LEAVE();
3528 	return ret;
3529 }
3530 
3531 /**
3532  *  @brief Get thermal reading
3533  *
3534  *  @param priv     A pointer to moal_private structure
3535  *  @param wrq      A pointer to iwreq structure
3536  *  @return         0 --success, otherwise fail
3537  */
3538 static int
woal_thermal_ioctl(moal_private * priv,struct iwreq * wrq)3539 woal_thermal_ioctl(moal_private *priv, struct iwreq *wrq)
3540 {
3541 	int ret = 0, data = 0;
3542 	mlan_ioctl_req *req = NULL;
3543 	mlan_ds_misc_cfg *cfg = NULL;
3544 	mlan_status status = MLAN_STATUS_SUCCESS;
3545 
3546 	ENTER();
3547 
3548 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3549 	if (req == NULL) {
3550 		ret = -ENOMEM;
3551 		goto done;
3552 	}
3553 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
3554 	if (wrq->u.data.length) {
3555 		PRINTM(MERROR, "Set is not supported for this command\n");
3556 		ret = -EINVAL;
3557 		goto done;
3558 	}
3559 	req->action = MLAN_ACT_GET;
3560 
3561 	cfg->sub_command = MLAN_OID_MISC_THERMAL;
3562 	req->req_id = MLAN_IOCTL_MISC_CFG;
3563 
3564 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3565 	if (status != MLAN_STATUS_SUCCESS) {
3566 		ret = -EFAULT;
3567 		goto done;
3568 	}
3569 
3570 	/* Copy response to user */
3571 	data = (int)cfg->param.thermal;
3572 	if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
3573 		PRINTM(MINFO, "Copy to user failed\n");
3574 		ret = -EFAULT;
3575 		goto done;
3576 	}
3577 	wrq->u.data.length = 1;
3578 
3579 done:
3580 	if (status != MLAN_STATUS_PENDING)
3581 		kfree(req);
3582 	LEAVE();
3583 	return ret;
3584 }
3585 
3586 #if defined(REASSOCIATION)
3587 /**
3588  * @brief Set/Get reassociation settings
3589  *
3590  * @param priv     A pointer to moal_private structure
3591  * @param wrq      A pointer to iwreq structure
3592  *
3593  * @return         0 --success, otherwise fail
3594  */
3595 static int
woal_set_get_reassoc(moal_private * priv,struct iwreq * wrq)3596 woal_set_get_reassoc(moal_private *priv, struct iwreq *wrq)
3597 {
3598 	moal_handle *handle = priv->phandle;
3599 	int ret = 0;
3600 	int data = 0;
3601 
3602 	ENTER();
3603 
3604 	if (wrq->u.data.length) {
3605 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
3606 			PRINTM(MERROR, "Copy from user failed\n");
3607 			ret = -EFAULT;
3608 			goto done;
3609 		}
3610 		if (data == 0) {
3611 			handle->reassoc_on &= ~MBIT(priv->bss_index);
3612 			priv->reassoc_on = MFALSE;
3613 			priv->reassoc_required = MFALSE;
3614 			if (!handle->reassoc_on &&
3615 			    handle->is_reassoc_timer_set == MTRUE) {
3616 				woal_cancel_timer(&handle->reassoc_timer);
3617 				handle->is_reassoc_timer_set = MFALSE;
3618 			}
3619 		} else {
3620 			handle->reassoc_on |= MBIT(priv->bss_index);
3621 			priv->reassoc_on = MTRUE;
3622 		}
3623 	} else {
3624 		data = (int)(priv->reassoc_on);
3625 		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
3626 			ret = -EFAULT;
3627 			goto done;
3628 		}
3629 		wrq->u.data.length = 1;
3630 	}
3631 
3632 done:
3633 	LEAVE();
3634 	return ret;
3635 }
3636 #endif /* REASSOCIATION */
3637 
3638 /**
3639  *  @brief implement WMM enable command
3640  *
3641  *  @param priv     Pointer to the moal_private driver data struct
3642  *  @param wrq      Pointer to the iwreq structure
3643  *
3644  *  @return         0 --success, otherwise fail
3645  */
3646 static int
woal_wmm_enable_ioctl(moal_private * priv,struct iwreq * wrq)3647 woal_wmm_enable_ioctl(moal_private *priv, struct iwreq *wrq)
3648 {
3649 	int ret = 0;
3650 	mlan_ds_wmm_cfg *wmm = NULL;
3651 	mlan_ioctl_req *req = NULL;
3652 	int data = 0;
3653 	mlan_status status = MLAN_STATUS_SUCCESS;
3654 
3655 	ENTER();
3656 
3657 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
3658 	if (req == NULL) {
3659 		ret = -ENOMEM;
3660 		goto done;
3661 	}
3662 	wmm = (mlan_ds_wmm_cfg *)req->pbuf;
3663 	req->req_id = MLAN_IOCTL_WMM_CFG;
3664 	wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
3665 
3666 	if (wrq->u.data.length) {
3667 		/* Set WMM configuration */
3668 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
3669 			PRINTM(MERROR, "Copy from user failed\n");
3670 			ret = -EFAULT;
3671 			goto done;
3672 		}
3673 		if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
3674 			ret = -EINVAL;
3675 			goto done;
3676 		}
3677 		req->action = MLAN_ACT_SET;
3678 		if (data == CMD_DISABLED)
3679 			wmm->param.wmm_enable = MFALSE;
3680 		else
3681 			wmm->param.wmm_enable = MTRUE;
3682 	} else {
3683 		/* Get WMM status */
3684 		req->action = MLAN_ACT_GET;
3685 	}
3686 
3687 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3688 	if (status != MLAN_STATUS_SUCCESS) {
3689 		ret = -EFAULT;
3690 		goto done;
3691 	}
3692 
3693 	if (wrq->u.data.pointer) {
3694 		if (copy_to_user
3695 		    (wrq->u.data.pointer, &wmm->param.wmm_enable,
3696 		     sizeof(wmm->param.wmm_enable))) {
3697 			PRINTM(MERROR, "Copy to user failed\n");
3698 			ret = -EFAULT;
3699 			goto done;
3700 		}
3701 		wrq->u.data.length = 1;
3702 	}
3703 done:
3704 	if (status != MLAN_STATUS_PENDING)
3705 		kfree(req);
3706 	LEAVE();
3707 	return ret;
3708 }
3709 
3710 /**
3711  *  @brief Implement 802.11D enable command
3712  *
3713  *  @param priv     Pointer to the moal_private driver data struct
3714  *  @param wrq      Pointer to the iwreq structure
3715  *
3716  *  @return         0 --success, otherwise fail
3717  */
3718 static int
woal_11d_enable_ioctl(moal_private * priv,struct iwreq * wrq)3719 woal_11d_enable_ioctl(moal_private *priv, struct iwreq *wrq)
3720 {
3721 	int ret = 0;
3722 	mlan_ds_11d_cfg *pcfg_11d = NULL;
3723 	mlan_ioctl_req *req = NULL;
3724 	int data = 0;
3725 	mlan_status status = MLAN_STATUS_SUCCESS;
3726 
3727 	ENTER();
3728 
3729 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
3730 	if (req == NULL) {
3731 		ret = -ENOMEM;
3732 		goto done;
3733 	}
3734 
3735 	pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
3736 	req->req_id = MLAN_IOCTL_11D_CFG;
3737 	pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
3738 	if (wrq->u.data.length) {
3739 		/* Set 11D configuration */
3740 		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
3741 			PRINTM(MERROR, "Copy from user failed\n");
3742 			ret = -EFAULT;
3743 			goto done;
3744 		}
3745 		if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
3746 			ret = -EINVAL;
3747 			goto done;
3748 		}
3749 		if (data == CMD_DISABLED)
3750 			pcfg_11d->param.enable_11d = MFALSE;
3751 		else
3752 			pcfg_11d->param.enable_11d = MTRUE;
3753 		req->action = MLAN_ACT_SET;
3754 	} else {
3755 		req->action = MLAN_ACT_GET;
3756 	}
3757 
3758 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3759 	if (status != MLAN_STATUS_SUCCESS) {
3760 		ret = -EFAULT;
3761 		goto done;
3762 	}
3763 
3764 	if (wrq->u.data.pointer) {
3765 		if (copy_to_user
3766 		    (wrq->u.data.pointer, &pcfg_11d->param.enable_11d,
3767 		     sizeof(pcfg_11d->param.enable_11d))) {
3768 			PRINTM(MERROR, "Copy to user failed\n");
3769 			ret = -EFAULT;
3770 			goto done;
3771 		}
3772 		wrq->u.data.length = 1;
3773 	}
3774 done:
3775 	if (status != MLAN_STATUS_PENDING)
3776 		kfree(req);
3777 	LEAVE();
3778 	return ret;
3779 }
3780 
3781 /**
3782  *  @brief Implement 802.11D clear chan table command
3783  *
3784  *  @param priv     Pointer to the moal_private driver data struct
3785  *  @param wrq      Pointer to the iwreq structure
3786  *
3787  *  @return         0 --success, otherwise fail
3788  */
3789 static int
woal_11d_clr_chan_table(moal_private * priv,struct iwreq * wrq)3790 woal_11d_clr_chan_table(moal_private *priv, struct iwreq *wrq)
3791 {
3792 	int ret = 0;
3793 	mlan_ds_11d_cfg *pcfg_11d = NULL;
3794 	mlan_ioctl_req *req = NULL;
3795 	mlan_status status = MLAN_STATUS_SUCCESS;
3796 
3797 	ENTER();
3798 
3799 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
3800 	if (req == NULL) {
3801 		ret = -ENOMEM;
3802 		goto done;
3803 	}
3804 
3805 	pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
3806 	req->req_id = MLAN_IOCTL_11D_CFG;
3807 	pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
3808 	req->action = MLAN_ACT_SET;
3809 
3810 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3811 	if (status != MLAN_STATUS_SUCCESS) {
3812 		ret = -EFAULT;
3813 		goto done;
3814 	}
3815 
3816 done:
3817 	if (status != MLAN_STATUS_PENDING)
3818 		kfree(req);
3819 	LEAVE();
3820 	return ret;
3821 }
3822 
3823 /**
3824  *  @brief Control WPS Session Enable/Disable
3825  *
3826  *  @param priv     Pointer to the moal_private driver data struct
3827  *  @param wrq      Pointer to the iwreq structure
3828  *
3829  *  @return         0 --success, otherwise fail
3830  */
3831 static int
woal_wps_cfg_ioctl(moal_private * priv,struct iwreq * wrq)3832 woal_wps_cfg_ioctl(moal_private *priv, struct iwreq *wrq)
3833 {
3834 	int ret = 0;
3835 	mlan_ds_wps_cfg *pwps = NULL;
3836 	mlan_ioctl_req *req = NULL;
3837 	char buf[8];
3838 	struct iwreq *wreq = (struct iwreq *)wrq;
3839 	mlan_status status = MLAN_STATUS_SUCCESS;
3840 
3841 	ENTER();
3842 
3843 	PRINTM(MINFO, "WOAL_WPS_SESSION\n");
3844 
3845 	memset(buf, 0, sizeof(buf));
3846 	if (copy_from_user(buf, wreq->u.data.pointer,
3847 			   MIN(sizeof(buf) - 1, wreq->u.data.length))) {
3848 		PRINTM(MERROR, "Copy from user failed\n");
3849 		ret = -EFAULT;
3850 		goto done;
3851 	}
3852 
3853 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
3854 	if (req == NULL) {
3855 		ret = -ENOMEM;
3856 		goto done;
3857 	}
3858 
3859 	pwps = (mlan_ds_wps_cfg *)req->pbuf;
3860 	req->req_id = MLAN_IOCTL_WPS_CFG;
3861 	req->action = MLAN_ACT_SET;
3862 	pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
3863 	if (buf[0] == 1)
3864 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
3865 	else
3866 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
3867 
3868 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3869 	if (status != MLAN_STATUS_SUCCESS) {
3870 		ret = -EFAULT;
3871 		goto done;
3872 	}
3873 
3874 done:
3875 	if (status != MLAN_STATUS_PENDING)
3876 		kfree(req);
3877 	LEAVE();
3878 	return ret;
3879 }
3880 
3881 /**
3882  *  @brief Set WPA passphrase and SSID
3883  *
3884  *  @param priv     A pointer to moal_private structure
3885  *  @param wrq      Pointer to the iwreq structure
3886  *
3887  *  @return         0 --success, otherwise fail
3888  */
3889 static int
woal_passphrase(moal_private * priv,struct iwreq * wrq)3890 woal_passphrase(moal_private *priv, struct iwreq *wrq)
3891 {
3892 	t_u16 len = 0;
3893 	char buf[256];
3894 	char *begin = NULL, *end = NULL, *opt = NULL;
3895 	int ret = 0, action = -1, i;
3896 	mlan_ds_sec_cfg *sec = NULL;
3897 	mlan_ioctl_req *req = NULL;
3898 	t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
3899 	t_u8 *mac = NULL;
3900 	int data_length = wrq->u.data.length, copy_len;
3901 	mlan_status status = MLAN_STATUS_SUCCESS;
3902 
3903 	ENTER();
3904 
3905 	if (!data_length || data_length >= sizeof(buf)) {
3906 		PRINTM(MERROR,
3907 		       "Argument missing or too long for setpassphrase\n");
3908 		ret = -EINVAL;
3909 		goto done;
3910 	}
3911 	memset(buf, 0, sizeof(buf));
3912 	copy_len = data_length;
3913 
3914 	if (copy_from_user(buf, wrq->u.data.pointer, copy_len)) {
3915 		PRINTM(MERROR, "Copy from user failed\n");
3916 		ret = -EFAULT;
3917 		goto done;
3918 	}
3919 
3920 	/* Parse the buf to get the cmd_action */
3921 	begin = buf;
3922 	end = woal_strsep(&begin, ';', '/');
3923 	if (!end) {
3924 		PRINTM(MERROR, "Invalid option\n");
3925 		ret = -EINVAL;
3926 		goto done;
3927 	}
3928 	action = woal_atox(end);
3929 	if (action < 0 || action > 2 || end[1] != '\0') {
3930 		PRINTM(MERROR, "Invalid action argument %s\n", end);
3931 		ret = -EINVAL;
3932 		goto done;
3933 	}
3934 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
3935 	if (req == NULL) {
3936 		ret = -ENOMEM;
3937 		goto done;
3938 	}
3939 	sec = (mlan_ds_sec_cfg *)req->pbuf;
3940 	sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
3941 	req->req_id = MLAN_IOCTL_SEC_CFG;
3942 	if (action == 0)
3943 		req->action = MLAN_ACT_GET;
3944 	else
3945 		req->action = MLAN_ACT_SET;
3946 	while (begin) {
3947 		end = woal_strsep(&begin, ';', '/');
3948 		opt = woal_strsep(&end, '=', '/');
3949 		if (!opt || !end || !end[0]) {
3950 			PRINTM(MERROR, "Invalid option\n");
3951 			ret = -EINVAL;
3952 			break;
3953 		} else if (!strnicmp(opt, "ssid", strlen(opt))) {
3954 			if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
3955 				PRINTM(MERROR,
3956 				       "SSID length exceeds max length\n");
3957 				ret = -EFAULT;
3958 				break;
3959 			}
3960 			sec->param.passphrase.ssid.ssid_len = strlen(end);
3961 			strncpy((char *)sec->param.passphrase.ssid.ssid, end,
3962 				MIN(strlen(end), MLAN_MAX_SSID_LENGTH));
3963 			PRINTM(MINFO, "ssid=%s, len=%d\n",
3964 			       sec->param.passphrase.ssid.ssid,
3965 			       (int)sec->param.passphrase.ssid.ssid_len);
3966 		} else if (!strnicmp(opt, "bssid", strlen(opt))) {
3967 			woal_mac2u8(sec->param.passphrase.bssid, end);
3968 		} else if (!strnicmp(opt, "psk", strlen(opt)) &&
3969 			   req->action == MLAN_ACT_SET) {
3970 			if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
3971 				PRINTM(MERROR, "Invalid PMK length\n");
3972 				ret = -EINVAL;
3973 				break;
3974 			}
3975 			woal_ascii2hex((t_u8 *)(sec->param.passphrase.psk.pmk.
3976 						pmk), end,
3977 				       MLAN_PMK_HEXSTR_LENGTH / 2);
3978 			sec->param.passphrase.psk_type = MLAN_PSK_PMK;
3979 		} else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
3980 			   req->action == MLAN_ACT_SET) {
3981 			if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
3982 			    strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
3983 				PRINTM(MERROR,
3984 				       "Invalid length for passphrase\n");
3985 				ret = -EINVAL;
3986 				break;
3987 			}
3988 			sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
3989 			memcpy(sec->param.passphrase.psk.passphrase.passphrase,
3990 			       end,
3991 			       sizeof(sec->param.passphrase.psk.passphrase.
3992 				      passphrase));
3993 			sec->param.passphrase.psk.passphrase.passphrase_len =
3994 				strlen(end);
3995 			PRINTM(MINFO, "passphrase=%s, len=%d\n",
3996 			       sec->param.passphrase.psk.passphrase.passphrase,
3997 			       (int)sec->param.passphrase.psk.passphrase.
3998 			       passphrase_len);
3999 		} else {
4000 			PRINTM(MERROR, "Invalid option %s\n", opt);
4001 			ret = -EINVAL;
4002 			break;
4003 		}
4004 	}
4005 	if (ret)
4006 		goto done;
4007 
4008 	if (action == 2)
4009 		sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
4010 	else if (action == 0)
4011 		sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
4012 
4013 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4014 	if (status != MLAN_STATUS_SUCCESS) {
4015 		ret = -EFAULT;
4016 		goto done;
4017 	}
4018 	if (action == 0) {
4019 		memset(buf, 0, sizeof(buf));
4020 		if (sec->param.passphrase.ssid.ssid_len) {
4021 			len += sprintf(buf + len, "ssid:");
4022 			memcpy(buf + len, sec->param.passphrase.ssid.ssid,
4023 			       sec->param.passphrase.ssid.ssid_len);
4024 			len += sec->param.passphrase.ssid.ssid_len;
4025 			len += sprintf(buf + len, " ");
4026 		}
4027 		if (memcmp
4028 		    (&sec->param.passphrase.bssid, zero_mac,
4029 		     sizeof(zero_mac))) {
4030 			mac = (t_u8 *)&sec->param.passphrase.bssid;
4031 			len += sprintf(buf + len, "bssid:");
4032 			for (i = 0; i < ETH_ALEN - 1; ++i)
4033 				len += sprintf(buf + len, "%02x:", mac[i]);
4034 			len += sprintf(buf + len, "%02x ", mac[i]);
4035 		}
4036 		if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
4037 			len += sprintf(buf + len, "psk:");
4038 			for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
4039 				len += sprintf(buf + len, "%02x",
4040 					       sec->param.passphrase.psk.pmk.
4041 					       pmk[i]);
4042 			len += sprintf(buf + len, "\n");
4043 		}
4044 		if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
4045 			len += sprintf(buf + len, "passphrase:%s\n",
4046 				       sec->param.passphrase.psk.passphrase.
4047 				       passphrase);
4048 		}
4049 		if (wrq->u.data.pointer) {
4050 			if (copy_to_user
4051 			    (wrq->u.data.pointer, buf, MIN(len, sizeof(buf)))) {
4052 				PRINTM(MERROR, "Copy to user failed, len %d\n",
4053 				       len);
4054 				ret = -EFAULT;
4055 				goto done;
4056 			}
4057 			wrq->u.data.length = len;
4058 		}
4059 
4060 	}
4061 done:
4062 	if (status != MLAN_STATUS_PENDING)
4063 		kfree(req);
4064 	LEAVE();
4065 	return ret;
4066 }
4067 
4068 /**
4069  *  @brief Get esupp mode
4070  *
4071  *  @param priv     A pointer to moal_private structure
4072  *  @param wrq      A pointer to iwreq structure
4073  *
4074  *  @return         0 --success, otherwise fail
4075  */
4076 static int
woal_get_esupp_mode(moal_private * priv,struct iwreq * wrq)4077 woal_get_esupp_mode(moal_private *priv, struct iwreq *wrq)
4078 {
4079 	int ret = 0;
4080 	mlan_ds_sec_cfg *sec = NULL;
4081 	mlan_ioctl_req *req = NULL;
4082 	mlan_status status = MLAN_STATUS_SUCCESS;
4083 
4084 	ENTER();
4085 
4086 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
4087 	if (req == NULL) {
4088 		ret = -ENOMEM;
4089 		goto done;
4090 	}
4091 	sec = (mlan_ds_sec_cfg *)req->pbuf;
4092 	sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
4093 	req->req_id = MLAN_IOCTL_SEC_CFG;
4094 	req->action = MLAN_ACT_GET;
4095 
4096 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4097 	if (status != MLAN_STATUS_SUCCESS) {
4098 		ret = -EFAULT;
4099 		goto done;
4100 	}
4101 
4102 	if (copy_to_user
4103 	    (wrq->u.data.pointer, (t_u8 *)&sec->param.esupp_mode,
4104 	     sizeof(int) * 3)) {
4105 		ret = -EFAULT;
4106 		goto done;
4107 	}
4108 	wrq->u.data.length = 3;
4109 done:
4110 	if (status != MLAN_STATUS_PENDING)
4111 		kfree(req);
4112 	LEAVE();
4113 	return ret;
4114 }
4115 
4116 /** AES key length */
4117 #define AES_KEY_LEN 16
4118 /**
4119  *  @brief Adhoc AES control
4120  *
4121  *  @param priv     A pointer to moal_private structure
4122  *  @param wrq      A pointer to the iwreq structure
4123  *
4124  *  @return         0 --success, otherwise fail
4125  */
4126 static int
woal_adhoc_aes_ioctl(moal_private * priv,struct iwreq * wrq)4127 woal_adhoc_aes_ioctl(moal_private *priv, struct iwreq *wrq)
4128 {
4129 	static char buf[256];
4130 	int ret = 0, action = -1;
4131 	unsigned int i;
4132 	t_u8 key_ascii[32];
4133 	t_u8 key_hex[16];
4134 	t_u8 *tmp = NULL;
4135 	mlan_bss_info bss_info;
4136 	mlan_ds_sec_cfg *sec = NULL;
4137 	mlan_ioctl_req *req = NULL;
4138 	t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
4139 	int data_length = wrq->u.data.length, copy_len;
4140 	mlan_status status = MLAN_STATUS_SUCCESS;
4141 	ENTER();
4142 
4143 	memset(key_ascii, 0x00, sizeof(key_ascii));
4144 	memset(key_hex, 0x00, sizeof(key_hex));
4145 	memset(buf, 0x00, sizeof(buf));
4146 
4147 	/* Get current BSS information */
4148 	memset(&bss_info, 0, sizeof(bss_info));
4149 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
4150 	if (bss_info.bss_mode != MLAN_BSS_MODE_IBSS ||
4151 	    bss_info.media_connected == MTRUE) {
4152 		PRINTM(MERROR, "STA is connected or not in IBSS mode.\n");
4153 		ret = -EOPNOTSUPP;
4154 		goto done;
4155 	}
4156 
4157 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
4158 	if (req == NULL) {
4159 		ret = -ENOMEM;
4160 		goto done;
4161 	}
4162 	copy_len = data_length;
4163 
4164 	if (data_length > 0) {
4165 		if (data_length >= sizeof(buf)) {
4166 			PRINTM(MERROR, "Too many arguments\n");
4167 			ret = -EINVAL;
4168 			goto done;
4169 		}
4170 		if (copy_from_user(buf, wrq->u.data.pointer, copy_len)) {
4171 			PRINTM(MERROR, "Copy from user failed\n");
4172 			ret = -EFAULT;
4173 			goto done;
4174 		}
4175 
4176 		if (data_length == 1) {
4177 			/* Get Adhoc AES Key */
4178 			req->req_id = MLAN_IOCTL_SEC_CFG;
4179 			req->action = MLAN_ACT_GET;
4180 			sec = (mlan_ds_sec_cfg *)req->pbuf;
4181 			sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
4182 			sec->param.encrypt_key.key_len = AES_KEY_LEN;
4183 			sec->param.encrypt_key.key_index =
4184 				MLAN_KEY_INDEX_UNICAST;
4185 			status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4186 			if (status != MLAN_STATUS_SUCCESS) {
4187 				ret = -EFAULT;
4188 				goto done;
4189 			}
4190 
4191 			memcpy(key_hex, sec->param.encrypt_key.key_material,
4192 			       sizeof(key_hex));
4193 			HEXDUMP("Adhoc AES Key (HEX)", key_hex,
4194 				sizeof(key_hex));
4195 
4196 			wrq->u.data.length = sizeof(key_ascii) + 1;
4197 
4198 			tmp = key_ascii;
4199 			for (i = 0; i < sizeof(key_hex); i++)
4200 				tmp += sprintf((char *)tmp, "%02x", key_hex[i]);
4201 		} else if (data_length >= 2) {
4202 			/* Parse the buf to get the cmd_action */
4203 			action = woal_atox(buf);
4204 			if (action < 1 || action > 2) {
4205 				PRINTM(MERROR, "Invalid action argument %d\n",
4206 				       action);
4207 				ret = -EINVAL;
4208 				goto done;
4209 			}
4210 
4211 			req->req_id = MLAN_IOCTL_SEC_CFG;
4212 			req->action = MLAN_ACT_SET;
4213 			sec = (mlan_ds_sec_cfg *)req->pbuf;
4214 			sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
4215 
4216 			if (action == 1) {
4217 				/* Set Adhoc AES Key  */
4218 				memcpy(key_ascii, &buf[2], sizeof(key_ascii));
4219 				woal_ascii2hex(key_hex, (char *)key_ascii,
4220 					       sizeof(key_hex));
4221 				HEXDUMP("Adhoc AES Key (HEX)", key_hex,
4222 					sizeof(key_hex));
4223 
4224 				sec->param.encrypt_key.key_len = AES_KEY_LEN;
4225 				sec->param.encrypt_key.key_index =
4226 					MLAN_KEY_INDEX_UNICAST;
4227 				sec->param.encrypt_key.key_flags =
4228 					KEY_FLAG_SET_TX_KEY |
4229 					KEY_FLAG_GROUP_KEY;
4230 				memcpy(sec->param.encrypt_key.mac_addr,
4231 				       (u8 *)bcast_addr, ETH_ALEN);
4232 				memcpy(sec->param.encrypt_key.key_material,
4233 				       key_hex, sec->param.encrypt_key.key_len);
4234 
4235 				status = woal_request_ioctl(priv, req,
4236 							    MOAL_IOCTL_WAIT);
4237 				if (status != MLAN_STATUS_SUCCESS) {
4238 					ret = -EFAULT;
4239 					goto done;
4240 				}
4241 			} else {
4242 				/* Clear Adhoc AES Key */
4243 				sec->param.encrypt_key.key_len = AES_KEY_LEN;
4244 				sec->param.encrypt_key.key_index =
4245 					MLAN_KEY_INDEX_UNICAST;
4246 				sec->param.encrypt_key.key_flags =
4247 					KEY_FLAG_REMOVE_KEY;
4248 				memcpy(sec->param.encrypt_key.mac_addr,
4249 				       (u8 *)bcast_addr, ETH_ALEN);
4250 				memset(sec->param.encrypt_key.key_material, 0,
4251 				       sizeof(sec->param.encrypt_key.
4252 					      key_material));
4253 
4254 				status = woal_request_ioctl(priv, req,
4255 							    MOAL_IOCTL_WAIT);
4256 				if (status != MLAN_STATUS_SUCCESS) {
4257 					ret = -EFAULT;
4258 					goto done;
4259 				}
4260 			}
4261 		}
4262 
4263 		HEXDUMP("Adhoc AES Key (ASCII)", key_ascii, sizeof(key_ascii));
4264 		wrq->u.data.length = sizeof(key_ascii);
4265 		if (wrq->u.data.pointer) {
4266 			if (copy_to_user(wrq->u.data.pointer, &key_ascii,
4267 					 sizeof(key_ascii))) {
4268 				PRINTM(MERROR, "copy_to_user failed\n");
4269 				ret = -EFAULT;
4270 				goto done;
4271 			}
4272 		}
4273 	}
4274 
4275 done:
4276 	if (status != MLAN_STATUS_PENDING)
4277 		kfree(req);
4278 	LEAVE();
4279 	return ret;
4280 }
4281 
4282 /**
4283  *  @brief arpfilter ioctl function
4284  *
4285  *  @param priv     A pointer to moal_private structure
4286  *  @param wrq      A pointer to iwreq structure
4287  *  @return         0 --success, otherwise fail
4288  */
4289 static int
woal_arp_filter(moal_private * priv,struct iwreq * wrq)4290 woal_arp_filter(moal_private *priv, struct iwreq *wrq)
4291 {
4292 	int ret = 0;
4293 	mlan_ds_misc_cfg *misc = NULL;
4294 	mlan_ioctl_req *req = NULL;
4295 	int data_length = wrq->u.data.length, copy_len;
4296 	mlan_status status = MLAN_STATUS_SUCCESS;
4297 
4298 	ENTER();
4299 
4300 	copy_len =
4301 		MIN(sizeof(misc->param.gen_ie.ie_data),
4302 		    sizeof(int) * data_length);
4303 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
4304 	if (req == NULL) {
4305 		ret = -ENOMEM;
4306 		goto done;
4307 	}
4308 	misc = (mlan_ds_misc_cfg *)req->pbuf;
4309 	misc->sub_command = MLAN_OID_MISC_GEN_IE;
4310 	req->req_id = MLAN_IOCTL_MISC_CFG;
4311 	req->action = MLAN_ACT_SET;
4312 	misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER;
4313 	misc->param.gen_ie.len = data_length;
4314 
4315 	/* get the whole command from user */
4316 	if (copy_from_user
4317 	    (misc->param.gen_ie.ie_data, wrq->u.data.pointer, copy_len)) {
4318 		PRINTM(MERROR, "copy from user failed\n");
4319 		ret = -EFAULT;
4320 		goto done;
4321 	}
4322 
4323 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4324 	if (status != MLAN_STATUS_SUCCESS) {
4325 		ret = -EFAULT;
4326 		goto done;
4327 	}
4328 done:
4329 	if (status != MLAN_STATUS_PENDING)
4330 		kfree(req);
4331 	LEAVE();
4332 	return ret;
4333 }
4334 
4335 /**
4336  *  @brief Set/get IP address
4337  *
4338  *  @param priv         A pointer to moal_private structure
4339  *  @param wrq          A pointer to iwreq structure
4340  *  @return             0 --success, otherwise fail
4341  */
4342 static int
woal_set_get_ip_addr(moal_private * priv,struct iwreq * wrq)4343 woal_set_get_ip_addr(moal_private *priv, struct iwreq *wrq)
4344 {
4345 	char buf[IPADDR_MAX_BUF];
4346 	mlan_ioctl_req *ioctl_req = NULL;
4347 	mlan_ds_misc_cfg *misc = NULL;
4348 	int ret = 0, op_code = 0, data_length = wrq->u.data.length;
4349 	mlan_status status = MLAN_STATUS_SUCCESS;
4350 
4351 	ENTER();
4352 
4353 	memset(buf, 0, IPADDR_MAX_BUF);
4354 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
4355 	if (ioctl_req == NULL) {
4356 		ret = -ENOMEM;
4357 		goto done;
4358 	}
4359 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
4360 
4361 	if (data_length <= 1) {	/* GET */
4362 		ioctl_req->action = MLAN_ACT_GET;
4363 	} else {
4364 		if (copy_from_user(buf, wrq->u.data.pointer,
4365 				   MIN(IPADDR_MAX_BUF - 1, data_length))) {
4366 			PRINTM(MERROR, "Copy from user failed\n");
4367 			ret = -EFAULT;
4368 			goto done;
4369 		}
4370 		/* Make sure we have the operation argument */
4371 		if (data_length > 2 && buf[1] != ';') {
4372 			PRINTM(MERROR,
4373 			       "No operation argument. Separate with ';'\n");
4374 			ret = -EINVAL;
4375 			goto done;
4376 		} else {
4377 			buf[1] = '\0';
4378 		}
4379 		ioctl_req->action = MLAN_ACT_SET;
4380 		/* only one IP is supported in current firmware */
4381 		memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
4382 		in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
4383 			 misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
4384 		/* only one IP is supported in current firmware */
4385 		misc->param.ipaddr_cfg.ip_addr_num = 1;
4386 		misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
4387 	}
4388 	if (woal_atoi(&op_code, buf) != MLAN_STATUS_SUCCESS) {
4389 		ret = -EINVAL;
4390 		goto done;
4391 	}
4392 	misc->param.ipaddr_cfg.op_code = (t_u32)op_code;
4393 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
4394 	misc->sub_command = MLAN_OID_MISC_IP_ADDR;
4395 
4396 	/* Send ioctl to mlan */
4397 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
4398 	if (status != MLAN_STATUS_SUCCESS) {
4399 		ret = -EFAULT;
4400 		goto done;
4401 	}
4402 
4403 	if (ioctl_req->action == MLAN_ACT_GET) {
4404 		snprintf(buf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
4405 			 misc->param.ipaddr_cfg.op_code,
4406 			 misc->param.ipaddr_cfg.ip_addr[0][0],
4407 			 misc->param.ipaddr_cfg.ip_addr[0][1],
4408 			 misc->param.ipaddr_cfg.ip_addr[0][2],
4409 			 misc->param.ipaddr_cfg.ip_addr[0][3]);
4410 		wrq->u.data.length = IPADDR_MAX_BUF;
4411 		if (copy_to_user(wrq->u.data.pointer, buf, IPADDR_MAX_BUF)) {
4412 			PRINTM(MERROR, "Copy to user failed\n");
4413 			ret = -EFAULT;
4414 		}
4415 	}
4416 
4417 done:
4418 	if (status != MLAN_STATUS_PENDING)
4419 		kfree(ioctl_req);
4420 	LEAVE();
4421 	return ret;
4422 }
4423 
4424 /**
4425  *  @brief Set/Get Transmit beamforming capabilities
4426  *
4427  *  @param priv     A pointer to moal_private structure
4428  *  @param wrq      A pointer to iwreq structure
4429  *
4430  *  @return         0 -- success, otherwise fail
4431  */
4432 static int
woal_tx_bf_cap_ioctl(moal_private * priv,struct iwreq * wrq)4433 woal_tx_bf_cap_ioctl(moal_private *priv, struct iwreq *wrq)
4434 {
4435 	int ret = 0, data_length = wrq->u.data.length;
4436 	mlan_ioctl_req *req = NULL;
4437 	mlan_ds_11n_cfg *bf_cfg = NULL;
4438 	int bf_cap = 0;
4439 	mlan_status status = MLAN_STATUS_SUCCESS;
4440 
4441 	ENTER();
4442 
4443 	if (data_length > 1) {
4444 		PRINTM(MERROR, "Invalid no of arguments!\n");
4445 		ret = -EINVAL;
4446 		goto done;
4447 	}
4448 	/* Allocate an IOCTL request buffer */
4449 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
4450 	if (req == NULL) {
4451 		ret = -ENOMEM;
4452 		goto done;
4453 	}
4454 
4455 	/* Fill request buffer */
4456 	bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
4457 	req->req_id = MLAN_IOCTL_11N_CFG;
4458 	bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
4459 	req->action = MLAN_ACT_GET;
4460 	if (data_length) {	/* SET */
4461 		if (copy_from_user(&bf_cap, wrq->u.data.pointer, sizeof(int))) {
4462 			PRINTM(MERROR, "copy from user failed\n");
4463 			ret = -EFAULT;
4464 			goto done;
4465 		}
4466 		bf_cfg->param.tx_bf_cap = bf_cap;
4467 		req->action = MLAN_ACT_SET;
4468 	}
4469 
4470 	/* Send IOCTL request to MLAN */
4471 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4472 	if (status != MLAN_STATUS_SUCCESS) {
4473 		ret = -EFAULT;
4474 		goto done;
4475 	}
4476 
4477 	bf_cap = bf_cfg->param.tx_bf_cap;
4478 	if (copy_to_user(wrq->u.data.pointer, &bf_cap, sizeof(int))) {
4479 		ret = -EFAULT;
4480 		goto done;
4481 	}
4482 	wrq->u.data.length = 1;
4483 
4484 done:
4485 	if (status != MLAN_STATUS_PENDING)
4486 		kfree(req);
4487 	LEAVE();
4488 	return ret;
4489 }
4490 
4491 /* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
4492 #define MAX_IN_OUT_CHAR     256
4493 /** Tx BF Global conf argument index */
4494 #define BF_ENABLE_PARAM     1
4495 #define SOUND_ENABLE_PARAM  2
4496 #define FB_TYPE_PARAM       3
4497 #define SNR_THRESHOLD_PARAM 4
4498 #define SOUND_INTVL_PARAM   5
4499 #define BF_MODE_PARAM       6
4500 #define MAX_TX_BF_GLOBAL_ARGS   6
4501 #define BF_CFG_ACT_GET      0
4502 #define BF_CFG_ACT_SET      1
4503 
4504 /**
4505  *  @brief Set/Get Transmit beamforming configuration
4506  *
4507  *  @param priv     A pointer to moal_private structure
4508  *  @param wrq      A pointer to iwreq structure
4509  *
4510  *  @return         0 -- success, otherwise fail
4511  */
4512 static int
woal_tx_bf_cfg_ioctl(moal_private * priv,struct iwreq * wrq)4513 woal_tx_bf_cfg_ioctl(moal_private *priv, struct iwreq *wrq)
4514 {
4515 	int ret = 0, data_length = wrq->u.data.length;
4516 	int bf_action = 0, interval = 0;
4517 	int snr = 0, i, tmp_val;
4518 	t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
4519 	t_u8 *str, *token, *pos;
4520 	t_u16 action = 0;
4521 
4522 	mlan_ds_11n_tx_bf_cfg bf_cfg;
4523 	mlan_trigger_sound_args *bf_sound = NULL;
4524 	mlan_tx_bf_peer_args *tx_bf_peer = NULL;
4525 	mlan_snr_thr_args *bf_snr = NULL;
4526 	mlan_bf_periodicity_args *bf_periodicity = NULL;
4527 	mlan_bf_global_cfg_args *bf_global = NULL;
4528 
4529 	ENTER();
4530 
4531 	memset(&bf_cfg, 0, sizeof(bf_cfg));
4532 	/* Pointer to corresponding buffer */
4533 	bf_sound = bf_cfg.body.bf_sound;
4534 	tx_bf_peer = bf_cfg.body.tx_bf_peer;
4535 	bf_snr = bf_cfg.body.bf_snr;
4536 	bf_periodicity = bf_cfg.body.bf_periodicity;
4537 	bf_global = &bf_cfg.body.bf_global_cfg;
4538 
4539 	/* Total characters in buffer */
4540 	char_count = data_length - 1;
4541 	memset(buf, 0, sizeof(buf));
4542 	if (char_count) {
4543 		if (data_length > sizeof(buf)) {
4544 			PRINTM(MERROR, "Too many arguments\n");
4545 			ret = -EINVAL;
4546 			goto done;
4547 		}
4548 		if (copy_from_user(buf, wrq->u.data.pointer, data_length)) {
4549 			PRINTM(MERROR, "copy from user failed\n");
4550 			ret = -EFAULT;
4551 			goto done;
4552 		}
4553 
4554 		if (char_count > 1 && buf[1] != ';') {
4555 			PRINTM(MERROR,
4556 			       "No action argument. Separate with ';'\n");
4557 			ret = -EINVAL;
4558 			goto done;
4559 		}
4560 		/* Replace ';' with NULL in the string to separate args */
4561 		for (i = 0; i < char_count; i++) {
4562 			if (buf[i] == ';')
4563 				buf[i] = '\0';
4564 		}
4565 		/* The first byte represents the beamforming action */
4566 		if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
4567 			ret = -EINVAL;
4568 			goto done;
4569 		}
4570 		switch (bf_action) {
4571 		case BF_GLOBAL_CONFIGURATION:
4572 			if (char_count == 1) {
4573 				action = MLAN_ACT_GET;
4574 				bf_cfg.action = BF_CFG_ACT_GET;
4575 			} else {
4576 				action = MLAN_ACT_SET;
4577 				bf_cfg.action = BF_CFG_ACT_SET;
4578 				/* Eliminate action field */
4579 				token = &buf[2];
4580 				for (i = 1, str = &buf[2]; token != NULL; i++) {
4581 					token = strstr(str, " ");
4582 					pos = str;
4583 					if (token != NULL) {
4584 						*token = '\0';
4585 						str = token + 1;
4586 					}
4587 					woal_atoi(&tmp_val, pos);
4588 					switch (i) {
4589 					case BF_ENABLE_PARAM:
4590 						bf_global->bf_enbl =
4591 							(t_u8)tmp_val;
4592 						break;
4593 					case SOUND_ENABLE_PARAM:
4594 						bf_global->sounding_enbl =
4595 							(t_u8)tmp_val;
4596 						break;
4597 					case FB_TYPE_PARAM:
4598 						bf_global->fb_type =
4599 							(t_u8)tmp_val;
4600 						break;
4601 					case SNR_THRESHOLD_PARAM:
4602 						bf_global->snr_threshold =
4603 							(t_u8)tmp_val;
4604 						break;
4605 					case SOUND_INTVL_PARAM:
4606 						bf_global->sounding_interval =
4607 							(t_u16)tmp_val;
4608 						break;
4609 					case BF_MODE_PARAM:
4610 						bf_global->bf_mode =
4611 							(t_u8)tmp_val;
4612 						break;
4613 					default:
4614 						PRINTM(MERROR,
4615 						       "Invalid Argument\n");
4616 						ret = -EINVAL;
4617 						goto done;
4618 					}
4619 				}
4620 			}
4621 			break;
4622 		case TRIGGER_SOUNDING_FOR_PEER:
4623 			/*
4624 			 * First arg  = 2   BfAction
4625 			 * Second arg = 17  MAC "00:50:43:20:BF:64"
4626 			 */
4627 			if (char_count != 19) {
4628 				PRINTM(MERROR, "Invalid argument\n");
4629 				ret = -EINVAL;
4630 				goto done;
4631 			}
4632 			woal_mac2u8(bf_sound->peer_mac, &buf[2]);
4633 			action = MLAN_ACT_SET;
4634 			bf_cfg.action = BF_CFG_ACT_SET;
4635 			break;
4636 		case SET_GET_BF_PERIODICITY:
4637 			/*
4638 			 * First arg  = 2   BfAction
4639 			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
4640 			 * Third arg =  1  (min char)  TX BF interval
4641 			 *              10 (max char)  u32 maximum value 4294967295
4642 			 */
4643 			if (char_count < 19 || char_count > 30) {
4644 				PRINTM(MERROR, "Invalid argument\n");
4645 				ret = -EINVAL;
4646 				goto done;
4647 			}
4648 
4649 			woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
4650 			if (char_count == 19) {
4651 				action = MLAN_ACT_GET;
4652 				bf_cfg.action = BF_CFG_ACT_GET;
4653 			} else {
4654 				action = MLAN_ACT_SET;
4655 				bf_cfg.action = BF_CFG_ACT_SET;
4656 				if (woal_atoi(&interval, &buf[20]) !=
4657 				    MLAN_STATUS_SUCCESS) {
4658 					ret = -EINVAL;
4659 					goto done;
4660 				}
4661 				bf_periodicity->interval = interval;
4662 			}
4663 			break;
4664 		case TX_BF_FOR_PEER_ENBL:
4665 			/*
4666 			 * Handle only SET operation here
4667 			 * First arg  = 2   BfAction
4668 			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
4669 			 * Third arg  = 2   enable/disable bf
4670 			 * Fourth arg = 2   enable/disable sounding
4671 			 * Fifth arg  = 1   FB Type
4672 			 */
4673 			if (char_count != 25 && char_count != 1) {
4674 				PRINTM(MERROR, "Invalid argument\n");
4675 				ret = -EINVAL;
4676 				goto done;
4677 			}
4678 			if (char_count == 1) {
4679 				action = MLAN_ACT_GET;
4680 				bf_cfg.action = BF_CFG_ACT_GET;
4681 			} else {
4682 				woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
4683 				woal_atoi(&tmp_val, &buf[20]);
4684 				tx_bf_peer->bf_enbl = (t_u8)tmp_val;
4685 				woal_atoi(&tmp_val, &buf[22]);
4686 				tx_bf_peer->sounding_enbl = (t_u8)tmp_val;
4687 				woal_atoi(&tmp_val, &buf[24]);
4688 				tx_bf_peer->fb_type = (t_u8)tmp_val;
4689 				action = MLAN_ACT_SET;
4690 				bf_cfg.action = BF_CFG_ACT_SET;
4691 			}
4692 			break;
4693 		case SET_SNR_THR_PEER:
4694 			/*
4695 			 * First arg  = 2   BfAction
4696 			 * Second arg = 18  MAC "00:50:43:20:BF:64;"
4697 			 * Third arg  = 1/2 SNR u8 - can be 1/2 charerters
4698 			 */
4699 			if (char_count != 1 &&
4700 			    !(char_count == 21 || char_count == 22)) {
4701 				PRINTM(MERROR, "Invalid argument\n");
4702 				ret = -EINVAL;
4703 				goto done;
4704 			}
4705 			if (char_count == 1) {
4706 				action = MLAN_ACT_GET;
4707 				bf_cfg.action = BF_CFG_ACT_GET;
4708 			} else {
4709 				woal_mac2u8(bf_snr->peer_mac, &buf[2]);
4710 				if (woal_atoi(&snr, &buf[20]) !=
4711 				    MLAN_STATUS_SUCCESS) {
4712 					ret = -EINVAL;
4713 					goto done;
4714 				}
4715 				bf_snr->snr = snr;
4716 				action = MLAN_ACT_SET;
4717 				bf_cfg.action = BF_CFG_ACT_SET;
4718 			}
4719 			break;
4720 		default:
4721 			ret = -EINVAL;
4722 			goto done;
4723 		}
4724 
4725 		/* Save the value */
4726 		bf_cfg.bf_action = bf_action;
4727 		if (MLAN_STATUS_SUCCESS !=
4728 		    woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
4729 			ret = -EFAULT;
4730 			goto done;
4731 		}
4732 	} else {
4733 		ret = -EINVAL;
4734 		goto done;
4735 	}
4736 
4737 	if (action == MLAN_ACT_GET) {
4738 		data_length = 0;
4739 		memset(buf, 0, sizeof(buf));
4740 		switch (bf_action) {
4741 		case BF_GLOBAL_CONFIGURATION:
4742 			data_length +=
4743 				sprintf(buf + data_length, "%d ",
4744 					(int)bf_global->bf_enbl);
4745 			data_length +=
4746 				sprintf(buf + data_length, "%d ",
4747 					(int)bf_global->sounding_enbl);
4748 			data_length +=
4749 				sprintf(buf + data_length, "%d ",
4750 					(int)bf_global->fb_type);
4751 			data_length +=
4752 				sprintf(buf + data_length, "%d ",
4753 					(int)bf_global->snr_threshold);
4754 			data_length +=
4755 				sprintf(buf + data_length, "%d ",
4756 					(int)bf_global->sounding_interval);
4757 			data_length +=
4758 				sprintf(buf + data_length, "%d ",
4759 					(int)bf_global->bf_mode);
4760 			break;
4761 		case SET_GET_BF_PERIODICITY:
4762 			data_length += sprintf(buf + data_length,
4763 					       "%02x:%02x:%02x:%02x:%02x:%02x",
4764 					       bf_periodicity->peer_mac[0],
4765 					       bf_periodicity->peer_mac[1],
4766 					       bf_periodicity->peer_mac[2],
4767 					       bf_periodicity->peer_mac[3],
4768 					       bf_periodicity->peer_mac[4],
4769 					       bf_periodicity->peer_mac[5]);
4770 			data_length += sprintf(buf + data_length, "%c", ' ');
4771 			data_length +=
4772 				sprintf(buf + data_length, "%d",
4773 					bf_periodicity->interval);
4774 			break;
4775 		case TX_BF_FOR_PEER_ENBL:
4776 			for (i = 0; i < bf_cfg.no_of_peers; i++) {
4777 				data_length += sprintf(buf + data_length,
4778 						       "%02x:%02x:%02x:%02x:%02x:%02x",
4779 						       tx_bf_peer->peer_mac[0],
4780 						       tx_bf_peer->peer_mac[1],
4781 						       tx_bf_peer->peer_mac[2],
4782 						       tx_bf_peer->peer_mac[3],
4783 						       tx_bf_peer->peer_mac[4],
4784 						       tx_bf_peer->peer_mac[5]);
4785 				data_length +=
4786 					sprintf(buf + data_length, "%c", ' ');
4787 				data_length +=
4788 					sprintf(buf + data_length, "%d;",
4789 						tx_bf_peer->bf_enbl);
4790 				data_length +=
4791 					sprintf(buf + data_length, "%d;",
4792 						tx_bf_peer->sounding_enbl);
4793 				data_length +=
4794 					sprintf(buf + data_length, "%d ",
4795 						tx_bf_peer->fb_type);
4796 				tx_bf_peer++;
4797 			}
4798 			break;
4799 		case SET_SNR_THR_PEER:
4800 			for (i = 0; i < bf_cfg.no_of_peers; i++) {
4801 				data_length += sprintf(buf + data_length,
4802 						       "%02x:%02x:%02x:%02x:%02x:%02x",
4803 						       bf_snr->peer_mac[0],
4804 						       bf_snr->peer_mac[1],
4805 						       bf_snr->peer_mac[2],
4806 						       bf_snr->peer_mac[3],
4807 						       bf_snr->peer_mac[4],
4808 						       bf_snr->peer_mac[5]);
4809 				data_length +=
4810 					sprintf(buf + data_length, "%c", ';');
4811 				data_length +=
4812 					sprintf(buf + data_length, "%d",
4813 						bf_snr->snr);
4814 				data_length +=
4815 					sprintf(buf + data_length, "%c", ' ');
4816 				bf_snr++;
4817 			}
4818 			break;
4819 		}
4820 		buf[data_length] = '\0';
4821 	}
4822 
4823 	wrq->u.data.length = data_length;
4824 	if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
4825 		ret = -EFAULT;
4826 		goto done;
4827 	}
4828 
4829 done:
4830 	LEAVE();
4831 	return ret;
4832 }
4833 
4834 /**
4835  *  @brief Retrieve the scan response/beacon table
4836  *
4837  *  @param wrq          A pointer to iwreq structure
4838  *  @param scan_resp    A pointer to mlan_scan_resp structure
4839  *  @param scan_start   argument
4840  *
4841  *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
4842  */
4843 static int
moal_ret_get_scan_table_ioctl(struct iwreq * wrq,mlan_scan_resp * scan_resp,t_u32 scan_start)4844 moal_ret_get_scan_table_ioctl(struct iwreq *wrq,
4845 			      mlan_scan_resp *scan_resp, t_u32 scan_start)
4846 {
4847 	pBSSDescriptor_t pbss_desc, scan_table;
4848 	wlan_ioctl_get_scan_table_info *prsp_info;
4849 	int ret_code;
4850 	int ret_len;
4851 	int space_left;
4852 	t_u8 *pcurrent;
4853 	t_u8 *pbuffer_end;
4854 	t_u32 num_scans_done;
4855 
4856 	ENTER();
4857 
4858 	num_scans_done = 0;
4859 	ret_code = MLAN_STATUS_SUCCESS;
4860 
4861 	prsp_info = (wlan_ioctl_get_scan_table_info *)wrq->u.data.pointer;
4862 	pcurrent = (t_u8 *)prsp_info->scan_table_entry_buf;
4863 
4864 	pbuffer_end = wrq->u.data.pointer + wrq->u.data.length - 1;
4865 	space_left = pbuffer_end - pcurrent;
4866 	scan_table = (BSSDescriptor_t *)(scan_resp->pscan_table);
4867 
4868 	PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
4869 	PRINTM(MINFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
4870 
4871 	if (!scan_start) {
4872 		PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
4873 
4874 		/* Use to get current association saved descriptor */
4875 		pbss_desc = scan_table;
4876 
4877 		ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
4878 							 &pcurrent,
4879 							 &space_left);
4880 
4881 		if (ret_code == MLAN_STATUS_SUCCESS)
4882 			num_scans_done = 1;
4883 	} else {
4884 		scan_start--;
4885 
4886 		while (space_left
4887 		       && (scan_start + num_scans_done <
4888 			   scan_resp->num_in_scan_table)
4889 		       && (ret_code == MLAN_STATUS_SUCCESS)) {
4890 
4891 			pbss_desc =
4892 				(scan_table + (scan_start + num_scans_done));
4893 
4894 			PRINTM(MINFO,
4895 			       "GetScanTable: get current BSS Descriptor [%d]\n",
4896 			       scan_start + num_scans_done);
4897 
4898 			ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
4899 								 &pcurrent,
4900 								 &space_left);
4901 
4902 			if (ret_code == MLAN_STATUS_SUCCESS)
4903 				num_scans_done++;
4904 		}
4905 	}
4906 
4907 	prsp_info->scan_number = num_scans_done;
4908 	ret_len = pcurrent - (t_u8 *)wrq->u.data.pointer;
4909 
4910 	wrq->u.data.length = ret_len;
4911 
4912 	/* Return ret_code (EFAULT or E2BIG) in the case where no scan results were
4913 	 *   successfully encoded.
4914 	 */
4915 	LEAVE();
4916 	return num_scans_done ? MLAN_STATUS_SUCCESS : ret_code;
4917 }
4918 
4919 /**
4920  *  @brief Get scan table ioctl
4921  *
4922  *  @param priv     A pointer to moal_private structure
4923  *  @param wrq      A pointer to iwreq structure
4924  *
4925  *  @return         MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
4926  */
4927 static mlan_status
woal_get_scan_table_ioctl(moal_private * priv,struct iwreq * wrq)4928 woal_get_scan_table_ioctl(moal_private *priv, struct iwreq *wrq)
4929 {
4930 	int ret = 0;
4931 	mlan_ioctl_req *req = NULL;
4932 	mlan_ds_scan *scan = NULL;
4933 	int scan_start = 0;
4934 	mlan_status status = MLAN_STATUS_SUCCESS;
4935 
4936 	ENTER();
4937 
4938 	/* Allocate an IOCTL request buffer */
4939 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
4940 	if (req == NULL) {
4941 		ret = -ENOMEM;
4942 		goto done;
4943 	}
4944 
4945 	/* Fill request buffer */
4946 	scan = (mlan_ds_scan *)req->pbuf;
4947 	req->req_id = MLAN_IOCTL_SCAN;
4948 	req->action = MLAN_ACT_GET;
4949 
4950 	/* get the whole command from user */
4951 	if (copy_from_user
4952 	    (&scan_start, wrq->u.data.pointer, sizeof(scan_start))) {
4953 		PRINTM(MERROR, "copy from user failed\n");
4954 		ret = -EFAULT;
4955 		goto done;
4956 	}
4957 	if (scan_start > 0)
4958 		scan->sub_command = MLAN_OID_SCAN_NORMAL;
4959 	else
4960 		scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;
4961 	/* Send IOCTL request to MLAN */
4962 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4963 	if (status == MLAN_STATUS_SUCCESS) {
4964 		status = moal_ret_get_scan_table_ioctl(wrq,
4965 						       &scan->param.scan_resp,
4966 						       scan_start);
4967 	}
4968 done:
4969 	if (status != MLAN_STATUS_PENDING)
4970 		kfree(req);
4971 	LEAVE();
4972 	return status;
4973 }
4974 
4975 /**
4976  *  @brief Set user scan ext -- Async mode, without wait
4977  *
4978  *  @param priv     A pointer to moal_private structure
4979  *  @param wrq      A pointer to iwreq structure
4980  *
4981  *  @return         0 -- success, otherwise fail
4982  */
4983 static int
woal_set_user_scan_ext_ioctl(moal_private * priv,struct iwreq * wrq)4984 woal_set_user_scan_ext_ioctl(moal_private *priv, struct iwreq *wrq)
4985 {
4986 	int ret = 0;
4987 	wlan_user_scan_cfg scan_req;
4988 	ENTER();
4989 	memset(&scan_req, 0x00, sizeof(scan_req));
4990 	if (copy_from_user
4991 	    (&scan_req, wrq->u.data.pointer,
4992 	     MIN(wrq->u.data.length, sizeof(scan_req)))) {
4993 		PRINTM(MINFO, "Copy from user failed\n");
4994 		LEAVE();
4995 		return -EFAULT;
4996 	}
4997 	if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_req))
4998 		ret = -EFAULT;
4999 	LEAVE();
5000 	return ret;
5001 }
5002 
5003 /**
5004  *  @brief Set user scan
5005  *
5006  *  @param priv     A pointer to moal_private structure
5007  *  @param wrq      A pointer to iwreq structure
5008  *
5009  *  @return         MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
5010  */
5011 static mlan_status
woal_set_user_scan_ioctl(moal_private * priv,struct iwreq * wrq)5012 woal_set_user_scan_ioctl(moal_private *priv, struct iwreq *wrq)
5013 {
5014 	int ret = 0;
5015 	mlan_ioctl_req *req = NULL;
5016 	mlan_ds_scan *scan = NULL;
5017 	mlan_status status = MLAN_STATUS_SUCCESS;
5018 	union iwreq_data wrqu;
5019 	moal_handle *handle = priv->phandle;
5020 
5021 	ENTER();
5022 
5023 	if (handle->scan_pending_on_block == MTRUE) {
5024 		PRINTM(MINFO, "scan already in processing...\n");
5025 		LEAVE();
5026 		return ret;
5027 	}
5028 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
5029 		PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
5030 		LEAVE();
5031 		return MLAN_STATUS_FAILURE;
5032 	}
5033 	handle->scan_pending_on_block = MTRUE;
5034 	handle->scan_priv = priv;
5035 
5036 	/* Allocate an IOCTL request buffer */
5037 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
5038 					wrq->u.data.length);
5039 	if (req == NULL) {
5040 		ret = -ENOMEM;
5041 		goto done;
5042 	}
5043 
5044 	/* Fill request buffer */
5045 	scan = (mlan_ds_scan *)req->pbuf;
5046 	scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
5047 	req->req_id = MLAN_IOCTL_SCAN;
5048 	req->action = MLAN_ACT_SET;
5049 
5050 	if (copy_from_user(scan->param.user_scan.scan_cfg_buf,
5051 			   wrq->u.data.pointer, wrq->u.data.length)) {
5052 		PRINTM(MINFO, "Copy from user failed\n");
5053 		LEAVE();
5054 		return -EFAULT;
5055 	}
5056 
5057 	/* Send IOCTL request to MLAN */
5058 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5059 	if (status == MLAN_STATUS_SUCCESS) {
5060 		memset(&wrqu, 0, sizeof(union iwreq_data));
5061 		wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
5062 	}
5063 	handle->scan_pending_on_block = MFALSE;
5064 	handle->scan_priv = NULL;
5065 	MOAL_REL_SEMAPHORE(&handle->async_sem);
5066 
5067 done:
5068 	if (status != MLAN_STATUS_PENDING)
5069 		kfree(req);
5070 	LEAVE();
5071 	return status;
5072 }
5073 
5074 /**
5075  *  @brief Cmd52 read/write register
5076  *
5077  *  @param priv         A pointer to moal_private structure
5078  *  @param wrq          A pointer to iwreq structure
5079  *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
5080  */
5081 static int
woal_cmd52rdwr_ioctl(moal_private * priv,struct iwreq * wrq)5082 woal_cmd52rdwr_ioctl(moal_private *priv, struct iwreq *wrq)
5083 {
5084 	t_u8 rw = 0, func, data = 0;
5085 	int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
5086 	int data_length = wrq->u.data.length;
5087 
5088 	ENTER();
5089 
5090 	if (data_length < 2 || data_length > 3) {
5091 		PRINTM(MERROR, "Invalid number of arguments\n");
5092 		ret = -EINVAL;
5093 		goto done;
5094 	}
5095 
5096 	if (copy_from_user(buf, wrq->u.data.pointer, sizeof(int) * data_length)) {
5097 		PRINTM(MERROR, "Copy from user failed\n");
5098 		ret = -EFAULT;
5099 		goto done;
5100 	}
5101 
5102 	func = (t_u8)buf[0];
5103 	if (func > 7) {
5104 		PRINTM(MERROR, "Invalid function number!\n");
5105 		ret = -EINVAL;
5106 		goto done;
5107 	}
5108 	reg = (t_u32)buf[1];
5109 	if (data_length == 2) {
5110 		rw = 0;		/* CMD52 read */
5111 		PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
5112 	}
5113 	if (data_length == 3) {
5114 		rw = 1;		/* CMD52 write */
5115 		data = (t_u8)buf[2];
5116 		PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
5117 		       func, reg, data);
5118 	}
5119 
5120 	if (!rw) {
5121 		sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)->
5122 				func);
5123 		if (func)
5124 			data = sdio_readb(((struct sdio_mmc_card *)priv->
5125 					   phandle->card)->func, reg, &ret);
5126 		else
5127 			data = sdio_f0_readb(((struct sdio_mmc_card *)priv->
5128 					      phandle->card)->func, reg, &ret);
5129 		sdio_release_host(((struct sdio_mmc_card *)priv->phandle->
5130 				   card)->func);
5131 		if (ret) {
5132 			PRINTM(MERROR,
5133 			       "sdio_readb: reading register 0x%X failed\n",
5134 			       reg);
5135 			goto done;
5136 		}
5137 	} else {
5138 		sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)->
5139 				func);
5140 		if (func)
5141 			sdio_writeb(((struct sdio_mmc_card *)priv->phandle->
5142 				     card)->func, data, reg, &ret);
5143 		else
5144 			sdio_f0_writeb(((struct sdio_mmc_card *)priv->phandle->
5145 					card)->func, data, reg, &ret);
5146 		sdio_release_host(((struct sdio_mmc_card *)priv->phandle->
5147 				   card)->func);
5148 		if (ret) {
5149 			PRINTM(MERROR,
5150 			       "sdio_writeb: writing register 0x%X failed\n",
5151 			       reg);
5152 			goto done;
5153 		}
5154 	}
5155 
5156 	buf[0] = data;
5157 	wrq->u.data.length = 1;
5158 	if (copy_to_user(wrq->u.data.pointer, buf, sizeof(int))) {
5159 		PRINTM(MERROR, "Copy to user failed\n");
5160 		ret = -EFAULT;
5161 		goto done;
5162 	}
5163 
5164 done:
5165 	LEAVE();
5166 	return ret;
5167 }
5168 
5169 /**
5170  *  @brief Cmd53 read/write register
5171  *
5172  *  @param priv         A pointer to moal_private structure
5173  *  @param wrq          A pointer to iwreq structure
5174  *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
5175  */
5176 static int
woal_cmd53rdwr_ioctl(moal_private * priv,struct iwreq * wrq)5177 woal_cmd53rdwr_ioctl(moal_private *priv, struct iwreq *wrq)
5178 {
5179 	t_u8 *buf = NULL;
5180 	t_u8 rw, func, mode;
5181 	t_u16 blklen = 0, blknum = 0;
5182 	int reg = 0, pattern_len = 0, pos = 0, ret = MLAN_STATUS_SUCCESS;
5183 	t_u32 total_len = 0;
5184 	t_u8 *data = NULL;
5185 
5186 	ENTER();
5187 
5188 	buf = kmalloc(WOAL_2K_BYTES, GFP_KERNEL);
5189 	if (!buf) {
5190 		PRINTM(MERROR, "Cannot allocate buffer for command!\n");
5191 		ret = -EFAULT;
5192 		goto done;
5193 	}
5194 	data = kmalloc(WOAL_2K_BYTES, GFP_KERNEL);
5195 	if (!data) {
5196 		PRINTM(MERROR, "Cannot allocate buffer for command!\n");
5197 		ret = -EFAULT;
5198 		goto done;
5199 	}
5200 	if (wrq->u.data.length > WOAL_2K_BYTES) {
5201 		PRINTM(MERROR, "Data lengh is too large!\n");
5202 		ret = -EINVAL;
5203 		goto done;
5204 	}
5205 	if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
5206 		PRINTM(MINFO, "Copy from user failed\n");
5207 		ret = -EFAULT;
5208 		goto done;
5209 	}
5210 
5211 	rw = buf[0];		/* read/write (0/1) */
5212 	func = buf[1];		/* func (0/1/2) */
5213 	reg = buf[5];		/* address */
5214 	reg = (reg << 8) + buf[4];
5215 	reg = (reg << 8) + buf[3];
5216 	reg = (reg << 8) + buf[2];
5217 	mode = buf[6];		/* byte mode/block mode (0/1) */
5218 	blklen = buf[8];	/* block size */
5219 	blklen = (blklen << 8) + buf[7];
5220 	blknum = buf[10];	/* block number or byte number */
5221 	blknum = (blknum << 8) + buf[9];
5222 
5223 	if (mode != BYTE_MODE)
5224 		mode = BLOCK_MODE;
5225 	total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
5226 	if (total_len > WOAL_2K_BYTES) {
5227 		PRINTM(MERROR, "Total data length is too large!\n");
5228 		ret = -EINVAL;
5229 		goto done;
5230 	}
5231 	PRINTM(MINFO,
5232 	       "CMD53 read/write, func = %d, addr = %#x, mode = %d, block size = %d, block(byte) number = %d\n",
5233 	       func, reg, mode, blklen, blknum);
5234 
5235 	if (!rw) {
5236 		sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)->
5237 				func);
5238 		if (sdio_readsb
5239 		    (((struct sdio_mmc_card *)priv->phandle->card)->func, data,
5240 		     reg, total_len))
5241 			PRINTM(MERROR,
5242 			       "sdio_readsb: reading memory 0x%x failed\n",
5243 			       reg);
5244 		sdio_release_host(((struct sdio_mmc_card *)priv->phandle->
5245 				   card)->func);
5246 
5247 		if (copy_to_user(wrq->u.data.pointer, data, total_len)) {
5248 			PRINTM(MINFO, "Copy to user failed\n");
5249 			ret = -EFAULT;
5250 			goto done;
5251 		}
5252 		wrq->u.data.length = total_len;
5253 	} else {
5254 		pattern_len = wrq->u.data.length - 11;
5255 		if (pattern_len > total_len)
5256 			pattern_len = total_len;
5257 		memset(data, 0, WOAL_2K_BYTES);
5258 
5259 		/* Copy/duplicate the pattern to data buffer */
5260 		for (pos = 0; pos < total_len; pos++)
5261 			data[pos] = buf[11 + (pos % pattern_len)];
5262 
5263 		sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)->
5264 				func);
5265 		if (sdio_writesb
5266 		    (((struct sdio_mmc_card *)priv->phandle->card)->func, reg,
5267 		     data, total_len))
5268 			PRINTM(MERROR,
5269 			       "sdio_writesb: writing memory 0x%x failed\n",
5270 			       reg);
5271 		sdio_release_host(((struct sdio_mmc_card *)priv->phandle->
5272 				   card)->func);
5273 	}
5274 
5275 done:
5276 	kfree(buf);
5277 	kfree(data);
5278 	LEAVE();
5279 	return ret;
5280 }
5281 
5282 #if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
5283 /**
5284  * @brief Set SDIO Multi-point aggregation control parameters
5285  *
5286  * @param priv     A pointer to moal_private structure
5287  * @param wrq      A pointer to iwreq structure
5288  *
5289  * @return         0/MLAN_STATUS_PENDING --success, otherwise fail
5290  */
5291 static int
woal_do_sdio_mpa_ctrl(moal_private * priv,struct iwreq * wrq)5292 woal_do_sdio_mpa_ctrl(moal_private *priv, struct iwreq *wrq)
5293 {
5294 	int data[6], data_length = wrq->u.data.length, copy_len;
5295 	int ret = 0;
5296 	mlan_ds_misc_cfg *misc = NULL;
5297 	mlan_ioctl_req *req = NULL;
5298 	mlan_status status = MLAN_STATUS_SUCCESS;
5299 
5300 	ENTER();
5301 
5302 	if (sizeof(int) * wrq->u.data.length > sizeof(data)) {
5303 		PRINTM(MERROR, "Too many arguments\n");
5304 		ret = -EINVAL;
5305 		goto done;
5306 	}
5307 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
5308 
5309 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
5310 	if (req == NULL) {
5311 		ret = -ENOMEM;
5312 		goto done;
5313 	}
5314 	misc = (mlan_ds_misc_cfg *)req->pbuf;
5315 	memset(misc, 0, sizeof(mlan_ds_misc_cfg));
5316 
5317 	misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
5318 	req->req_id = MLAN_IOCTL_MISC_CFG;
5319 
5320 	/* Get the values first, then modify these values if
5321 	 * user had modified them */
5322 
5323 	req->action = MLAN_ACT_GET;
5324 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5325 	if (status != MLAN_STATUS_SUCCESS) {
5326 		PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
5327 		ret = -EFAULT;
5328 		goto done;
5329 	}
5330 
5331 	if (data_length == 0) {
5332 		data[0] = misc->param.mpa_ctrl.tx_enable;
5333 		data[1] = misc->param.mpa_ctrl.rx_enable;
5334 		data[2] = misc->param.mpa_ctrl.tx_buf_size;
5335 		data[3] = misc->param.mpa_ctrl.rx_buf_size;
5336 		data[4] = misc->param.mpa_ctrl.tx_max_ports;
5337 		data[5] = misc->param.mpa_ctrl.rx_max_ports;
5338 
5339 		PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0],
5340 		       data[1], data[2], data[3], data[4], data[5]);
5341 
5342 		if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
5343 			ret = -EFAULT;
5344 			goto done;
5345 		}
5346 		wrq->u.data.length = ARRAY_SIZE(data);
5347 		goto done;
5348 	}
5349 
5350 	if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
5351 		PRINTM(MINFO, "Copy from user failed\n");
5352 		ret = -EFAULT;
5353 		goto done;
5354 	}
5355 
5356 	switch (data_length) {
5357 	case 6:
5358 		misc->param.mpa_ctrl.rx_max_ports = data[5];
5359 	case 5:
5360 		misc->param.mpa_ctrl.tx_max_ports = data[4];
5361 	case 4:
5362 		misc->param.mpa_ctrl.rx_buf_size = data[3];
5363 	case 3:
5364 		misc->param.mpa_ctrl.tx_buf_size = data[2];
5365 	case 2:
5366 		misc->param.mpa_ctrl.rx_enable = data[1];
5367 	case 1:
5368 		/* Set cmd */
5369 		req->action = MLAN_ACT_SET;
5370 
5371 		PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0],
5372 		       data[1], data[2], data[3], data[4], data[5]);
5373 
5374 		misc->param.mpa_ctrl.tx_enable = data[0];
5375 		break;
5376 	default:
5377 		PRINTM(MERROR, "Default case error\n");
5378 		ret = -EINVAL;
5379 		goto done;
5380 	}
5381 
5382 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5383 	if (status != MLAN_STATUS_SUCCESS) {
5384 		PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
5385 		ret = -EFAULT;
5386 		goto done;
5387 	}
5388 
5389 done:
5390 	if (status != MLAN_STATUS_PENDING)
5391 		kfree(req);
5392 	LEAVE();
5393 	return ret;
5394 }
5395 #endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
5396 
5397 /**
5398  * @brief Set/Get scan configuration parameters
5399  *
5400  * @param priv     A pointer to moal_private structure
5401  * @param wrq      A pointer to iwreq structure
5402  *
5403  * @return         0 --success, otherwise fail
5404  */
5405 static int
woal_set_get_scan_cfg(moal_private * priv,struct iwreq * wrq)5406 woal_set_get_scan_cfg(moal_private *priv, struct iwreq *wrq)
5407 {
5408 	int ret = 0;
5409 	int arg_len = 7;
5410 	int data[arg_len], copy_len;
5411 	mlan_ds_scan *scan = NULL;
5412 	mlan_ioctl_req *req = NULL;
5413 	int data_length = wrq->u.data.length;
5414 	mlan_status status = MLAN_STATUS_SUCCESS;
5415 
5416 	ENTER();
5417 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
5418 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
5419 	if (req == NULL) {
5420 		ret = -ENOMEM;
5421 		goto done;
5422 	}
5423 	if (data_length > arg_len) {
5424 		ret = -EINVAL;
5425 		goto done;
5426 	}
5427 	scan = (mlan_ds_scan *)req->pbuf;
5428 	scan->sub_command = MLAN_OID_SCAN_CONFIG;
5429 	req->req_id = MLAN_IOCTL_SCAN;
5430 	memset(data, 0, sizeof(data));
5431 
5432 	if (data_length) {
5433 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
5434 			PRINTM(MERROR, "Copy from user failed\n");
5435 			ret = -EFAULT;
5436 			goto done;
5437 		}
5438 		if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) {
5439 			PRINTM(MERROR, "Invalid argument for scan type\n");
5440 			ret = -EINVAL;
5441 			goto done;
5442 		}
5443 		if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) {
5444 			PRINTM(MERROR, "Invalid argument for scan mode\n");
5445 			ret = -EINVAL;
5446 			goto done;
5447 		}
5448 		if ((data[2] < 0) || (data[2] > MAX_PROBES)) {
5449 			PRINTM(MERROR, "Invalid argument for scan probes\n");
5450 			ret = -EINVAL;
5451 			goto done;
5452 		}
5453 		if (((data[3] < 0) ||
5454 		     (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
5455 		    ((data[4] < 0) ||
5456 		     (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
5457 		    ((data[5] < 0) ||
5458 		     (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) {
5459 			PRINTM(MERROR, "Invalid argument for scan time\n");
5460 			ret = -EINVAL;
5461 			goto done;
5462 		}
5463 		if ((data[6] < 0) || (data[6] > 1)) {
5464 			PRINTM(MERROR, "Invalid argument for extended scan\n");
5465 			ret = -EINVAL;
5466 			goto done;
5467 		}
5468 		req->action = MLAN_ACT_SET;
5469 		memcpy(&scan->param.scan_cfg, data, sizeof(data));
5470 	} else
5471 		req->action = MLAN_ACT_GET;
5472 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5473 	if (status != MLAN_STATUS_SUCCESS) {
5474 		ret = -EFAULT;
5475 		goto done;
5476 	}
5477 	if (!data_length) {
5478 		memcpy(data, &scan->param.scan_cfg, sizeof(data));
5479 		if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
5480 			ret = -EFAULT;
5481 			goto done;
5482 		}
5483 		wrq->u.data.length = ARRAY_SIZE(data);
5484 	}
5485 done:
5486 	if (status != MLAN_STATUS_PENDING)
5487 		kfree(req);
5488 	LEAVE();
5489 	return ret;
5490 }
5491 
5492 /**
5493  * @brief Set/Get PS configuration parameters
5494  *
5495  * @param priv     A pointer to moal_private structure
5496  * @param wrq      A pointer to iwreq structure
5497  *
5498  * @return         0 --success, otherwise fail
5499  */
5500 static int
woal_set_get_ps_cfg(moal_private * priv,struct iwreq * wrq)5501 woal_set_get_ps_cfg(moal_private *priv, struct iwreq *wrq)
5502 {
5503 	int data[7], copy_len, ret = 0;
5504 	mlan_ds_pm_cfg *pm_cfg = NULL;
5505 	mlan_ioctl_req *req = NULL;
5506 	int allowed = 3;
5507 	int i = 3;
5508 	int data_length = wrq->u.data.length;
5509 	mlan_status status = MLAN_STATUS_SUCCESS;
5510 
5511 	ENTER();
5512 
5513 	allowed++;		/* For ad-hoc awake period parameter */
5514 	allowed++;		/* For beacon missing timeout parameter */
5515 	allowed += 2;		/* For delay to PS and PS mode parameters */
5516 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
5517 
5518 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
5519 	if (req == NULL) {
5520 		ret = -ENOMEM;
5521 		goto done;
5522 	}
5523 	if (data_length > allowed) {
5524 		ret = -EINVAL;
5525 		goto done;
5526 	}
5527 	pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
5528 	pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
5529 	req->req_id = MLAN_IOCTL_PM_CFG;
5530 	memset(data, 0, sizeof(data));
5531 
5532 	if (data_length) {
5533 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
5534 			PRINTM(MERROR, "Copy from user failed\n");
5535 			ret = -EFAULT;
5536 			goto done;
5537 		}
5538 		if ((data[0] < PS_NULL_DISABLE)) {
5539 			PRINTM(MERROR,
5540 			       "Invalid argument for PS null interval\n");
5541 			ret = -EINVAL;
5542 			goto done;
5543 		}
5544 		if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM)
5545 		    && (data[1] != MRVDRV_MATCH_CLOSEST_DTIM)
5546 		    && ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM)
5547 			|| (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
5548 			PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
5549 			ret = -EINVAL;
5550 			goto done;
5551 		}
5552 
5553 		if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL)
5554 		    && (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
5555 			PRINTM(MERROR,
5556 			       "Invalid argument for listen interval\n");
5557 			ret = -EINVAL;
5558 			goto done;
5559 		}
5560 
5561 		if ((data[i] != SPECIAL_ADHOC_AWAKE_PD) &&
5562 		    ((data[i] < MIN_ADHOC_AWAKE_PD) ||
5563 		     (data[i] > MAX_ADHOC_AWAKE_PD))) {
5564 			PRINTM(MERROR,
5565 			       "Invalid argument for adhoc awake period\n");
5566 			ret = -EINVAL;
5567 			goto done;
5568 		}
5569 		i++;
5570 		if ((data[i] != DISABLE_BCN_MISS_TO) &&
5571 		    ((data[i] < MIN_BCN_MISS_TO) ||
5572 		     (data[i] > MAX_BCN_MISS_TO))) {
5573 			PRINTM(MERROR,
5574 			       "Invalid argument for beacon miss timeout\n");
5575 			ret = -EINVAL;
5576 			goto done;
5577 		}
5578 		i++;
5579 		if (data_length < allowed - 1)
5580 			data[i] = DELAY_TO_PS_UNCHANGED;
5581 		else if ((data[i] < MIN_DELAY_TO_PS) ||
5582 			 (data[i] > MAX_DELAY_TO_PS)) {
5583 			PRINTM(MERROR, "Invalid argument for delay to PS\n");
5584 			ret = -EINVAL;
5585 			goto done;
5586 		}
5587 		i++;
5588 		if ((data[i] != PS_MODE_UNCHANGED) && (data[i] != PS_MODE_AUTO)
5589 		    && (data[i] != PS_MODE_POLL) && (data[i] != PS_MODE_NULL)) {
5590 			PRINTM(MERROR, "Invalid argument for PS mode\n");
5591 			ret = -EINVAL;
5592 			goto done;
5593 		}
5594 		i++;
5595 		req->action = MLAN_ACT_SET;
5596 		memcpy(&pm_cfg->param.ps_cfg, data,
5597 		       MIN(sizeof(pm_cfg->param.ps_cfg), sizeof(data)));
5598 	} else
5599 		req->action = MLAN_ACT_GET;
5600 
5601 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5602 	if (status != MLAN_STATUS_SUCCESS) {
5603 		ret = -EFAULT;
5604 		goto done;
5605 	}
5606 	memcpy(data, &pm_cfg->param.ps_cfg,
5607 	       MIN((sizeof(int) * allowed), sizeof(pm_cfg->param.ps_cfg)));
5608 	if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * allowed)) {
5609 		ret = -EFAULT;
5610 		goto done;
5611 	}
5612 	wrq->u.data.length = allowed;
5613 
5614 	if (req->action == MLAN_ACT_SET) {
5615 		pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
5616 		pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
5617 		pm_cfg->param.ps_mode = 1;
5618 		req->req_id = MLAN_IOCTL_PM_CFG;
5619 		req->action = MLAN_ACT_SET;
5620 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5621 	}
5622 
5623 done:
5624 	if (status != MLAN_STATUS_PENDING)
5625 		kfree(req);
5626 	LEAVE();
5627 	return ret;
5628 }
5629 
5630 /**
5631  *  @brief Private IOCTL entry to send an ADDTS TSPEC
5632  *
5633  *  Receive a ADDTS command from the application.  The command structure
5634  *    contains a TSPEC and timeout in milliseconds.  The timeout is performed
5635  *    in the firmware after the ADDTS command frame is sent.
5636  *
5637  *  The TSPEC is received in the API as an opaque block. The firmware will
5638  *    send the entire data block, including the bytes after the TSPEC.  This
5639  *    is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
5640  *    action frame.
5641  *
5642  *  The IOCTL structure contains two return fields:
5643  *    - The firmware command result, which indicates failure and timeouts
5644  *    - The IEEE Status code which contains the corresponding value from
5645  *      any ADDTS response frame received.
5646  *
5647  *  In addition, the opaque TSPEC data block passed in is replaced with the
5648  *    TSPEC received in the ADDTS response frame.  In case of failure, the
5649  *    AP may modify the TSPEC on return and in the case of success, the
5650  *    medium time is returned as calculated by the AP.  Along with the TSPEC,
5651  *    any IEs that are sent in the ADDTS response are also returned and can be
5652  *    parsed using the IOCTL length as an indicator of extra elements.
5653  *
5654  *  The return value to the application layer indicates a driver execution
5655  *    success or failure.  A successful return could still indicate a firmware
5656  *    failure or AP negotiation failure via the commandResult field copied
5657  *    back to the application.
5658  *
5659  *  @param priv    Pointer to the mlan_private driver data struct
5660  *  @param wrq     A pointer to iwreq structure containing the
5661  *                 wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
5662  *
5663  *  @return        0 if successful; IOCTL error code otherwise
5664  */
5665 static int
woal_wmm_addts_req_ioctl(moal_private * priv,struct iwreq * wrq)5666 woal_wmm_addts_req_ioctl(moal_private *priv, struct iwreq *wrq)
5667 {
5668 	mlan_ioctl_req *req = NULL;
5669 	mlan_ds_wmm_cfg *cfg = NULL;
5670 	wlan_ioctl_wmm_addts_req_t addts_ioctl;
5671 	int ret = 0;
5672 	mlan_status status = MLAN_STATUS_SUCCESS;
5673 
5674 	ENTER();
5675 
5676 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
5677 	if (req == NULL) {
5678 		ret = -ENOMEM;
5679 		goto done;
5680 	}
5681 
5682 	req->req_id = MLAN_IOCTL_WMM_CFG;
5683 	cfg = (mlan_ds_wmm_cfg *)req->pbuf;
5684 	cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
5685 
5686 	memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));
5687 
5688 	if (wrq->u.data.length) {
5689 		if (copy_from_user(&addts_ioctl, wrq->u.data.pointer,
5690 				   MIN(wrq->u.data.length,
5691 				       sizeof(addts_ioctl)))) {
5692 			PRINTM(MERROR, "TSPEC: ADDTS copy from user failed\n");
5693 			ret = -EFAULT;
5694 			goto done;
5695 		}
5696 
5697 		cfg->param.addts.timeout = addts_ioctl.timeout_ms;
5698 		cfg->param.addts.ie_data_len = addts_ioctl.ie_data_len;
5699 
5700 		if (cfg->param.addts.ie_data_len >
5701 		    sizeof(cfg->param.addts.ie_data)) {
5702 			PRINTM(MERROR, "IE data length too large\n");
5703 			ret = -EFAULT;
5704 			goto done;
5705 		}
5706 
5707 		memcpy(cfg->param.addts.ie_data,
5708 		       addts_ioctl.ie_data, cfg->param.addts.ie_data_len);
5709 
5710 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5711 		if (status != MLAN_STATUS_SUCCESS) {
5712 			ret = -EFAULT;
5713 			goto done;
5714 		}
5715 		addts_ioctl.cmd_result = cfg->param.addts.result;
5716 		addts_ioctl.ieee_status_code =
5717 			(t_u8)cfg->param.addts.status_code;
5718 		addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;
5719 
5720 		memcpy(addts_ioctl.ie_data,
5721 		       cfg->param.addts.ie_data, cfg->param.addts.ie_data_len);
5722 
5723 		wrq->u.data.length = (sizeof(addts_ioctl)
5724 				      - sizeof(addts_ioctl.ie_data)
5725 				      + cfg->param.addts.ie_data_len);
5726 
5727 		if (copy_to_user(wrq->u.data.pointer,
5728 				 &addts_ioctl, wrq->u.data.length)) {
5729 			PRINTM(MERROR, "TSPEC: ADDTS copy to user failed\n");
5730 			ret = -EFAULT;
5731 			goto done;
5732 		}
5733 	}
5734 
5735 done:
5736 	if (status != MLAN_STATUS_PENDING)
5737 		kfree(req);
5738 	LEAVE();
5739 	return ret;
5740 }
5741 
5742 /**
5743  *  @brief Private IOCTL entry to send a DELTS TSPEC
5744  *
5745  *  Receive a DELTS command from the application.  The command structure
5746  *    contains a TSPEC and reason code along with space for a command result
5747  *    to be returned.  The information is packaged is sent to the wlan_cmd.c
5748  *    firmware command prep and send routines for execution in the firmware.
5749  *
5750  *  The reason code is not used for WMM implementations but is indicated in
5751  *    the 802.11e specification.
5752  *
5753  *  The return value to the application layer indicates a driver execution
5754  *    success or failure.  A successful return could still indicate a firmware
5755  *    failure via the cmd_result field copied back to the application.
5756  *
5757  *  @param priv    Pointer to the mlan_private driver data struct
5758  *  @param wrq     A pointer to iwreq structure containing the
5759  *                 wlan_ioctl_wmm_delts_req_t struct for this DELTS request
5760  *
5761  *  @return        0 if successful; IOCTL error code otherwise
5762  */
5763 static int
woal_wmm_delts_req_ioctl(moal_private * priv,struct iwreq * wrq)5764 woal_wmm_delts_req_ioctl(moal_private *priv, struct iwreq *wrq)
5765 {
5766 	mlan_ioctl_req *req = NULL;
5767 	mlan_ds_wmm_cfg *cfg = NULL;
5768 	wlan_ioctl_wmm_delts_req_t delts_ioctl;
5769 	int ret = 0;
5770 	mlan_status status = MLAN_STATUS_SUCCESS;
5771 
5772 	ENTER();
5773 
5774 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
5775 	if (req == NULL) {
5776 		ret = -ENOMEM;
5777 		goto done;
5778 	}
5779 
5780 	req->req_id = MLAN_IOCTL_WMM_CFG;
5781 	cfg = (mlan_ds_wmm_cfg *)req->pbuf;
5782 	cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
5783 
5784 	memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));
5785 
5786 	if (wrq->u.data.length) {
5787 		if (copy_from_user(&delts_ioctl, wrq->u.data.pointer,
5788 				   MIN(wrq->u.data.length,
5789 				       sizeof(delts_ioctl)))) {
5790 			PRINTM(MERROR, "TSPEC: DELTS copy from user failed\n");
5791 			ret = -EFAULT;
5792 			goto done;
5793 		}
5794 
5795 		cfg->param.delts.status_code =
5796 			(t_u32)delts_ioctl.ieee_reason_code;
5797 		cfg->param.delts.ie_data_len = (t_u8)delts_ioctl.ie_data_len;
5798 
5799 		if ((cfg->param.delts.ie_data_len) >
5800 		    sizeof(cfg->param.delts.ie_data)) {
5801 			PRINTM(MERROR, "IE data length too large\n");
5802 			ret = -EFAULT;
5803 			goto done;
5804 		}
5805 
5806 		memcpy(cfg->param.delts.ie_data,
5807 		       delts_ioctl.ie_data, cfg->param.delts.ie_data_len);
5808 
5809 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5810 		if (status != MLAN_STATUS_SUCCESS) {
5811 			ret = -EFAULT;
5812 			goto done;
5813 		}
5814 
5815 		/* Return the firmware command result back to the application layer */
5816 		delts_ioctl.cmd_result = cfg->param.delts.result;
5817 		wrq->u.data.length = sizeof(delts_ioctl);
5818 
5819 		if (copy_to_user(wrq->u.data.pointer,
5820 				 &delts_ioctl, wrq->u.data.length)) {
5821 			PRINTM(MERROR, "TSPEC: DELTS copy to user failed\n");
5822 			ret = -EFAULT;
5823 			goto done;
5824 		}
5825 	}
5826 
5827 done:
5828 	if (status != MLAN_STATUS_PENDING)
5829 		kfree(req);
5830 	LEAVE();
5831 	return ret;
5832 }
5833 
5834 /**
5835  *  @brief Private IOCTL entry to get/set a specified AC Queue's parameters
5836  *
5837  *  Receive a AC Queue configuration command which is used to get, set, or
5838  *    default the parameters associated with a specific WMM AC Queue.
5839  *
5840  *  @param priv    Pointer to the mlan_private driver data struct
5841  *  @param wrq     A pointer to iwreq structure containing the
5842  *                 wlan_ioctl_wmm_queue_config_t struct
5843  *
5844  *  @return        0 if successful; IOCTL error code otherwise
5845  */
5846 static int
woal_wmm_queue_config_ioctl(moal_private * priv,struct iwreq * wrq)5847 woal_wmm_queue_config_ioctl(moal_private *priv, struct iwreq *wrq)
5848 {
5849 	mlan_ioctl_req *req = NULL;
5850 	mlan_ds_wmm_cfg *pwmm = NULL;
5851 	mlan_ds_wmm_queue_config *pqcfg = NULL;
5852 	wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
5853 	int ret = 0;
5854 	mlan_status status = MLAN_STATUS_SUCCESS;
5855 
5856 	ENTER();
5857 
5858 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
5859 	if (req == NULL) {
5860 		ret = -ENOMEM;
5861 		goto done;
5862 	}
5863 
5864 	req->req_id = MLAN_IOCTL_WMM_CFG;
5865 	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
5866 	pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
5867 
5868 	memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
5869 	pqcfg = (mlan_ds_wmm_queue_config *)&pwmm->param.q_cfg;
5870 
5871 	if (wrq->u.data.length) {
5872 		if (copy_from_user(&qcfg_ioctl, wrq->u.data.pointer,
5873 				   MIN(wrq->u.data.length,
5874 				       sizeof(qcfg_ioctl)))) {
5875 			PRINTM(MERROR, "QCONFIG: copy from user failed\n");
5876 			ret = -EFAULT;
5877 			goto done;
5878 		}
5879 
5880 		pqcfg->action = qcfg_ioctl.action;
5881 		pqcfg->access_category = qcfg_ioctl.access_category;
5882 		pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
5883 
5884 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5885 		if (status != MLAN_STATUS_SUCCESS) {
5886 			ret = -EFAULT;
5887 			goto done;
5888 		}
5889 		memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
5890 		qcfg_ioctl.action = pqcfg->action;
5891 		qcfg_ioctl.access_category = pqcfg->access_category;
5892 		qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
5893 		wrq->u.data.length = sizeof(qcfg_ioctl);
5894 
5895 		if (copy_to_user
5896 		    (wrq->u.data.pointer, &qcfg_ioctl, wrq->u.data.length)) {
5897 			PRINTM(MERROR, "QCONFIG: copy to user failed\n");
5898 			ret = -EFAULT;
5899 			goto done;
5900 		}
5901 	}
5902 
5903 done:
5904 	if (status != MLAN_STATUS_PENDING)
5905 		kfree(req);
5906 	LEAVE();
5907 	return ret;
5908 }
5909 
5910 /**
5911  *  @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
5912  *
5913  *  Receive a AC Queue statistics command from the application for a specific
5914  *    WMM AC.  The command can:
5915  *         - Turn stats on
5916  *         - Turn stats off
5917  *         - Collect and clear the stats
5918  *
5919  *  @param priv    Pointer to the moal_private driver data struct
5920  *  @param wrq     A pointer to iwreq structure containing the
5921  *                 wlan_ioctl_wmm_queue_stats_t struct
5922  *
5923  *  @return        0 if successful; IOCTL error code otherwise
5924  */
5925 static int
woal_wmm_queue_stats_ioctl(moal_private * priv,struct iwreq * wrq)5926 woal_wmm_queue_stats_ioctl(moal_private *priv, struct iwreq *wrq)
5927 {
5928 	mlan_ioctl_req *req = NULL;
5929 	mlan_ds_wmm_cfg *pwmm = NULL;
5930 	mlan_ds_wmm_queue_stats *pqstats = NULL;
5931 	wlan_ioctl_wmm_queue_stats_t qstats_ioctl;
5932 	int ret = 0;
5933 	mlan_status status = MLAN_STATUS_SUCCESS;
5934 
5935 	ENTER();
5936 
5937 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
5938 	if (req == NULL) {
5939 		ret = -ENOMEM;
5940 		goto done;
5941 	}
5942 
5943 	req->req_id = MLAN_IOCTL_WMM_CFG;
5944 	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
5945 	pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATS;
5946 
5947 	memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
5948 	pqstats = (mlan_ds_wmm_queue_stats *)&pwmm->param.q_stats;
5949 
5950 	if (wrq->u.data.length) {
5951 		if (copy_from_user(&qstats_ioctl, wrq->u.data.pointer,
5952 				   MIN(wrq->u.data.length,
5953 				       sizeof(qstats_ioctl)))) {
5954 			PRINTM(MERROR, "QSTATS: copy from user failed\n");
5955 			ret = -EFAULT;
5956 			goto done;
5957 		}
5958 
5959 		memcpy((void *)pqstats, (void *)&qstats_ioctl,
5960 		       sizeof(qstats_ioctl));
5961 		PRINTM(MINFO, "QSTATS: IOCTL [%d,%d]\n", qstats_ioctl.action,
5962 		       qstats_ioctl.user_priority);
5963 
5964 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5965 		if (status != MLAN_STATUS_SUCCESS) {
5966 			ret = -EFAULT;
5967 			goto done;
5968 		}
5969 
5970 		memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
5971 		memcpy((void *)&qstats_ioctl, (void *)pqstats,
5972 		       sizeof(qstats_ioctl));
5973 		wrq->u.data.length = sizeof(qstats_ioctl);
5974 
5975 		if (copy_to_user
5976 		    (wrq->u.data.pointer, &qstats_ioctl, wrq->u.data.length)) {
5977 			PRINTM(MERROR, "QSTATS: copy to user failed\n");
5978 			ret = -EFAULT;
5979 			goto done;
5980 		}
5981 	}
5982 
5983 done:
5984 	if (status != MLAN_STATUS_PENDING)
5985 		kfree(req);
5986 	LEAVE();
5987 	return ret;
5988 }
5989 
5990 /**
5991  *  @brief Private IOCTL entry to get the status of the WMM queues
5992  *
5993  *  Return the following information for each WMM AC:
5994  *        - WMM IE Acm Required
5995  *        - Firmware Flow Required
5996  *        - Firmware Flow Established
5997  *        - Firmware Queue Enabled
5998  *        - Firmware Delivery Enabled
5999  *        - Firmware Trigger Enabled
6000  *
6001  *  @param priv    Pointer to the moal_private driver data struct
6002  *  @param wrq     A pointer to iwreq structure containing the
6003  *                 wlan_ioctl_wmm_queue_status_t struct for request
6004  *
6005  *  @return        0 if successful; IOCTL error code otherwise
6006  */
6007 static int
woal_wmm_queue_status_ioctl(moal_private * priv,struct iwreq * wrq)6008 woal_wmm_queue_status_ioctl(moal_private *priv, struct iwreq *wrq)
6009 {
6010 	mlan_ioctl_req *req = NULL;
6011 	mlan_ds_wmm_cfg *pwmm = NULL;
6012 	wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
6013 	int ret = 0;
6014 	mlan_status status = MLAN_STATUS_SUCCESS;
6015 
6016 	ENTER();
6017 
6018 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
6019 	if (req == NULL) {
6020 		ret = -ENOMEM;
6021 		goto done;
6022 	}
6023 
6024 	req->req_id = MLAN_IOCTL_WMM_CFG;
6025 	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
6026 	pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
6027 
6028 	if (wrq->u.data.length == sizeof(qstatus_ioctl)) {
6029 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6030 		if (status != MLAN_STATUS_SUCCESS) {
6031 			ret = -EFAULT;
6032 			goto done;
6033 		}
6034 
6035 		memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
6036 		memcpy((void *)&qstatus_ioctl, (void *)&pwmm->param.q_status,
6037 		       sizeof(qstatus_ioctl));
6038 		wrq->u.data.length = sizeof(qstatus_ioctl);
6039 	} else {
6040 		wrq->u.data.length = 0;
6041 	}
6042 
6043 	if (copy_to_user
6044 	    (wrq->u.data.pointer, &qstatus_ioctl, wrq->u.data.length)) {
6045 		PRINTM(MERROR, "QSTATUS: copy to user failed\n");
6046 		ret = -EFAULT;
6047 		goto done;
6048 	}
6049 
6050 done:
6051 	if (status != MLAN_STATUS_PENDING)
6052 		kfree(req);
6053 	LEAVE();
6054 	return ret;
6055 }
6056 
6057 /**
6058  *  @brief Private IOCTL entry to get the status of the WMM Traffic Streams
6059  *
6060  *  @param priv    Pointer to the moal_private driver data struct
6061  *  @param wrq     A pointer to iwreq structure containing the
6062  *                 wlan_ioctl_wmm_ts_status_t struct for request
6063  *
6064  *  @return        0 if successful; IOCTL error code otherwise
6065  */
6066 static int
woal_wmm_ts_status_ioctl(moal_private * priv,struct iwreq * wrq)6067 woal_wmm_ts_status_ioctl(moal_private *priv, struct iwreq *wrq)
6068 {
6069 	mlan_ioctl_req *req = NULL;
6070 	mlan_ds_wmm_cfg *pwmm = NULL;
6071 	wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
6072 	int ret = 0;
6073 	mlan_status status = MLAN_STATUS_SUCCESS;
6074 
6075 	ENTER();
6076 
6077 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
6078 	if (req == NULL) {
6079 		ret = -ENOMEM;
6080 		goto done;
6081 	}
6082 
6083 	req->req_id = MLAN_IOCTL_WMM_CFG;
6084 	pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
6085 	pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
6086 
6087 	memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
6088 
6089 	if (wrq->u.data.length == sizeof(ts_status_ioctl)) {
6090 		if (copy_from_user(&ts_status_ioctl, wrq->u.data.pointer,
6091 				   MIN(wrq->u.data.length,
6092 				       sizeof(ts_status_ioctl)))) {
6093 			PRINTM(MERROR, "TS_STATUS: copy from user failed\n");
6094 			ret = -EFAULT;
6095 			goto done;
6096 		}
6097 
6098 		memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
6099 		pwmm->param.ts_status.tid = ts_status_ioctl.tid;
6100 
6101 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6102 		if (status != MLAN_STATUS_SUCCESS) {
6103 			ret = -EFAULT;
6104 			goto done;
6105 		}
6106 
6107 		memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
6108 		memcpy((void *)&ts_status_ioctl, (void *)&pwmm->param.ts_status,
6109 		       sizeof(ts_status_ioctl));
6110 		wrq->u.data.length = sizeof(ts_status_ioctl);
6111 	} else {
6112 		wrq->u.data.length = 0;
6113 	}
6114 
6115 	if (copy_to_user
6116 	    (wrq->u.data.pointer, &ts_status_ioctl, wrq->u.data.length)) {
6117 		PRINTM(MERROR, "TS_STATUS: copy to user failed\n");
6118 		ret = -EFAULT;
6119 		goto done;
6120 	}
6121 
6122 done:
6123 	if (status != MLAN_STATUS_PENDING)
6124 		kfree(req);
6125 	LEAVE();
6126 	return ret;
6127 }
6128 
6129 /**
6130  *  @brief Private IOCTL entry to get the By-passed TX packet from upper layer
6131  *
6132  *  @param priv    Pointer to the moal_private driver data struct
6133  *  @param wrq     A pointer to iwreq structure containing the packet
6134  *
6135  *  @return        0 if successful; IOCTL error code otherwise
6136  */
6137 static int
woal_bypassed_packet_ioctl(moal_private * priv,struct iwreq * wrq)6138 woal_bypassed_packet_ioctl(moal_private *priv, struct iwreq *wrq)
6139 {
6140 	int ret = 0;
6141 	struct sk_buff *skb = NULL;
6142 	struct ethhdr *eth;
6143 	t_u16 moreLen = 0, copyLen = 0;
6144 	ENTER();
6145 
6146 #define MLAN_BYPASS_PKT_EXTRA_OFFSET        (4)
6147 
6148 	copyLen = wrq->u.data.length;
6149 	moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET
6150 		+ sizeof(mlan_buffer);
6151 
6152 	skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
6153 	if (skb == NULL) {
6154 		PRINTM(MERROR, "kmalloc no memory !!\n");
6155 		LEAVE();
6156 		return -ENOMEM;
6157 	}
6158 
6159 	skb_reserve(skb, moreLen);
6160 
6161 	if (copy_from_user(skb_put(skb, copyLen), wrq->u.data.pointer, copyLen)) {
6162 		PRINTM(MERROR, "PortBlock: copy from user failed\n");
6163 		dev_kfree_skb_any(skb);
6164 		ret = -EFAULT;
6165 		goto done;
6166 	}
6167 
6168 	eth = (struct ethhdr *)skb->data;
6169 	eth->h_proto = __constant_htons(eth->h_proto);
6170 	skb->dev = priv->netdev;
6171 
6172 	HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));
6173 
6174 	woal_hard_start_xmit(skb, priv->netdev);
6175 done:
6176 	LEAVE();
6177 	return ret;
6178 }
6179 
6180 /**
6181  *  @brief Set/Get auth type
6182  *
6183  *  @param priv     Pointer to the moal_private driver data struct
6184  *  @param wrq      A pointer to iwreq structure
6185  *
6186  *  @return         0 --success, otherwise fail
6187  */
6188 static int
woal_auth_type(moal_private * priv,struct iwreq * wrq)6189 woal_auth_type(moal_private *priv, struct iwreq *wrq)
6190 {
6191 	int auth_type;
6192 	t_u32 auth_mode;
6193 	int ret = 0;
6194 
6195 	ENTER();
6196 	if (wrq->u.data.length == 0) {
6197 		if (MLAN_STATUS_SUCCESS !=
6198 		    woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
6199 			ret = -EFAULT;
6200 			goto done;
6201 		}
6202 		auth_type = auth_mode;
6203 		if (copy_to_user
6204 		    (wrq->u.data.pointer, &auth_type, sizeof(auth_type))) {
6205 			PRINTM(MERROR, "Copy to user failed\n");
6206 			ret = -EFAULT;
6207 			goto done;
6208 		}
6209 		wrq->u.data.length = 1;
6210 	} else {
6211 		if (copy_from_user
6212 		    (&auth_type, wrq->u.data.pointer, sizeof(auth_type))) {
6213 			PRINTM(MERROR, "Copy from user failed\n");
6214 			ret = -EFAULT;
6215 			goto done;
6216 		}
6217 		PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
6218 		if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
6219 		     (auth_type > MLAN_AUTH_MODE_SHARED))
6220 		    && (auth_type != MLAN_AUTH_MODE_AUTO)) {
6221 			ret = -EINVAL;
6222 			goto done;
6223 		}
6224 		auth_mode = auth_type;
6225 		if (MLAN_STATUS_SUCCESS !=
6226 		    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) {
6227 			ret = -EFAULT;
6228 			goto done;
6229 		}
6230 	}
6231 done:
6232 	LEAVE();
6233 	return ret;
6234 }
6235 
6236 /**
6237  *  @brief Set/Get Port Control mode
6238  *
6239  *  @param priv     Pointer to the moal_private driver data struct
6240  *  @param wrq      A pointer to iwreq structure
6241  *
6242  *  @return         0 --success, otherwise fail
6243  */
6244 static int
woal_port_ctrl(moal_private * priv,struct iwreq * wrq)6245 woal_port_ctrl(moal_private *priv, struct iwreq *wrq)
6246 {
6247 	mlan_ioctl_req *req = NULL;
6248 	mlan_ds_sec_cfg *sec = NULL;
6249 	int ret = 0;
6250 	mlan_status status = MLAN_STATUS_SUCCESS;
6251 	ENTER();
6252 
6253 	/* Allocate an IOCTL request buffer */
6254 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
6255 	if (req == NULL) {
6256 		ret = -ENOMEM;
6257 		goto done;
6258 	}
6259 
6260 	/* Fill request buffer */
6261 	sec = (mlan_ds_sec_cfg *)req->pbuf;
6262 	sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
6263 	req->req_id = MLAN_IOCTL_SEC_CFG;
6264 
6265 	if (wrq->u.data.length) {
6266 		if (copy_from_user(&sec->param.port_ctrl_enabled,
6267 				   wrq->u.data.pointer, sizeof(int)) != 0) {
6268 			PRINTM(MERROR, "port_ctrl:Copy from user failed\n");
6269 			ret = -EFAULT;
6270 			goto done;
6271 		}
6272 		req->action = MLAN_ACT_SET;
6273 	} else {
6274 		req->action = MLAN_ACT_GET;
6275 	}
6276 
6277 	/* Send IOCTL request to MLAN */
6278 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6279 	if (status != MLAN_STATUS_SUCCESS) {
6280 		ret = -EFAULT;
6281 		goto done;
6282 	}
6283 
6284 	if (!wrq->u.data.length) {
6285 		if (copy_to_user
6286 		    (wrq->u.data.pointer, &sec->param.port_ctrl_enabled,
6287 		     sizeof(int))) {
6288 			PRINTM(MERROR, "port_ctrl:Copy to user failed\n");
6289 			ret = -EFAULT;
6290 			goto done;
6291 		}
6292 		wrq->u.data.length = 1;
6293 	}
6294 
6295 done:
6296 	if (status != MLAN_STATUS_PENDING)
6297 		kfree(req);
6298 	LEAVE();
6299 	return ret;
6300 }
6301 
6302 #if defined(DFS_TESTING_SUPPORT)
6303 /**
6304  *  @brief Set/Get DFS Testing settings
6305  *
6306  *  @param priv     Pointer to the moal_private driver data struct
6307  *  @param wrq      A pointer to iwreq structure
6308  *
6309  *  @return         0 --success, otherwise fail
6310  */
6311 static int
woal_dfs_testing(moal_private * priv,struct iwreq * wrq)6312 woal_dfs_testing(moal_private *priv, struct iwreq *wrq)
6313 {
6314 	mlan_ioctl_req *req = NULL;
6315 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
6316 	int ret = 0;
6317 	int data[4], copy_len;
6318 	int data_length = wrq->u.data.length;
6319 	mlan_status status = MLAN_STATUS_SUCCESS;
6320 	ENTER();
6321 
6322 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
6323 	/* Allocate an IOCTL request buffer */
6324 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
6325 	if (req == NULL) {
6326 		ret = -ENOMEM;
6327 		goto done;
6328 	}
6329 
6330 	/* Fill request buffer */
6331 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
6332 	ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
6333 	req->req_id = MLAN_IOCTL_11H_CFG;
6334 
6335 	if (!data_length) {
6336 		req->action = MLAN_ACT_GET;
6337 	} else if (data_length == 4) {
6338 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
6339 			PRINTM(MERROR, "Copy from user failed\n");
6340 			ret = -EFAULT;
6341 			goto done;
6342 		}
6343 		if ((unsigned)data[0] > 0xFFFF) {
6344 			PRINTM(MERROR, "The maximum user CAC is 65535 msec.\n");
6345 			ret = -EINVAL;
6346 			goto done;
6347 		}
6348 		if ((unsigned)data[1] > 0xFFFF) {
6349 			PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
6350 			ret = -EINVAL;
6351 			goto done;
6352 		}
6353 		if ((unsigned)data[3] > 0xFF) {
6354 			PRINTM(MERROR,
6355 			       "The maximum user fixed channel is 255.\n");
6356 			ret = -EINVAL;
6357 			goto done;
6358 		}
6359 		ds_11hcfg->param.dfs_testing.usr_cac_period_msec =
6360 			(t_u16)data[0];
6361 		ds_11hcfg->param.dfs_testing.usr_nop_period_sec =
6362 			(t_u16)data[1];
6363 		ds_11hcfg->param.dfs_testing.usr_no_chan_change =
6364 			data[2] ? 1 : 0;
6365 		ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8)data[3];
6366 		priv->phandle->cac_period_jiffies = (t_u16)data[0] * HZ / 1000;
6367 		req->action = MLAN_ACT_SET;
6368 	} else {
6369 		PRINTM(MERROR, "Invalid number of args!\n");
6370 		ret = -EINVAL;
6371 		goto done;
6372 	}
6373 
6374 	/* Send IOCTL request to MLAN */
6375 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6376 	if (status != MLAN_STATUS_SUCCESS) {
6377 		ret = -EFAULT;
6378 		goto done;
6379 	}
6380 
6381 	if (!data_length) {
6382 		data[0] = ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
6383 		data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
6384 		data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
6385 		data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
6386 		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * 4)) {
6387 			PRINTM(MERROR, "Copy to user failed\n");
6388 			ret = -EFAULT;
6389 			goto done;
6390 		}
6391 		wrq->u.data.length = 4;
6392 	}
6393 
6394 done:
6395 	if (status != MLAN_STATUS_PENDING)
6396 		kfree(req);
6397 	LEAVE();
6398 	return ret;
6399 }
6400 #endif /* DFS_SUPPORT && DFS_TESTING_SUPPORT */
6401 
6402 /**
6403  *  @brief Set/Get Mgmt Frame passthru mask
6404  *
6405  *  @param priv     A pointer to moal_private structure
6406  *  @param wrq      A pointer to iwreq structure
6407  *
6408  *  @return         0 -- success, otherwise fail
6409  */
6410 static int
woal_mgmt_frame_passthru_ctrl(moal_private * priv,struct iwreq * wrq)6411 woal_mgmt_frame_passthru_ctrl(moal_private *priv, struct iwreq *wrq)
6412 {
6413 	int ret = 0, data_length = wrq->u.data.length;
6414 	mlan_ioctl_req *req = NULL;
6415 	mlan_ds_misc_cfg *mgmt_cfg = NULL;
6416 	int mask = 0;
6417 	mlan_status status = MLAN_STATUS_SUCCESS;
6418 
6419 	ENTER();
6420 
6421 	if (data_length > 1) {
6422 		PRINTM(MERROR, "Invalid no of arguments!\n");
6423 		ret = -EINVAL;
6424 		goto done;
6425 	}
6426 	/* Allocate an IOCTL request buffer */
6427 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6428 	if (req == NULL) {
6429 		ret = -ENOMEM;
6430 		goto done;
6431 	}
6432 
6433 	/* Fill request buffer */
6434 	mgmt_cfg = (mlan_ds_misc_cfg *)req->pbuf;
6435 	req->req_id = MLAN_IOCTL_MISC_CFG;
6436 	mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
6437 
6438 	if (data_length) {	/* SET */
6439 		if (copy_from_user(&mask, wrq->u.data.pointer, sizeof(int))) {
6440 			PRINTM(MERROR, "copy from user failed\n");
6441 			ret = -EFAULT;
6442 			goto done;
6443 		}
6444 		mgmt_cfg->param.mgmt_subtype_mask = mask;
6445 		req->action = MLAN_ACT_SET;
6446 	} else {
6447 		req->action = MLAN_ACT_GET;
6448 	}
6449 
6450 	/* Send IOCTL request to MLAN */
6451 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6452 	if (status != MLAN_STATUS_SUCCESS) {
6453 		ret = -EFAULT;
6454 		goto done;
6455 	}
6456 
6457 	mask = mgmt_cfg->param.mgmt_subtype_mask;
6458 	if (copy_to_user(wrq->u.data.pointer, &mask, sizeof(int))) {
6459 		ret = -EFAULT;
6460 		goto done;
6461 	}
6462 	wrq->u.data.length = 1;
6463 
6464 done:
6465 	if (status != MLAN_STATUS_PENDING)
6466 		kfree(req);
6467 	LEAVE();
6468 	return ret;
6469 }
6470 
6471 /**
6472  *  @brief Set/Get CFP table codes
6473  *
6474  *  @param priv     Pointer to the moal_private driver data struct
6475  *  @param wrq      A pointer to iwreq structure
6476  *
6477  *  @return         0 --success, otherwise fail
6478  */
6479 static int
woal_cfp_code(moal_private * priv,struct iwreq * wrq)6480 woal_cfp_code(moal_private *priv, struct iwreq *wrq)
6481 {
6482 	int ret = 0;
6483 	int data[2], copy_len;
6484 	int data_length = wrq->u.data.length;
6485 	mlan_ioctl_req *req = NULL;
6486 	mlan_ds_misc_cfg *misc_cfg = NULL;
6487 	mlan_ds_misc_cfp_code *cfp_code = NULL;
6488 	mlan_status status = MLAN_STATUS_SUCCESS;
6489 
6490 	ENTER();
6491 
6492 	if (data_length > 2) {
6493 		PRINTM(MERROR, "Invalid number of argument!\n");
6494 		ret = -EINVAL;
6495 		goto done;
6496 	}
6497 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
6498 
6499 	/* Allocate an IOCTL request buffer */
6500 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6501 	if (req == NULL) {
6502 		ret = -ENOMEM;
6503 		goto done;
6504 	}
6505 
6506 	/* Fill request buffer */
6507 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
6508 	cfp_code = &misc_cfg->param.cfp_code;
6509 	misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
6510 	req->req_id = MLAN_IOCTL_MISC_CFG;
6511 
6512 	if (!data_length) {
6513 		req->action = MLAN_ACT_GET;
6514 	} else {
6515 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
6516 			PRINTM(MERROR, "Copy from user failed\n");
6517 			ret = -EFAULT;
6518 			goto done;
6519 		}
6520 		cfp_code->cfp_code_bg = data[0];
6521 		if (data_length == 2)
6522 			cfp_code->cfp_code_a = data[1];
6523 		req->action = MLAN_ACT_SET;
6524 	}
6525 
6526 	/* Send IOCTL request to MLAN */
6527 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6528 	if (status != MLAN_STATUS_SUCCESS) {
6529 		ret = -EFAULT;
6530 		goto done;
6531 	}
6532 
6533 	if (!data_length) {
6534 		data[0] = cfp_code->cfp_code_bg;
6535 		data[1] = cfp_code->cfp_code_a;
6536 		data_length = 2;
6537 		if (copy_to_user
6538 		    (wrq->u.data.pointer, &data, sizeof(int) * data_length)) {
6539 			PRINTM(MERROR, "Copy to user failed\n");
6540 			ret = -EFAULT;
6541 			goto done;
6542 		}
6543 		wrq->u.data.length = data_length;
6544 	}
6545 
6546 done:
6547 	if (status != MLAN_STATUS_PENDING)
6548 		kfree(req);
6549 	LEAVE();
6550 	return ret;
6551 }
6552 
6553 /**
6554  * @brief Set/Get Tx/Rx antenna
6555  *
6556  * @param priv     A pointer to moal_private structure
6557  * @param wrq      A pointer to iwreq structure
6558  *
6559  * @return         0 --success, otherwise fail
6560  */
6561 static int
woal_set_get_tx_rx_ant(moal_private * priv,struct iwreq * wrq)6562 woal_set_get_tx_rx_ant(moal_private *priv, struct iwreq *wrq)
6563 {
6564 	int ret = 0;
6565 	mlan_ds_radio_cfg *radio = NULL;
6566 	mlan_ioctl_req *req = NULL;
6567 	int data[3] = { 0 };
6568 	mlan_status status = MLAN_STATUS_SUCCESS;
6569 	int copy_len;
6570 
6571 	ENTER();
6572 
6573 	if (wrq->u.data.length * sizeof(int) > sizeof(data)) {
6574 		PRINTM(MERROR, "Too many arguments\n");
6575 		ret = -EFAULT;
6576 		goto done;
6577 	}
6578 	copy_len = MIN(sizeof(data), wrq->u.data.length * sizeof(int));
6579 
6580 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
6581 	if (req == NULL) {
6582 		ret = -ENOMEM;
6583 		goto done;
6584 	}
6585 	radio = (mlan_ds_radio_cfg *)req->pbuf;
6586 	radio->sub_command = MLAN_OID_ANT_CFG;
6587 	req->req_id = MLAN_IOCTL_RADIO_CFG;
6588 	if (wrq->u.data.length) {
6589 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
6590 			PRINTM(MERROR, "Copy from user failed\n");
6591 			ret = -EFAULT;
6592 			goto done;
6593 		}
6594 
6595 		radio->param.ant_cfg_1x1.antenna = data[0];
6596 		if (wrq->u.data.length == 2)
6597 			radio->param.ant_cfg_1x1.evaluate_time = data[1];
6598 		req->action = MLAN_ACT_SET;
6599 	} else
6600 		req->action = MLAN_ACT_GET;
6601 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6602 	if (status != MLAN_STATUS_SUCCESS) {
6603 		ret = -EFAULT;
6604 		goto done;
6605 	}
6606 	if (!wrq->u.data.length) {
6607 		wrq->u.data.length = 1;
6608 		data[0] = (int)radio->param.ant_cfg_1x1.antenna;
6609 		data[1] = (int)radio->param.ant_cfg_1x1.evaluate_time;
6610 		data[2] = (int)radio->param.ant_cfg_1x1.current_antenna;
6611 		if (data[0] == 0xffff && data[2] > 0)
6612 			wrq->u.data.length = 3;
6613 		else if (data[0] == 0xffff)
6614 			wrq->u.data.length = 2;
6615 		if (copy_to_user
6616 		    (wrq->u.data.pointer, data,
6617 		     wrq->u.data.length * sizeof(int))) {
6618 			ret = -EFAULT;
6619 			goto done;
6620 		}
6621 	}
6622 done:
6623 	if (status != MLAN_STATUS_PENDING)
6624 		kfree(req);
6625 	LEAVE();
6626 	return ret;
6627 }
6628 
6629 /**
6630  * @brief Configure gpio independent reset
6631  *
6632  * @param priv         A pointer to moal_private structure
6633  * @param wrq          A pointer to iwreq structure
6634  *
6635  * @return             0 --success, otherwise fail
6636  */
6637 static int
woal_ind_rst_ioctl(moal_private * priv,struct iwreq * wrq)6638 woal_ind_rst_ioctl(moal_private *priv, struct iwreq *wrq)
6639 {
6640 	int data[2], data_length = wrq->u.data.length, copy_len;
6641 	int ret = 0;
6642 	mlan_ds_misc_cfg *misc = NULL;
6643 	mlan_ioctl_req *req = NULL;
6644 	mlan_status status = MLAN_STATUS_SUCCESS;
6645 
6646 	ENTER();
6647 
6648 	if (sizeof(int) * wrq->u.data.length > sizeof(data)) {
6649 		PRINTM(MERROR, "Too many arguments\n");
6650 		ret = -EINVAL;
6651 		goto done;
6652 	}
6653 	copy_len = MIN(sizeof(data), sizeof(int) * data_length);
6654 
6655 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6656 	if (req == NULL) {
6657 		ret = -ENOMEM;
6658 		goto done;
6659 	}
6660 	misc = (mlan_ds_misc_cfg *)req->pbuf;
6661 	memset(misc, 0, sizeof(mlan_ds_misc_cfg));
6662 
6663 	misc->sub_command = MLAN_OID_MISC_IND_RST_CFG;
6664 	req->req_id = MLAN_IOCTL_MISC_CFG;
6665 
6666 	if (data_length == 0) {
6667 		req->action = MLAN_ACT_GET;
6668 	} else if ((data_length == 1) || (data_length == 2)) {
6669 		req->action = MLAN_ACT_SET;
6670 
6671 		if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
6672 			/* copy_from_user failed  */
6673 			PRINTM(MERROR, "S_PARAMS: copy from user failed\n");
6674 			LEAVE();
6675 			return -EINVAL;
6676 		}
6677 
6678 		/* ir_mode */
6679 		if (data[0] < 0 || data[0] > 2) {
6680 			PRINTM(MERROR, "Invalid ir mode parameter (0/1/2)!\n");
6681 			ret = -EINVAL;
6682 			goto done;
6683 		}
6684 		misc->param.ind_rst_cfg.ir_mode = data[0];
6685 
6686 		/* gpio_pin */
6687 		if (data_length == 2) {
6688 			if ((data[1] != 0xFF) && (data[1] < 0 || data[1] > 15)) {
6689 				PRINTM(MERROR,
6690 				       "Invalid gpio pin no (0-15 , 0xFF for default)!\n");
6691 				ret = -EINVAL;
6692 				goto done;
6693 			}
6694 			misc->param.ind_rst_cfg.gpio_pin = data[1];
6695 		}
6696 
6697 	} else {
6698 		ret = -EINVAL;
6699 		goto done;
6700 	}
6701 
6702 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6703 	if (status != MLAN_STATUS_SUCCESS) {
6704 		ret = -EFAULT;
6705 		goto done;
6706 	}
6707 
6708 	data[0] = misc->param.ind_rst_cfg.ir_mode;
6709 	data[1] = misc->param.ind_rst_cfg.gpio_pin;
6710 	wrq->u.data.length = 2;
6711 
6712 	if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) *
6713 			 wrq->u.data.length)) {
6714 		PRINTM(MERROR, "QCONFIG: copy to user failed\n");
6715 		ret = -EFAULT;
6716 		goto done;
6717 	}
6718 
6719 done:
6720 	if (status != MLAN_STATUS_PENDING)
6721 		kfree(req);
6722 	LEAVE();
6723 	return ret;
6724 }
6725 
6726 /********************************************************
6727 			Global Functions
6728 ********************************************************/
6729 /**
6730  *  @brief ioctl function - entry point
6731  *
6732  *  @param dev      A pointer to net_device structure
6733  *  @param req      A pointer to ifreq structure
6734  *  @param cmd      Command
6735  *
6736  *  @return         0 --success, otherwise fail
6737  */
6738 int
woal_wext_do_ioctl(struct net_device * dev,struct ifreq * req,int cmd)6739 woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
6740 {
6741 	moal_private *priv = (moal_private *)netdev_priv(dev);
6742 	struct iwreq *wrq = (struct iwreq *)req;
6743 	int ret = 0;
6744 
6745 	if (!IS_STA_WEXT(cfg80211_wext))
6746 		return -EOPNOTSUPP;
6747 
6748 	ENTER();
6749 
6750 	PRINTM(MINFO, "woal_wext_do_ioctl: ioctl cmd = 0x%x\n", cmd);
6751 	switch (cmd) {
6752 	case WOAL_SETONEINT_GETWORDCHAR:
6753 		switch (wrq->u.data.flags) {
6754 		case WOAL_VERSION:	/* Get driver version */
6755 			ret = woal_get_driver_version(priv, req);
6756 			break;
6757 		case WOAL_VEREXT:	/* Get extended driver version */
6758 			ret = woal_get_driver_verext(priv, req);
6759 			break;
6760 		default:
6761 			ret = -EOPNOTSUPP;
6762 			break;
6763 		}
6764 		break;
6765 	case WOAL_SETNONE_GETNONE:
6766 		switch (wrq->u.data.flags) {
6767 		case WOAL_WARMRESET:
6768 			ret = woal_warm_reset(priv);
6769 			break;
6770 		case WOAL_11D_CLR_CHAN_TABLE:
6771 			ret = woal_11d_clr_chan_table(priv, wrq);
6772 			break;
6773 		default:
6774 			ret = -EOPNOTSUPP;
6775 			break;
6776 		}
6777 		break;
6778 	case WOAL_SETONEINT_GETONEINT:
6779 		switch (wrq->u.data.flags) {
6780 		case WOAL_SET_GET_TXRATE:
6781 			ret = woal_set_get_txrate(priv, wrq);
6782 			break;
6783 		case WOAL_SET_GET_REGIONCODE:
6784 			ret = woal_set_get_regioncode(priv, wrq);
6785 			break;
6786 		case WOAL_SET_RADIO:
6787 			ret = woal_set_get_radio(priv, wrq);
6788 			break;
6789 		case WOAL_WMM_ENABLE:
6790 			ret = woal_wmm_enable_ioctl(priv, wrq);
6791 			break;
6792 		case WOAL_11D_ENABLE:
6793 			ret = woal_11d_enable_ioctl(priv, wrq);
6794 			break;
6795 		case WOAL_SET_GET_QOS_CFG:
6796 			ret = woal_set_get_qos_cfg(priv, wrq);
6797 			break;
6798 #if defined(REASSOCIATION)
6799 		case WOAL_SET_GET_REASSOC:
6800 			ret = woal_set_get_reassoc(priv, wrq);
6801 			break;
6802 #endif /* REASSOCIATION */
6803 		case WOAL_TXBUF_CFG:
6804 			ret = woal_txbuf_cfg(priv, wrq);
6805 			break;
6806 		case WOAL_SET_GET_WWS_CFG:
6807 			ret = woal_wws_cfg(priv, wrq);
6808 			break;
6809 		case WOAL_SLEEP_PD:
6810 			ret = woal_sleep_pd(priv, wrq);
6811 			break;
6812 		case WOAL_FW_WAKEUP_METHOD:
6813 			ret = woal_fw_wakeup_method(priv, wrq);
6814 			break;
6815 		case WOAL_AUTH_TYPE:
6816 			ret = woal_auth_type(priv, wrq);
6817 			break;
6818 		case WOAL_PORT_CTRL:
6819 			ret = woal_port_ctrl(priv, wrq);
6820 			break;
6821 		case WOAL_COALESCING_STATUS:
6822 			ret = woal_coalescing_status_ioctl(priv, wrq);
6823 			break;
6824 #if defined(WIFI_DIRECT_SUPPORT)
6825 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
6826 		case WOAL_SET_GET_BSS_ROLE:
6827 			ret = woal_set_get_bss_role(priv, wrq);
6828 			break;
6829 #endif
6830 #endif
6831 		case WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT:
6832 			ret = woal_set_get_11h_local_pwr_constraint(priv, wrq);
6833 			break;
6834 		case WOAL_MAC_CONTROL:
6835 			ret = woal_mac_control_ioctl(priv, wrq);
6836 			break;
6837 		case WOAL_THERMAL:
6838 			ret = woal_thermal_ioctl(priv, wrq);
6839 			break;
6840 		default:
6841 			ret = -EOPNOTSUPP;
6842 			break;
6843 		}
6844 		break;
6845 
6846 	case WOAL_SET_GET_SIXTEEN_INT:
6847 		switch ((int)wrq->u.data.flags) {
6848 		case WOAL_TX_POWERCFG:
6849 			ret = woal_tx_power_cfg(priv, wrq);
6850 			break;
6851 #ifdef DEBUG_LEVEL1
6852 		case WOAL_DRV_DBG:
6853 			ret = woal_drv_dbg(priv, wrq);
6854 			break;
6855 #endif
6856 		case WOAL_BEACON_INTERVAL:
6857 			ret = woal_beacon_interval(priv, wrq);
6858 			break;
6859 		case WOAL_ATIM_WINDOW:
6860 			ret = woal_atim_window(priv, wrq);
6861 			break;
6862 		case WOAL_SIGNAL:
6863 			ret = woal_get_signal(priv, wrq);
6864 			break;
6865 		case WOAL_DEEP_SLEEP:
6866 			ret = woal_deep_sleep_ioctl(priv, wrq);
6867 			break;
6868 		case WOAL_11N_TX_CFG:
6869 			ret = woal_11n_tx_cfg(priv, wrq);
6870 			break;
6871 		case WOAL_11N_AMSDU_AGGR_CTRL:
6872 			ret = woal_11n_amsdu_aggr_ctrl(priv, wrq);
6873 			break;
6874 		case WOAL_11N_HTCAP_CFG:
6875 			ret = woal_11n_htcap_cfg(priv, wrq);
6876 			break;
6877 		case WOAL_PRIO_TBL:
6878 			ret = woal_11n_prio_tbl(priv, wrq);
6879 			break;
6880 		case WOAL_ADDBA_UPDT:
6881 			ret = woal_addba_para_updt(priv, wrq);
6882 			break;
6883 		case WOAL_ADDBA_REJECT:
6884 			ret = woal_addba_reject(priv, wrq);
6885 			break;
6886 		case WOAL_TX_BF_CAP:
6887 			ret = woal_tx_bf_cap_ioctl(priv, wrq);
6888 			break;
6889 		case WOAL_HS_CFG:
6890 			ret = woal_hs_cfg(priv, wrq, MTRUE);
6891 			break;
6892 		case WOAL_HS_SETPARA:
6893 			ret = woal_hs_setpara(priv, wrq);
6894 			break;
6895 		case WOAL_REG_READ_WRITE:
6896 			ret = woal_reg_read_write(priv, wrq);
6897 			break;
6898 		case WOAL_INACTIVITY_TIMEOUT_EXT:
6899 			ret = woal_inactivity_timeout_ext(priv, wrq);
6900 			break;
6901 		case WOAL_SDIO_CLOCK:
6902 			ret = woal_sdio_clock_ioctl(priv, wrq);
6903 			break;
6904 		case WOAL_CMD_52RDWR:
6905 			ret = woal_cmd52rdwr_ioctl(priv, wrq);
6906 			break;
6907 		case WOAL_BAND_CFG:
6908 			ret = woal_band_cfg(priv, wrq);
6909 			break;
6910 		case WOAL_SCAN_CFG:
6911 			ret = woal_set_get_scan_cfg(priv, wrq);
6912 			break;
6913 		case WOAL_PS_CFG:
6914 			ret = woal_set_get_ps_cfg(priv, wrq);
6915 			break;
6916 		case WOAL_MEM_READ_WRITE:
6917 			ret = woal_mem_read_write(priv, wrq);
6918 			break;
6919 #if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
6920 		case WOAL_SDIO_MPA_CTRL:
6921 			ret = woal_do_sdio_mpa_ctrl(priv, wrq);
6922 			break;
6923 #endif
6924 		case WOAL_SLEEP_PARAMS:
6925 			ret = woal_sleep_params_ioctl(priv, wrq);
6926 			break;
6927 		case WOAL_NET_MONITOR:
6928 			ret = woal_net_monitor_ioctl(priv, wrq);
6929 			break;
6930 #if defined(DFS_TESTING_SUPPORT)
6931 		case WOAL_DFS_TESTING:
6932 			ret = woal_dfs_testing(priv, wrq);
6933 			break;
6934 #endif
6935 		case WOAL_MGMT_FRAME_CTRL:
6936 			ret = woal_mgmt_frame_passthru_ctrl(priv, wrq);
6937 			break;
6938 		case WOAL_CFP_CODE:
6939 			ret = woal_cfp_code(priv, wrq);
6940 			break;
6941 		case WOAL_SET_GET_TX_RX_ANT:
6942 			ret = woal_set_get_tx_rx_ant(priv, wrq);
6943 			break;
6944 		case WOAL_IND_RST_CFG:
6945 			ret = woal_ind_rst_ioctl(priv, wrq);
6946 			break;
6947 		default:
6948 			ret = -EINVAL;
6949 			break;
6950 		}
6951 		break;
6952 
6953 	case WOALGETLOG:
6954 		ret = woal_get_log(priv, wrq);
6955 		break;
6956 
6957 	case WOAL_SET_GET_256_CHAR:
6958 		switch (wrq->u.data.flags) {
6959 		case WOAL_PASSPHRASE:
6960 			ret = woal_passphrase(priv, wrq);
6961 			break;
6962 		case WOAL_ADHOC_AES:
6963 			ret = woal_adhoc_aes_ioctl(priv, wrq);
6964 			break;
6965 		case WOAL_ASSOCIATE:
6966 			ret = woal_associate_ssid_bssid(priv, wrq);
6967 			break;
6968 		case WOAL_WMM_QUEUE_STATUS:
6969 			ret = woal_wmm_queue_status_ioctl(priv, wrq);
6970 			break;
6971 
6972 		case WOAL_WMM_TS_STATUS:
6973 			ret = woal_wmm_ts_status_ioctl(priv, wrq);
6974 			break;
6975 		case WOAL_IP_ADDRESS:
6976 			ret = woal_set_get_ip_addr(priv, wrq);
6977 			break;
6978 		case WOAL_TX_BF_CFG:
6979 			ret = woal_tx_bf_cfg_ioctl(priv, wrq);
6980 			break;
6981 		default:
6982 			ret = -EINVAL;
6983 			break;
6984 		}
6985 		break;
6986 
6987 	case WOAL_SETADDR_GETNONE:
6988 		switch ((int)wrq->u.data.flags) {
6989 		case WOAL_DEAUTH:
6990 			ret = woal_deauth(priv, wrq);
6991 			break;
6992 		default:
6993 			ret = -EINVAL;
6994 			break;
6995 		}
6996 		break;
6997 
6998 	case WOAL_SETNONE_GETTWELVE_CHAR:
6999 		/*
7000 		 * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
7001 		 * in flags of iwreq structure, otherwise it will be in
7002 		 * mode member of iwreq structure.
7003 		 */
7004 		switch ((int)wrq->u.data.flags) {
7005 		case WOAL_WPS_SESSION:
7006 			ret = woal_wps_cfg_ioctl(priv, wrq);
7007 			break;
7008 		default:
7009 			ret = -EINVAL;
7010 			break;
7011 		}
7012 		break;
7013 	case WOAL_SETNONE_GET_FOUR_INT:
7014 		switch ((int)wrq->u.data.flags) {
7015 		case WOAL_DATA_RATE:
7016 			ret = woal_get_txrx_rate(priv, wrq);
7017 			break;
7018 		case WOAL_ESUPP_MODE:
7019 			ret = woal_get_esupp_mode(priv, wrq);
7020 			break;
7021 		default:
7022 			ret = -EINVAL;
7023 			break;
7024 		}
7025 		break;
7026 
7027 	case WOAL_SET_GET_64_INT:
7028 		switch ((int)wrq->u.data.flags) {
7029 		case WOAL_ECL_SYS_CLOCK:
7030 			ret = woal_ecl_sys_clock(priv, wrq);
7031 			break;
7032 		}
7033 
7034 		break;
7035 
7036 	case WOAL_HOST_CMD:
7037 		ret = woal_host_command(priv, wrq);
7038 		break;
7039 	case WOAL_ARP_FILTER:
7040 		ret = woal_arp_filter(priv, wrq);
7041 		break;
7042 	case WOAL_SET_INTS_GET_CHARS:
7043 		switch ((int)wrq->u.data.flags) {
7044 		case WOAL_READ_EEPROM:
7045 			ret = woal_read_eeprom(priv, wrq);
7046 			break;
7047 		}
7048 		break;
7049 	case WOAL_SET_GET_2K_BYTES:
7050 		switch ((int)wrq->u.data.flags) {
7051 		case WOAL_CMD_53RDWR:
7052 			ret = woal_cmd53rdwr_ioctl(priv, wrq);
7053 			break;
7054 		case WOAL_SET_USER_SCAN:
7055 			ret = woal_set_user_scan_ioctl(priv, wrq);
7056 			break;
7057 		case WOAL_GET_SCAN_TABLE:
7058 			ret = woal_get_scan_table_ioctl(priv, wrq);
7059 			break;
7060 		case WOAL_SET_USER_SCAN_EXT:
7061 			ret = woal_set_user_scan_ext_ioctl(priv, wrq);
7062 			break;
7063 		case WOAL_WMM_ADDTS:
7064 			ret = woal_wmm_addts_req_ioctl(priv, wrq);
7065 			break;
7066 		case WOAL_WMM_DELTS:
7067 			ret = woal_wmm_delts_req_ioctl(priv, wrq);
7068 			break;
7069 		case WOAL_WMM_QUEUE_CONFIG:
7070 			ret = woal_wmm_queue_config_ioctl(priv, wrq);
7071 			break;
7072 		case WOAL_WMM_QUEUE_STATS:
7073 			ret = woal_wmm_queue_stats_ioctl(priv, wrq);
7074 			break;
7075 		case WOAL_BYPASSED_PACKET:
7076 			ret = woal_bypassed_packet_ioctl(priv, wrq);
7077 			break;
7078 		default:
7079 			ret = -EINVAL;
7080 			break;
7081 		}
7082 		break;
7083 
7084 #ifdef UAP_WEXT
7085 	case WOAL_FROYO_START:
7086 		break;
7087 	case WOAL_FROYO_WL_FW_RELOAD:
7088 		break;
7089 	case WOAL_FROYO_STOP:
7090 		if (IS_UAP_WEXT(cfg80211_wext) && MLAN_STATUS_SUCCESS !=
7091 		    woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
7092 				    DEF_DEAUTH_REASON_CODE)) {
7093 			ret = -EFAULT;
7094 		}
7095 		break;
7096 #endif
7097 	default:
7098 		ret = -EINVAL;
7099 		break;
7100 	}
7101 
7102 	LEAVE();
7103 	return ret;
7104 }
7105 
7106 /**
7107  *  @brief Get data rates
7108  *
7109  *  @param priv          A pointer to moal_private structure
7110  *  @param wait_option   Wait option
7111  *  @param m_rates       A pointer to moal_802_11_rates structure
7112  *
7113  *  @return              MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
7114  */
7115 mlan_status
woal_get_data_rates(moal_private * priv,t_u8 wait_option,moal_802_11_rates * m_rates)7116 woal_get_data_rates(moal_private *priv, t_u8 wait_option,
7117 		    moal_802_11_rates *m_rates)
7118 {
7119 	int ret = 0;
7120 	mlan_ds_rate *rate = NULL;
7121 	mlan_ioctl_req *req = NULL;
7122 	mlan_status status = MLAN_STATUS_SUCCESS;
7123 	ENTER();
7124 
7125 	/* Allocate an IOCTL request buffer */
7126 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
7127 	if (req == NULL) {
7128 		ret = -ENOMEM;
7129 		goto done;
7130 	}
7131 
7132 	/* Fill request buffer */
7133 	rate = (mlan_ds_rate *)req->pbuf;
7134 	rate->sub_command = MLAN_OID_SUPPORTED_RATES;
7135 	req->req_id = MLAN_IOCTL_RATE;
7136 	req->action = MLAN_ACT_GET;
7137 
7138 	/* Send IOCTL request to MLAN */
7139 	status = woal_request_ioctl(priv, req, wait_option);
7140 	if (status == MLAN_STATUS_SUCCESS) {
7141 		if (m_rates)
7142 			m_rates->num_of_rates =
7143 				woal_copy_rates(m_rates->rates,
7144 						m_rates->num_of_rates,
7145 						rate->param.rates,
7146 						MLAN_SUPPORTED_RATES);
7147 	}
7148 done:
7149 	if (status != MLAN_STATUS_PENDING)
7150 		kfree(req);
7151 	LEAVE();
7152 	return status;
7153 }
7154 
7155 /**
7156  *  @brief Get channel list
7157  *
7158  *  @param priv            A pointer to moal_private structure
7159  *  @param wait_option     Wait option
7160  *  @param chan_list       A pointer to mlan_chan_list structure
7161  *
7162  *  @return                MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
7163  */
7164 mlan_status
woal_get_channel_list(moal_private * priv,t_u8 wait_option,mlan_chan_list * chan_list)7165 woal_get_channel_list(moal_private *priv, t_u8 wait_option,
7166 		      mlan_chan_list *chan_list)
7167 {
7168 	int ret = 0;
7169 	mlan_ds_bss *bss = NULL;
7170 	mlan_ioctl_req *req = NULL;
7171 	mlan_status status = MLAN_STATUS_SUCCESS;
7172 	ENTER();
7173 
7174 	/* Allocate an IOCTL request buffer */
7175 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
7176 	if (req == NULL) {
7177 		ret = -ENOMEM;
7178 		goto done;
7179 	}
7180 
7181 	/* Fill request buffer */
7182 	bss = (mlan_ds_bss *)req->pbuf;
7183 	bss->sub_command = MLAN_OID_BSS_CHANNEL_LIST;
7184 	req->req_id = MLAN_IOCTL_BSS;
7185 	req->action = MLAN_ACT_GET;
7186 
7187 	/* Send IOCTL request to MLAN */
7188 	status = woal_request_ioctl(priv, req, wait_option);
7189 	if (status == MLAN_STATUS_SUCCESS) {
7190 		if (chan_list) {
7191 			memcpy(chan_list, &bss->param.chanlist,
7192 			       sizeof(mlan_chan_list));
7193 		}
7194 	}
7195 done:
7196 	if (status != MLAN_STATUS_PENDING)
7197 		kfree(req);
7198 	LEAVE();
7199 	return status;
7200 }
7201 
7202 /**
7203  *  @brief Handle get info resp
7204  *
7205  *  @param priv     Pointer to moal_private structure
7206  *  @param info     Pointer to mlan_ds_get_info structure
7207  *
7208  *  @return         N/A
7209  */
7210 void
woal_ioctl_get_info_resp(moal_private * priv,mlan_ds_get_info * info)7211 woal_ioctl_get_info_resp(moal_private *priv, mlan_ds_get_info *info)
7212 {
7213 	ENTER();
7214 	switch (info->sub_command) {
7215 	case MLAN_OID_GET_STATS:
7216 		priv->w_stats.discard.fragment = info->param.stats.fcs_error;
7217 		priv->w_stats.discard.retries = info->param.stats.retry;
7218 		priv->w_stats.discard.misc = info->param.stats.ack_failure;
7219 		break;
7220 	case MLAN_OID_GET_SIGNAL:
7221 		if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
7222 			priv->w_stats.qual.level =
7223 				info->param.signal.bcn_rssi_avg;
7224 		if (info->param.signal.selector & BCN_NF_AVG_MASK)
7225 			priv->w_stats.qual.noise =
7226 				info->param.signal.bcn_nf_avg;
7227 		break;
7228 	default:
7229 		break;
7230 	}
7231 	LEAVE();
7232 }
7233 
7234 /**
7235  *  @brief Handle get BSS resp
7236  *
7237  *  @param priv     Pointer to moal_private structure
7238  *  @param bss      Pointer to mlan_ds_bss structure
7239  *
7240  *  @return         N/A
7241  */
7242 void
woal_ioctl_get_bss_resp(moal_private * priv,mlan_ds_bss * bss)7243 woal_ioctl_get_bss_resp(moal_private *priv, mlan_ds_bss *bss)
7244 {
7245 	t_u32 mode = 0;
7246 
7247 	ENTER();
7248 
7249 	switch (bss->sub_command) {
7250 	case MLAN_OID_BSS_MODE:
7251 		if (bss->param.bss_mode == MLAN_BSS_MODE_INFRA)
7252 			mode = IW_MODE_INFRA;
7253 		else if (bss->param.bss_mode == MLAN_BSS_MODE_IBSS)
7254 			mode = IW_MODE_ADHOC;
7255 		else
7256 			mode = IW_MODE_AUTO;
7257 		priv->w_stats.status = mode;
7258 		break;
7259 	default:
7260 		break;
7261 	}
7262 
7263 	LEAVE();
7264 	return;
7265 }
7266