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