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