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