1 /** @file moal_wext.c
2 *
3 * @brief This file contains wireless extension standard ioctl functions
4 *
5 * Copyright (C) 2008-2017, Marvell International Ltd.
6 *
7 * This software file (the "File") is distributed by Marvell International
8 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9 * (the "License"). You may use, redistribute and/or modify this File in
10 * accordance with the terms and conditions of the License, a copy of which
11 * is available by writing to the Free Software Foundation, Inc.,
12 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14 *
15 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18 * this warranty disclaimer.
19 *
20 */
21
22 /************************************************************************
23 Change log:
24 10/21/2008: initial version
25 ************************************************************************/
26
27 #include "moal_main.h"
28
29 #ifdef STA_SUPPORT
30 /** Approximate amount of data needed to pass a scan result back to iwlist */
31 #define MAX_SCAN_CELL_SIZE \
32 (IW_EV_ADDR_LEN \
33 + MLAN_MAX_SSID_LENGTH \
34 + IW_EV_UINT_LEN \
35 + IW_EV_FREQ_LEN \
36 + IW_EV_QUAL_LEN \
37 + MLAN_MAX_SSID_LENGTH \
38 + IW_EV_PARAM_LEN \
39 + 40) /* 40 for WPAIE */
40 /** Macro for minimum size of scan buffer */
41 #define MIN_ACCEPTED_GET_SCAN_BUF 8000
42
43 /********************************************************
44 Global Variables
45 ********************************************************/
46 extern int hw_test;
47 /********************************************************
48 Local Functions
49 ********************************************************/
50
51 /**
52 * @brief Compare two SSIDs
53 *
54 * @param ssid1 A pointer to ssid to compare
55 * @param ssid2 A pointer to ssid to compare
56 *
57 * @return 0--ssid is same, otherwise is different
58 */
59 static t_s32
woal_ssid_cmp(mlan_802_11_ssid * ssid1,mlan_802_11_ssid * ssid2)60 woal_ssid_cmp(mlan_802_11_ssid *ssid1, mlan_802_11_ssid *ssid2)
61 {
62 ENTER();
63
64 if (!ssid1 || !ssid2) {
65 LEAVE();
66 return -1;
67 }
68 if (ssid1->ssid_len != ssid2->ssid_len) {
69 LEAVE();
70 return -1;
71 }
72
73 LEAVE();
74 return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
75 }
76
77 /**
78 * @brief Sort Channels
79 *
80 * @param freq A pointer to iw_freq structure
81 * @param num Number of Channels
82 *
83 * @return N/A
84 */
85 static inline void
woal_sort_channels(struct iw_freq * freq,int num)86 woal_sort_channels(struct iw_freq *freq, int num)
87 {
88 int i, j;
89 struct iw_freq temp;
90
91 for (i = 0; i < num; i++)
92 for (j = i + 1; j < num; j++)
93 if (freq[i].i > freq[j].i) {
94 temp.i = freq[i].i;
95 temp.m = freq[i].m;
96
97 freq[i].i = freq[j].i;
98 freq[i].m = freq[j].m;
99
100 freq[j].i = temp.i;
101 freq[j].m = temp.m;
102 }
103 }
104
105 /**
106 * @brief Convert RSSI to quality
107 *
108 * @param rssi RSSI in dBm
109 *
110 * @return Quality of the link (0-5)
111 */
112 static t_u8
woal_rssi_to_quality(t_s16 rssi)113 woal_rssi_to_quality(t_s16 rssi)
114 {
115 /** Macro for RSSI range */
116 #define MOAL_RSSI_NO_SIGNAL -90
117 #define MOAL_RSSI_VERY_LOW -80
118 #define MOAL_RSSI_LOW -70
119 #define MOAL_RSSI_GOOD -60
120 #define MOAL_RSSI_VERY_GOOD -50
121 #define MOAL_RSSI_INVALID 0
122 if (rssi <= MOAL_RSSI_NO_SIGNAL || rssi == MOAL_RSSI_INVALID)
123 return 0;
124 else if (rssi <= MOAL_RSSI_VERY_LOW)
125 return 1;
126 else if (rssi <= MOAL_RSSI_LOW)
127 return 2;
128 else if (rssi <= MOAL_RSSI_GOOD)
129 return 3;
130 else if (rssi <= MOAL_RSSI_VERY_GOOD)
131 return 4;
132 else
133 return 5;
134 }
135
136 /**
137 * @brief Set Adapter Node Name
138 *
139 * @param dev A pointer to net_device structure
140 * @param info A pointer to iw_request_info structure
141 * @param dwrq A pointer to iw_point structure
142 * @param extra A pointer to extra data buf
143 *
144 * @return 0 --success, otherwise fail
145 */
146 static int
woal_set_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)147 woal_set_nick(struct net_device *dev, struct iw_request_info *info,
148 struct iw_point *dwrq, char *extra)
149 {
150 moal_private *priv = (moal_private *)netdev_priv(dev);
151 ENTER();
152 /*
153 * Check the size of the string
154 */
155 if (dwrq->length > 16) {
156 LEAVE();
157 return -E2BIG;
158 }
159 memset(priv->nick_name, 0, sizeof(priv->nick_name));
160 memcpy(priv->nick_name, extra, dwrq->length);
161 LEAVE();
162 return 0;
163 }
164
165 /**
166 * @brief Get Adapter Node Name
167 *
168 * @param dev A pointer to net_device structure
169 * @param info A pointer to iw_request_info structure
170 * @param dwrq A pointer to iw_point structure
171 * @param extra A pointer to extra data buf
172 *
173 * @return 0 --success
174 */
175 static int
woal_get_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)176 woal_get_nick(struct net_device *dev, struct iw_request_info *info,
177 struct iw_point *dwrq, char *extra)
178 {
179 moal_private *priv = (moal_private *)netdev_priv(dev);
180 ENTER();
181 /*
182 * Get the Nick Name saved
183 */
184 strncpy(extra, (char *)priv->nick_name, 16);
185 extra[16] = '\0';
186 /*
187 * If none, we may want to get the one that was set
188 */
189
190 /*
191 * Push it out !
192 */
193 dwrq->length = strlen(extra) + 1;
194 LEAVE();
195 return 0;
196 }
197
198 /**
199 * @brief Commit handler: called after a bunch of SET operations
200 *
201 * @param dev A pointer to net_device structure
202 * @param info A pointer to iw_request_info structure
203 * @param cwrq A pointer to char buffer
204 * @param extra A pointer to extra data buf
205 *
206 * @return 0 --success
207 */
208 static int
woal_config_commit(struct net_device * dev,struct iw_request_info * info,char * cwrq,char * extra)209 woal_config_commit(struct net_device *dev,
210 struct iw_request_info *info, char *cwrq, char *extra)
211 {
212 ENTER();
213
214 LEAVE();
215 return 0;
216 }
217
218 /**
219 * @brief Get name
220 *
221 * @param dev A pointer to net_device structure
222 * @param info A pointer to iw_request_info structure
223 * @param cwrq A pointer to char buffer
224 * @param extra A pointer to extra data buf
225 *
226 * @return 0 --success
227 */
228 static int
woal_get_name(struct net_device * dev,struct iw_request_info * info,char * cwrq,char * extra)229 woal_get_name(struct net_device *dev, struct iw_request_info *info,
230 char *cwrq, char *extra)
231 {
232 ENTER();
233 strcpy(cwrq, "IEEE 802.11-DS");
234 LEAVE();
235 return 0;
236 }
237
238 /**
239 * @brief Set frequency
240 *
241 * @param dev A pointer to net_device structure
242 * @param info A pointer to iw_request_info structure
243 * @param fwrq A pointer to iw_freq structure
244 * @param extra A pointer to extra data buf
245 *
246 * @return 0 --success, otherwise fail
247 */
248 static int
woal_set_freq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)249 woal_set_freq(struct net_device *dev, struct iw_request_info *info,
250 struct iw_freq *fwrq, char *extra)
251 {
252 int ret = 0;
253 moal_private *priv = (moal_private *)netdev_priv(dev);
254 mlan_ds_bss *bss = NULL;
255 mlan_ioctl_req *req = NULL;
256 mlan_status status = MLAN_STATUS_SUCCESS;
257
258 ENTER();
259 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
260 if (req == NULL) {
261 ret = -ENOMEM;
262 goto done;
263 }
264 bss = (mlan_ds_bss *)req->pbuf;
265 /*
266 * If setting by frequency, convert to a channel
267 */
268 if (fwrq->e == 1) {
269 long f = fwrq->m / 100000;
270 bss->param.bss_chan.freq = f;
271 } else
272 bss->param.bss_chan.channel = fwrq->m;
273
274 bss->sub_command = MLAN_OID_BSS_CHANNEL;
275 req->req_id = MLAN_IOCTL_BSS;
276 req->action = MLAN_ACT_SET;
277 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
278 if (status != MLAN_STATUS_SUCCESS) {
279 ret = -EFAULT;
280 goto done;
281 }
282 if (MLAN_STATUS_SUCCESS !=
283 woal_change_adhoc_chan(priv, bss->param.bss_chan.channel,
284 MOAL_IOCTL_WAIT))
285 ret = -EFAULT;
286
287 done:
288 if (status != MLAN_STATUS_PENDING)
289 kfree(req);
290 LEAVE();
291 return ret;
292 }
293
294 /**
295 * @brief Get frequency
296 *
297 * @param dev A pointer to net_device structure
298 * @param info A pointer to iw_request_info structure
299 * @param fwrq A pointer to iw_freq structure
300 * @param extra A pointer to extra data buf
301 *
302 * @return 0 --success, otherwise fail
303 */
304 static int
woal_get_freq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)305 woal_get_freq(struct net_device *dev, struct iw_request_info *info,
306 struct iw_freq *fwrq, char *extra)
307 {
308 int ret = 0;
309 moal_private *priv = (moal_private *)netdev_priv(dev);
310 mlan_ds_bss *bss = NULL;
311 mlan_ioctl_req *req = NULL;
312 mlan_status status = MLAN_STATUS_SUCCESS;
313
314 ENTER();
315
316 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
317 if (req == NULL) {
318 ret = -ENOMEM;
319 goto done;
320 }
321 bss = (mlan_ds_bss *)req->pbuf;
322 bss->sub_command = MLAN_OID_BSS_CHANNEL;
323 req->req_id = MLAN_IOCTL_BSS;
324 req->action = MLAN_ACT_GET;
325 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
326 if (status != MLAN_STATUS_SUCCESS) {
327 ret = -EFAULT;
328 goto done;
329 }
330 fwrq->m = (long)bss->param.bss_chan.freq;
331 fwrq->i = (long)bss->param.bss_chan.channel;
332 fwrq->e = 6;
333 fwrq->flags = IW_FREQ_FIXED;
334 done:
335 if (status != MLAN_STATUS_PENDING)
336 kfree(req);
337 LEAVE();
338 return ret;
339 }
340
341 /**
342 * @brief Set wlan mode
343 *
344 * @param dev A pointer to net_device structure
345 * @param info A pointer to iw_request_info structure
346 * @param uwrq Wireless mode to set
347 * @param extra A pointer to extra data buf
348 *
349 * @return 0 --success, otherwise fail
350 */
351 static int
woal_set_bss_mode(struct net_device * dev,struct iw_request_info * info,t_u32 * uwrq,char * extra)352 woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info,
353 t_u32 *uwrq, char *extra)
354 {
355 int ret = 0;
356 moal_private *priv = (moal_private *)netdev_priv(dev);
357 mlan_ds_bss *bss = NULL;
358 mlan_ioctl_req *req = NULL;
359 mlan_status status = MLAN_STATUS_SUCCESS;
360
361 ENTER();
362
363 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
364 if (req == NULL) {
365 ret = -ENOMEM;
366 goto done;
367 }
368 bss = (mlan_ds_bss *)req->pbuf;
369 bss->sub_command = MLAN_OID_BSS_MODE;
370 req->req_id = MLAN_IOCTL_BSS;
371 req->action = MLAN_ACT_SET;
372
373 switch (*uwrq) {
374 case IW_MODE_INFRA:
375 bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
376 break;
377 case IW_MODE_ADHOC:
378 bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
379 break;
380 case IW_MODE_AUTO:
381 bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
382 break;
383 default:
384 ret = -EINVAL;
385 break;
386 }
387 if (ret)
388 goto done;
389 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
390 if (status != MLAN_STATUS_SUCCESS) {
391 ret = -EFAULT;
392 goto done;
393 }
394 done:
395 if (status != MLAN_STATUS_PENDING)
396 kfree(req);
397 LEAVE();
398 return ret;
399 }
400
401 /**
402 * @brief Get current BSSID
403 *
404 * @param dev A pointer to net_device structure
405 * @param info A pointer to iw_request_info structure
406 * @param awrq A pointer to sockaddr structure
407 * @param extra A pointer to extra data buf
408 *
409 * @return 0 --success
410 */
411 static int
woal_get_wap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)412 woal_get_wap(struct net_device *dev, struct iw_request_info *info,
413 struct sockaddr *awrq, char *extra)
414 {
415 int ret = 0;
416 moal_private *priv = (moal_private *)netdev_priv(dev);
417 mlan_bss_info bss_info;
418
419 ENTER();
420
421 memset(&bss_info, 0, sizeof(bss_info));
422
423 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
424
425 if (bss_info.media_connected == MTRUE)
426 memcpy(awrq->sa_data, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
427 else
428 memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
429 awrq->sa_family = ARPHRD_ETHER;
430
431 LEAVE();
432 return ret;
433 }
434
435 /**
436 * @brief Connect to the AP or Ad-hoc Network with specific bssid
437 *
438 * NOTE: Scan should be issued by application before this function is called
439 *
440 * @param dev A pointer to net_device structure
441 * @param info A pointer to iw_request_info structure
442 * @param awrq A pointer to sockaddr structure
443 * @param extra A pointer to extra data buf
444 *
445 * @return 0 --success, otherwise fail
446 */
447 static int
woal_set_wap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)448 woal_set_wap(struct net_device *dev, struct iw_request_info *info,
449 struct sockaddr *awrq, char *extra)
450 {
451 int ret = 0;
452 const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {
453 255, 255, 255, 255, 255, 255
454 };
455 const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {
456 0, 0, 0, 0, 0, 0
457 };
458 moal_private *priv = (moal_private *)netdev_priv(dev);
459 mlan_ssid_bssid ssid_bssid;
460 mlan_bss_info bss_info;
461
462 ENTER();
463
464 if (awrq->sa_family != ARPHRD_ETHER) {
465 ret = -EINVAL;
466 goto done;
467 }
468
469 PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
470 MAC2STR((t_u8 *)awrq->sa_data));
471
472 if (MLAN_STATUS_SUCCESS !=
473 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
474 ret = -EFAULT;
475 goto done;
476 }
477 #ifdef REASSOCIATION
478 /* Cancel re-association */
479 priv->reassoc_required = MFALSE;
480 #endif
481
482 /* zero_mac means disconnect */
483 if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
484 woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
485 DEF_DEAUTH_REASON_CODE);
486 goto done;
487 }
488
489 /* Broadcast MAC means search for best network */
490 memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
491
492 if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
493 /* Check if we are already assoicated to the AP */
494 if (bss_info.media_connected == MTRUE) {
495 if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
496 goto done;
497 }
498 memcpy(&ssid_bssid.bssid, awrq->sa_data, ETH_ALEN);
499 }
500
501 if (MLAN_STATUS_SUCCESS != woal_find_best_network(priv,
502 MOAL_IOCTL_WAIT,
503 &ssid_bssid)) {
504 PRINTM(MERROR,
505 "ASSOC: WAP: MAC address not found in BSSID List\n");
506 ret = -ENETUNREACH;
507 goto done;
508 }
509 /* Zero SSID implies use BSSID to connect */
510 memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
511 if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
512 MOAL_IOCTL_WAIT,
513 &ssid_bssid)) {
514 ret = -EFAULT;
515 goto done;
516 }
517 #ifdef REASSOCIATION
518 memset(&bss_info, 0, sizeof(bss_info));
519 if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
520 MOAL_IOCTL_WAIT,
521 &bss_info)) {
522 ret = -EFAULT;
523 goto done;
524 }
525 memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
526 sizeof(mlan_802_11_ssid));
527 memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid,
528 MLAN_MAC_ADDR_LENGTH);
529 #endif /* REASSOCIATION */
530
531 done:
532
533 LEAVE();
534 return ret;
535 }
536
537 /**
538 * @brief Get wlan mode
539 *
540 * @param dev A pointer to net_device structure
541 * @param info A pointer to iw_request_info structure
542 * @param uwrq A pointer to t_u32 string
543 * @param extra A pointer to extra data buf
544 *
545 * @return 0 --success
546 */
547 static int
woal_get_bss_mode(struct net_device * dev,struct iw_request_info * info,t_u32 * uwrq,char * extra)548 woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info,
549 t_u32 *uwrq, char *extra)
550 {
551 moal_private *priv = (moal_private *)netdev_priv(dev);
552 ENTER();
553 *uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT);
554 LEAVE();
555 return 0;
556 }
557
558 /**
559 * @brief Set sensitivity
560 *
561 * @param dev A pointer to net_device structure
562 * @param info A pointer to iw_request_info structure
563 * @param vwrq A pointer to iw_param structure
564 * @param extra A pointer to extra data buf
565 *
566 * @return 0 --success
567 */
568 static int
woal_set_sens(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)569 woal_set_sens(struct net_device *dev, struct iw_request_info *info,
570 struct iw_param *vwrq, char *extra)
571 {
572 int ret = 0;
573
574 ENTER();
575
576 LEAVE();
577 return ret;
578 }
579
580 /**
581 * @brief Get sensitivity
582 *
583 * @param dev A pointer to net_device structure
584 * @param info A pointer to iw_request_info structure
585 * @param vwrq A pointer to iw_param structure
586 * @param extra A pointer to extra data buf
587 *
588 * @return -1
589 */
590 static int
woal_get_sens(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)591 woal_get_sens(struct net_device *dev, struct iw_request_info *info,
592 struct iw_param *vwrq, char *extra)
593 {
594 int ret = -1;
595
596 ENTER();
597
598 LEAVE();
599 return ret;
600 }
601
602 /**
603 * @brief Set Tx power
604 *
605 * @param dev A pointer to net_device structure
606 * @param info A pointer to iw_request_info structure
607 * @param vwrq A pointer to iw_param structure
608 * @param extra A pointer to extra data buf
609 *
610 * @return 0 --success, otherwise fail
611 */
612 static int
woal_set_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)613 woal_set_txpow(struct net_device *dev, struct iw_request_info *info,
614 struct iw_param *vwrq, char *extra)
615 {
616 int ret = 0;
617 moal_private *priv = (moal_private *)netdev_priv(dev);
618 mlan_power_cfg_t power_cfg;
619
620 ENTER();
621 if (vwrq->disabled) {
622 woal_set_radio(priv, 0);
623 goto done;
624 }
625 woal_set_radio(priv, 1);
626
627 if (!vwrq->fixed)
628 power_cfg.is_power_auto = 1;
629 else {
630 power_cfg.is_power_auto = 0;
631 power_cfg.power_level = vwrq->value;
632 }
633
634 if (MLAN_STATUS_SUCCESS !=
635 woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) {
636 ret = -EFAULT;
637 goto done;
638 }
639
640 done:
641 LEAVE();
642 return ret;
643 }
644
645 /**
646 * @brief Get Tx power
647 *
648 * @param dev A pointer to net_device structure
649 * @param info A pointer to iw_request_info structure
650 * @param vwrq A pointer to iw_param structure
651 * @param extra A pointer to extra data buf
652 *
653 * @return 0 --success, otherwise fail
654 */
655 static int
woal_get_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)656 woal_get_txpow(struct net_device *dev, struct iw_request_info *info,
657 struct iw_param *vwrq, char *extra)
658 {
659 int ret = 0;
660 moal_private *priv = (moal_private *)netdev_priv(dev);
661 mlan_power_cfg_t power_cfg;
662 mlan_bss_info bss_info;
663
664 ENTER();
665
666 memset(&power_cfg, 0, sizeof(mlan_power_cfg_t));
667 memset(&bss_info, 0, sizeof(bss_info));
668 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
669
670 if (MLAN_STATUS_SUCCESS !=
671 woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
672 ret = -EFAULT;
673 goto done;
674 }
675
676 vwrq->value = power_cfg.power_level;
677 if (power_cfg.is_power_auto)
678 vwrq->fixed = 0;
679 else
680 vwrq->fixed = 1;
681 if (bss_info.radio_on) {
682 vwrq->disabled = 0;
683 vwrq->flags = IW_TXPOW_DBM;
684 } else {
685 vwrq->disabled = 1;
686 }
687
688 done:
689 LEAVE();
690 return ret;
691 }
692
693 /**
694 * @brief Set power management
695 *
696 * @param dev A pointer to net_device structure
697 * @param info A pointer to iw_request_info structure
698 * @param vwrq A pointer to iw_param structure
699 * @param extra A pointer to extra data buf
700 *
701 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
702 */
703 static int
woal_set_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)704 woal_set_power(struct net_device *dev, struct iw_request_info *info,
705 struct iw_param *vwrq, char *extra)
706 {
707 int ret = 0, disabled;
708 moal_private *priv = (moal_private *)netdev_priv(dev);
709
710 ENTER();
711
712 if (hw_test) {
713 PRINTM(MIOCTL, "block set power in hw_test mode\n");
714 LEAVE();
715 return ret;
716 }
717 disabled = vwrq->disabled;
718
719 if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
720 MLAN_ACT_SET,
721 &disabled,
722 vwrq->flags,
723 MOAL_IOCTL_WAIT)) {
724 ret = -EFAULT;
725 }
726
727 LEAVE();
728 return ret;
729 }
730
731 /**
732 * @brief Get power management
733 *
734 * @param dev A pointer to net_device structure
735 * @param info A pointer to iw_request_info structure
736 * @param vwrq A pointer to iw_param structure
737 * @param extra A pointer to extra data buf
738 *
739 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
740 */
741 static int
woal_get_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)742 woal_get_power(struct net_device *dev, struct iw_request_info *info,
743 struct iw_param *vwrq, char *extra)
744 {
745 int ret = 0, ps_mode;
746 moal_private *priv = (moal_private *)netdev_priv(dev);
747
748 ENTER();
749
750 if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
751 MLAN_ACT_GET,
752 &ps_mode, 0,
753 MOAL_IOCTL_WAIT)) {
754 ret = -EFAULT;
755 }
756
757 if (ps_mode)
758 vwrq->disabled = 0;
759 else
760 vwrq->disabled = 1;
761
762 vwrq->value = 0;
763
764 LEAVE();
765 return ret;
766 }
767
768 /**
769 * @brief Set Tx retry count
770 *
771 * @param dev A pointer to net_device structure
772 * @param info A pointer to iw_request_info structure
773 * @param vwrq A pointer to iw_param structure
774 * @param extra A pointer to extra data buf
775 *
776 * @return 0 --success, otherwise fail
777 */
778 static int
woal_set_retry(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)779 woal_set_retry(struct net_device *dev, struct iw_request_info *info,
780 struct iw_param *vwrq, char *extra)
781 {
782 int ret = 0, retry_val = vwrq->value;
783 moal_private *priv = (moal_private *)netdev_priv(dev);
784
785 ENTER();
786
787 if (vwrq->flags == IW_RETRY_LIMIT) {
788 /*
789 * The MAC has a 4-bit Total_Tx_Count register
790 * Total_Tx_Count = 1 + Tx_Retry_Count
791 */
792
793 if (MLAN_STATUS_SUCCESS !=
794 woal_set_get_retry(priv, MLAN_ACT_SET,
795 MOAL_IOCTL_WAIT, &retry_val)) {
796 ret = -EFAULT;
797 goto done;
798 }
799 } else {
800 ret = -EOPNOTSUPP;
801 goto done;
802 }
803
804 done:
805 LEAVE();
806 return ret;
807 }
808
809 /**
810 * @brief Get Tx retry count
811 *
812 * @param dev A pointer to net_device structure
813 * @param info A pointer to iw_request_info structure
814 * @param vwrq A pointer to iw_param structure
815 * @param extra A pointer to extra data buf
816 *
817 * @return 0 --success, otherwise fail
818 */
819 static int
woal_get_retry(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)820 woal_get_retry(struct net_device *dev, struct iw_request_info *info,
821 struct iw_param *vwrq, char *extra)
822 {
823 int retry_val, ret = 0;
824 moal_private *priv = (moal_private *)netdev_priv(dev);
825
826 ENTER();
827
828 if (MLAN_STATUS_SUCCESS !=
829 woal_set_get_retry(priv, MLAN_ACT_GET,
830 MOAL_IOCTL_WAIT, &retry_val)) {
831 ret = -EFAULT;
832 goto done;
833 }
834
835 vwrq->disabled = 0;
836 if (!vwrq->flags) {
837 vwrq->flags = IW_RETRY_LIMIT;
838 /* Get Tx retry count */
839 vwrq->value = retry_val;
840 }
841
842 done:
843 LEAVE();
844 return ret;
845 }
846
847 /**
848 * @brief Set encryption key
849 *
850 * @param dev A pointer to net_device structure
851 * @param info A pointer to iw_request_info structure
852 * @param dwrq A pointer to iw_point structure
853 * @param extra A pointer to extra data buf
854 *
855 * @return 0 --success, otherwise fail
856 */
857 static int
woal_set_encode(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)858 woal_set_encode(struct net_device *dev, struct iw_request_info *info,
859 struct iw_point *dwrq, char *extra)
860 {
861 int ret = 0;
862 moal_private *priv = (moal_private *)netdev_priv(dev);
863 mlan_ds_sec_cfg *sec = NULL;
864 mlan_ioctl_req *req = NULL;
865 int index = 0;
866 t_u32 auth_mode = 0;
867 mlan_status status = MLAN_STATUS_SUCCESS;
868
869 ENTER();
870
871 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
872 if (req == NULL) {
873 ret = -ENOMEM;
874 goto done;
875 }
876 sec = (mlan_ds_sec_cfg *)req->pbuf;
877 sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
878 req->req_id = MLAN_IOCTL_SEC_CFG;
879 req->action = MLAN_ACT_SET;
880
881 /* Check index */
882 index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
883 if (index > 3) {
884 PRINTM(MERROR, "Key index #%d out of range\n", index);
885 ret = -EINVAL;
886 goto done;
887 }
888
889 sec->param.encrypt_key.key_len = 0;
890 if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
891 if (dwrq->length > MAX_WEP_KEY_SIZE) {
892 PRINTM(MERROR, "Key length (%d) out of range\n",
893 dwrq->length);
894 ret = -EINVAL;
895 goto done;
896 }
897 if (index < 0)
898 sec->param.encrypt_key.key_index =
899 MLAN_KEY_INDEX_DEFAULT;
900 else
901 sec->param.encrypt_key.key_index = index;
902 memcpy(sec->param.encrypt_key.key_material, extra,
903 dwrq->length);
904 /* Set the length */
905 if (dwrq->length > MIN_WEP_KEY_SIZE)
906 sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE;
907 else
908 sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE;
909 } else {
910 /*
911 * No key provided so it is either enable key,
912 * on or off
913 */
914 if (dwrq->flags & IW_ENCODE_DISABLED) {
915 PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
916 sec->param.encrypt_key.key_disable = MTRUE;
917 } else {
918 /*
919 * iwconfig mlanX key [n]
920 * iwconfig mlanX key on
921 * iwconfig mlanX key open
922 * iwconfig mlanX key restricted
923 * Do we want to just set the transmit key index ?
924 */
925 if (index < 0) {
926 PRINTM(MINFO,
927 "*** iwconfig mlanX key on ***\n");
928 sec->param.encrypt_key.key_index =
929 MLAN_KEY_INDEX_DEFAULT;
930 } else
931 sec->param.encrypt_key.key_index = index;
932 sec->param.encrypt_key.is_current_wep_key = MTRUE;
933 }
934 }
935 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
936 if (status != MLAN_STATUS_SUCCESS) {
937 ret = -EFAULT;
938 goto done;
939 }
940 if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
941 switch (dwrq->flags & 0xf000) {
942 case IW_ENCODE_RESTRICTED:
943 /* iwconfig mlanX restricted key [1] */
944 auth_mode = MLAN_AUTH_MODE_SHARED;
945 PRINTM(MINFO, "Auth mode restricted!\n");
946 break;
947 case IW_ENCODE_OPEN:
948 /* iwconfig mlanX key [2] open */
949 auth_mode = MLAN_AUTH_MODE_OPEN;
950 PRINTM(MINFO, "Auth mode open!\n");
951 break;
952 case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
953 default:
954 /* iwconfig mlanX key [2] open restricted */
955 auth_mode = MLAN_AUTH_MODE_AUTO;
956 PRINTM(MINFO, "Auth mode auto!\n");
957 break;
958 }
959 if (MLAN_STATUS_SUCCESS !=
960 woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
961 ret = -EFAULT;
962 }
963 done:
964 if (status != MLAN_STATUS_PENDING)
965 kfree(req);
966 LEAVE();
967 return ret;
968 }
969
970 /**
971 * @brief Get encryption key
972 *
973 * @param dev A pointer to net_device structure
974 * @param info A pointer to iw_request_info structure
975 * @param dwrq A pointer to iw_point structure
976 * @param extra A pointer to extra data buf
977 *
978 * @return 0 --success, otherwise fail
979 */
980 static int
woal_get_encode(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)981 woal_get_encode(struct net_device *dev, struct iw_request_info *info,
982 struct iw_point *dwrq, char *extra)
983 {
984 int ret = 0;
985 moal_private *priv = (moal_private *)netdev_priv(dev);
986 mlan_ds_sec_cfg *sec = NULL;
987 mlan_ioctl_req *req = NULL;
988 t_u32 auth_mode;
989 int index = (dwrq->flags & IW_ENCODE_INDEX);
990 mlan_status status = MLAN_STATUS_SUCCESS;
991
992 ENTER();
993 if (index < 0 || index > 4) {
994 PRINTM(MERROR, "Key index #%d out of range\n", index);
995 ret = -EINVAL;
996 goto done;
997 }
998 if (MLAN_STATUS_SUCCESS !=
999 woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
1000 ret = -EFAULT;
1001 goto done;
1002 }
1003 dwrq->flags = 0;
1004 /*
1005 * Check encryption mode
1006 */
1007 switch (auth_mode) {
1008 case MLAN_AUTH_MODE_OPEN:
1009 dwrq->flags = IW_ENCODE_OPEN;
1010 break;
1011
1012 case MLAN_AUTH_MODE_SHARED:
1013 case MLAN_AUTH_MODE_NETWORKEAP:
1014 dwrq->flags = IW_ENCODE_RESTRICTED;
1015 break;
1016
1017 case MLAN_AUTH_MODE_AUTO:
1018 dwrq->flags = IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED;
1019 break;
1020
1021 default:
1022 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1023 break;
1024 }
1025 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1026 if (req == NULL) {
1027 ret = -ENOMEM;
1028 goto done;
1029 }
1030
1031 sec = (mlan_ds_sec_cfg *)req->pbuf;
1032 sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
1033 req->req_id = MLAN_IOCTL_SEC_CFG;
1034 req->action = MLAN_ACT_GET;
1035
1036 if (!index)
1037 sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
1038 else
1039 sec->param.encrypt_key.key_index = index - 1;
1040
1041 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1042 if (status != MLAN_STATUS_SUCCESS) {
1043 ret = -EFAULT;
1044 goto done;
1045 }
1046 memset(extra, 0, 16);
1047 if (sec->param.encrypt_key.key_len) {
1048 memcpy(extra, sec->param.encrypt_key.key_material,
1049 sec->param.encrypt_key.key_len);
1050 dwrq->length = sec->param.encrypt_key.key_len;
1051 dwrq->flags |= (sec->param.encrypt_key.key_index + 1);
1052 dwrq->flags &= ~IW_ENCODE_DISABLED;
1053 } else if (sec->param.encrypt_key.key_disable)
1054 dwrq->flags |= IW_ENCODE_DISABLED;
1055 else
1056 dwrq->flags &= ~IW_ENCODE_DISABLED;
1057
1058 dwrq->flags |= IW_ENCODE_NOKEY;
1059 done:
1060 if (status != MLAN_STATUS_PENDING)
1061 kfree(req);
1062 LEAVE();
1063 return ret;
1064 }
1065
1066 /**
1067 * @brief Set data rate
1068 *
1069 * @param dev A pointer to net_device structure
1070 * @param info A pointer to iw_request_info structure
1071 * @param vwrq A pointer to iw_param structure
1072 * @param extra A pointer to extra data buf
1073 *
1074 * @return 0 --success, otherwise fail
1075 */
1076 static int
woal_set_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1077 woal_set_rate(struct net_device *dev, struct iw_request_info *info,
1078 struct iw_param *vwrq, char *extra)
1079 {
1080 int ret = 0;
1081 moal_private *priv = (moal_private *)netdev_priv(dev);
1082 mlan_rate_cfg_t rate_cfg;
1083
1084 ENTER();
1085
1086 if (vwrq->value == -1) {
1087 rate_cfg.is_rate_auto = 1;
1088 } else {
1089 rate_cfg.is_rate_auto = 0;
1090 rate_cfg.rate_type = MLAN_RATE_VALUE;
1091 rate_cfg.rate = vwrq->value / 500000;
1092 }
1093 if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
1094 MLAN_ACT_SET,
1095 &rate_cfg)) {
1096 ret = -EFAULT;
1097 }
1098
1099 LEAVE();
1100 return ret;
1101 }
1102
1103 /**
1104 * @brief Get data rate
1105 *
1106 * @param dev A pointer to net_device structure
1107 * @param info A pointer to iw_request_info structure
1108 * @param vwrq A pointer to iw_param structure
1109 * @param extra A pointer to extra data buf
1110 *
1111 * @return 0 --success, otherwise fail
1112 */
1113 static int
woal_get_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1114 woal_get_rate(struct net_device *dev, struct iw_request_info *info,
1115 struct iw_param *vwrq, char *extra)
1116 {
1117 int ret = 0;
1118 moal_private *priv = (moal_private *)netdev_priv(dev);
1119 mlan_rate_cfg_t rate_cfg;
1120
1121 ENTER();
1122
1123 if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
1124 MLAN_ACT_GET,
1125 &rate_cfg)) {
1126 ret = -EFAULT;
1127 goto done;
1128 }
1129
1130 if (rate_cfg.is_rate_auto)
1131 vwrq->fixed = 0;
1132 else
1133 vwrq->fixed = 1;
1134 vwrq->value = rate_cfg.rate * 500000;
1135 done:
1136 LEAVE();
1137 return ret;
1138 }
1139
1140 /**
1141 * @brief Set RTS threshold
1142 *
1143 * @param dev A pointer to net_device structure
1144 * @param info A pointer to iw_request_info structure
1145 * @param vwrq A pointer to iw_param structure
1146 * @param extra A pointer to extra data buf
1147 *
1148 * @return 0 --success, otherwise fail
1149 */
1150 static int
woal_set_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1151 woal_set_rts(struct net_device *dev, struct iw_request_info *info,
1152 struct iw_param *vwrq, char *extra)
1153 {
1154 int ret = 0;
1155 moal_private *priv = (moal_private *)netdev_priv(dev);
1156 int rthr = vwrq->value;
1157
1158 ENTER();
1159
1160 if (vwrq->disabled) {
1161 rthr = MLAN_RTS_MAX_VALUE;
1162 } else {
1163 if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) {
1164 ret = -EINVAL;
1165 goto done;
1166 }
1167 }
1168
1169 if (MLAN_STATUS_SUCCESS !=
1170 woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rthr)) {
1171 ret = -EFAULT;
1172 goto done;
1173 }
1174
1175 done:
1176 LEAVE();
1177 return ret;
1178 }
1179
1180 /**
1181 * @brief Get RTS threshold
1182 *
1183 * @param dev A pointer to net_device structure
1184 * @param info A pointer to iw_request_info structure
1185 * @param vwrq A pointer to iw_param structure
1186 * @param extra A pointer to extra data buf
1187 *
1188 * @return 0 --success, otherwise fail
1189 */
1190 static int
woal_get_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1191 woal_get_rts(struct net_device *dev, struct iw_request_info *info,
1192 struct iw_param *vwrq, char *extra)
1193 {
1194 int rthr, ret = 0;
1195 moal_private *priv = (moal_private *)netdev_priv(dev);
1196
1197 ENTER();
1198
1199 if (MLAN_STATUS_SUCCESS !=
1200 woal_set_get_rts(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &rthr)) {
1201 ret = -EFAULT;
1202 goto done;
1203 }
1204
1205 vwrq->value = rthr;
1206 vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE)
1207 || (vwrq->value > MLAN_RTS_MAX_VALUE));
1208 vwrq->fixed = 1;
1209
1210 done:
1211 LEAVE();
1212 return ret;
1213 }
1214
1215 /**
1216 * @brief Set Fragment threshold
1217 *
1218 * @param dev A pointer to net_device structure
1219 * @param info A pointer to iw_request_info structure
1220 * @param vwrq A pointer to iw_param structure
1221 * @param extra A pointer to extra data buf
1222 *
1223 * @return 0 --success, otherwise fail
1224 */
1225 static int
woal_set_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1226 woal_set_frag(struct net_device *dev, struct iw_request_info *info,
1227 struct iw_param *vwrq, char *extra)
1228 {
1229 int ret = 0;
1230 moal_private *priv = (moal_private *)netdev_priv(dev);
1231 int fthr = vwrq->value;
1232
1233 ENTER();
1234
1235 if (vwrq->disabled) {
1236 fthr = MLAN_FRAG_MAX_VALUE;
1237 } else {
1238 if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) {
1239 ret = -EINVAL;
1240 goto done;
1241 }
1242 }
1243
1244 if (MLAN_STATUS_SUCCESS !=
1245 woal_set_get_frag(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &fthr)) {
1246 ret = -EFAULT;
1247 goto done;
1248 }
1249
1250 done:
1251 LEAVE();
1252 return ret;
1253 }
1254
1255 /**
1256 * @brief Get Fragment threshold
1257 *
1258 * @param dev A pointer to net_device structure
1259 * @param info A pointer to iw_request_info structure
1260 * @param vwrq A pointer to iw_param structure
1261 * @param extra A pointer to extra data buf
1262 *
1263 * @return 0 --success, otherwise fail
1264 */
1265 static int
woal_get_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1266 woal_get_frag(struct net_device *dev, struct iw_request_info *info,
1267 struct iw_param *vwrq, char *extra)
1268 {
1269 int ret = 0, fthr;
1270 moal_private *priv = (moal_private *)netdev_priv(dev);
1271
1272 ENTER();
1273
1274 if (MLAN_STATUS_SUCCESS !=
1275 woal_set_get_frag(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &fthr)) {
1276 ret = -EFAULT;
1277 goto done;
1278 }
1279
1280 vwrq->value = fthr;
1281 vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE)
1282 || (vwrq->value > MLAN_FRAG_MAX_VALUE));
1283 vwrq->fixed = 1;
1284
1285 done:
1286 LEAVE();
1287 return ret;
1288 }
1289
1290 #if (WIRELESS_EXT >= 18)
1291 /**
1292 * @brief Get IE
1293 *
1294 * @param dev A pointer to net_device structure
1295 * @param info A pointer to iw_request_info structure
1296 * @param dwrq A pointer to iw_point structure
1297 * @param extra A pointer to extra data buf
1298 *
1299 * @return 0 --success, otherwise fail
1300 */
1301 static int
woal_get_gen_ie(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1302 woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
1303 struct iw_point *dwrq, char *extra)
1304 {
1305 int ret = 0;
1306 moal_private *priv = (moal_private *)netdev_priv(dev);
1307 int copy_size = 0, ie_len;
1308 t_u8 ie[MAX_IE_SIZE];
1309
1310 ENTER();
1311
1312 if (MLAN_STATUS_SUCCESS !=
1313 woal_set_get_gen_ie(priv, MLAN_ACT_GET, ie, &ie_len,
1314 MOAL_IOCTL_WAIT)) {
1315 ret = -EFAULT;
1316 goto done;
1317 }
1318
1319 copy_size = MIN(ie_len, dwrq->length);
1320 memcpy(extra, ie, copy_size);
1321 dwrq->length = copy_size;
1322
1323 done:
1324 LEAVE();
1325 return ret;
1326 }
1327
1328 /**
1329 * @brief Set IE
1330 *
1331 * Pass an opaque block of data, expected to be IEEE IEs, to the driver
1332 * for eventual passthrough to the firmware in an associate/join
1333 * (and potentially start) command.
1334 *
1335 * @param dev A pointer to net_device structure
1336 * @param info A pointer to iw_request_info structure
1337 * @param dwrq A pointer to iw_point structure
1338 * @param extra A pointer to extra data buf
1339 *
1340 * @return 0 --success, otherwise fail
1341 */
1342 static int
woal_set_gen_ie(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1343 woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
1344 struct iw_point *dwrq, char *extra)
1345 {
1346 int ret = 0;
1347 moal_private *priv = (moal_private *)netdev_priv(dev);
1348 int ie_len = dwrq->length;
1349 const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
1350 mlan_ds_wps_cfg *pwps = NULL;
1351 mlan_ioctl_req *req = NULL;
1352 mlan_status status = MLAN_STATUS_SUCCESS;
1353
1354 ENTER();
1355
1356 /* extra + 2 to skip element id and length */
1357 if (!memcmp((t_u8 *)(extra + 2), wps_oui, sizeof(wps_oui))) {
1358 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
1359 if (req == NULL) {
1360 ret = -ENOMEM;
1361 goto done;
1362 }
1363
1364 pwps = (mlan_ds_wps_cfg *)req->pbuf;
1365 req->req_id = MLAN_IOCTL_WPS_CFG;
1366 req->action = MLAN_ACT_SET;
1367 pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
1368 pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
1369
1370 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1371 if (status != MLAN_STATUS_SUCCESS) {
1372 ret = -EFAULT;
1373 goto done;
1374 }
1375 }
1376
1377 if (MLAN_STATUS_SUCCESS !=
1378 woal_set_get_gen_ie(priv, MLAN_ACT_SET, (t_u8 *)extra, &ie_len,
1379 MOAL_IOCTL_WAIT)) {
1380 ret = -EFAULT;
1381 goto done;
1382 }
1383
1384 done:
1385 if (status != MLAN_STATUS_PENDING)
1386 kfree(req);
1387
1388 LEAVE();
1389 return ret;
1390 }
1391
1392 /**
1393 * @brief Extended version of encoding configuration
1394 *
1395 * @param dev A pointer to net_device structure
1396 * @param info A pointer to iw_request_info structure
1397 * @param dwrq A pointer to iw_point structure
1398 * @param extra A pointer to extra data buf
1399 *
1400 * @return 0 --success, otherwise fail
1401 */
1402 static int
woal_set_encode_ext(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1403 woal_set_encode_ext(struct net_device *dev,
1404 struct iw_request_info *info,
1405 struct iw_point *dwrq, char *extra)
1406 {
1407 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1408 moal_private *priv = (moal_private *)netdev_priv(dev);
1409 int key_index;
1410 t_u8 *pkey_material = NULL;
1411 mlan_ioctl_req *req = NULL;
1412 mlan_ds_sec_cfg *sec = NULL;
1413 int ret = 0;
1414 mlan_status status = MLAN_STATUS_SUCCESS;
1415
1416 ENTER();
1417 key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1418 if (key_index < 0 || key_index > 5) {
1419 ret = -EINVAL;
1420 goto done;
1421 }
1422 if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
1423 ret = -EINVAL;
1424 goto done;
1425 }
1426 if (ext->key_len > (MLAN_MAX_KEY_LENGTH)) {
1427 ret = -EINVAL;
1428 goto done;
1429 }
1430 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1431 if (req == NULL) {
1432 ret = -ENOMEM;
1433 goto done;
1434 }
1435 sec = (mlan_ds_sec_cfg *)req->pbuf;
1436 sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
1437 req->req_id = MLAN_IOCTL_SEC_CFG;
1438 req->action = MLAN_ACT_SET;
1439 pkey_material = (t_u8 *)(ext + 1);
1440 sec->param.encrypt_key.key_len = ext->key_len;
1441 memcpy(sec->param.encrypt_key.mac_addr, (u8 *)ext->addr.sa_data,
1442 ETH_ALEN);
1443 /* Disable and Remove Key */
1444 if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
1445 sec->param.encrypt_key.key_remove = MTRUE;
1446 sec->param.encrypt_key.key_index = key_index;
1447 sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
1448 PRINTM(MIOCTL,
1449 "Remove key key_index=%d, dwrq->flags=0x%x " MACSTR "\n",
1450 key_index, dwrq->flags,
1451 MAC2STR(sec->param.encrypt_key.mac_addr));
1452 } else if (ext->key_len <= MAX_WEP_KEY_SIZE) {
1453 /* Set WEP key */
1454 sec->param.encrypt_key.key_index = key_index;
1455 sec->param.encrypt_key.key_flags = ext->ext_flags;
1456 memcpy(sec->param.encrypt_key.key_material, pkey_material,
1457 ext->key_len);
1458 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
1459 sec->param.encrypt_key.is_current_wep_key = MTRUE;
1460 } else {
1461 /* Set WPA key */
1462 sec->param.encrypt_key.key_index = key_index;
1463 sec->param.encrypt_key.key_flags = ext->ext_flags;
1464 if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
1465 memcpy(sec->param.encrypt_key.pn, (t_u8 *)ext->rx_seq,
1466 SEQ_MAX_SIZE);
1467 DBG_HEXDUMP(MCMD_D, "Rx PN", sec->param.encrypt_key.pn,
1468 SEQ_MAX_SIZE);
1469 }
1470 if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
1471 memcpy(sec->param.encrypt_key.pn, (t_u8 *)ext->tx_seq,
1472 SEQ_MAX_SIZE);
1473 DBG_HEXDUMP(MCMD_D, "Tx PN", sec->param.encrypt_key.pn,
1474 SEQ_MAX_SIZE);
1475 }
1476 memcpy(sec->param.encrypt_key.key_material, pkey_material,
1477 ext->key_len);
1478 PRINTM(MIOCTL,
1479 "set wpa key key_index=%d, key_len=%d key_flags=0x%x "
1480 MACSTR "\n", key_index, ext->key_len,
1481 sec->param.encrypt_key.key_flags,
1482 MAC2STR(sec->param.encrypt_key.mac_addr));
1483 DBG_HEXDUMP(MCMD_D, "wpa key", pkey_material, ext->key_len);
1484 #define IW_ENCODE_ALG_AES_CMAC 5
1485 if (ext->alg == IW_ENCODE_ALG_AES_CMAC)
1486 sec->param.encrypt_key.key_flags |=
1487 KEY_FLAG_AES_MCAST_IGTK;
1488 #define IW_ENCODE_ALG_SMS4 0x20
1489 /* Set WAPI key */
1490 if (ext->alg == IW_ENCODE_ALG_SMS4) {
1491 sec->param.encrypt_key.is_wapi_key = MTRUE;
1492 memcpy(sec->param.encrypt_key.pn, (t_u8 *)ext->tx_seq,
1493 SEQ_MAX_SIZE);
1494 memcpy(&sec->param.encrypt_key.pn[SEQ_MAX_SIZE],
1495 (t_u8 *)ext->rx_seq, SEQ_MAX_SIZE);
1496 DBG_HEXDUMP(MCMD_D, "WAPI PN",
1497 sec->param.encrypt_key.pn, PN_SIZE);
1498 }
1499 }
1500 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1501 if (status != MLAN_STATUS_SUCCESS)
1502 ret = -EFAULT;
1503 done:
1504 if (status != MLAN_STATUS_PENDING)
1505 kfree(req);
1506 LEAVE();
1507 return ret;
1508 }
1509
1510 /**
1511 * @brief Extended version of encoding configuration
1512 *
1513 * @param dev A pointer to net_device structure
1514 * @param info A pointer to iw_request_info structure
1515 * @param dwrq A pointer to iw_point structure
1516 * @param extra A pointer to extra data buf
1517 *
1518 * @return -EOPNOTSUPP
1519 */
1520 static int
woal_get_encode_ext(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1521 woal_get_encode_ext(struct net_device *dev,
1522 struct iw_request_info *info,
1523 struct iw_point *dwrq, char *extra)
1524 {
1525 ENTER();
1526 LEAVE();
1527 return -EOPNOTSUPP;
1528 }
1529
1530 /**
1531 * @brief Request MLME operation
1532 *
1533 * @param dev A pointer to net_device structure
1534 * @param info A pointer to iw_request_info structure
1535 * @param dwrq A pointer to iw_point structure
1536 * @param extra A pointer to extra data buf
1537 *
1538 * @return 0--success, otherwise fail
1539 */
1540 static int
woal_set_mlme(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1541 woal_set_mlme(struct net_device *dev,
1542 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1543 {
1544 struct iw_mlme *mlme = (struct iw_mlme *)extra;
1545 moal_private *priv = (moal_private *)netdev_priv(dev);
1546 int ret = 0;
1547
1548 ENTER();
1549 if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
1550
1551 if (MLAN_STATUS_SUCCESS !=
1552 woal_disconnect(priv, MOAL_IOCTL_WAIT,
1553 (t_u8 *)mlme->addr.sa_data,
1554 DEF_DEAUTH_REASON_CODE))
1555 ret = -EFAULT;
1556 }
1557 LEAVE();
1558 return ret;
1559 }
1560
1561 /** @brief Set authentication mode parameters
1562 *
1563 * @param dev A pointer to net_device structure
1564 * @param info A pointer to iw_request_info structure
1565 * @param vwrq A pointer to iw_param structure
1566 * @param extra A pointer to extra data buf
1567 *
1568 * @return 0 --success, otherwise fail
1569 */
1570 static int
woal_set_auth(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1571 woal_set_auth(struct net_device *dev, struct iw_request_info *info,
1572 struct iw_param *vwrq, char *extra)
1573 {
1574 int ret = 0;
1575 moal_private *priv = (moal_private *)netdev_priv(dev);
1576 t_u32 auth_mode = 0;
1577 t_u32 encrypt_mode = 0;
1578 ENTER();
1579
1580 switch (vwrq->flags & IW_AUTH_INDEX) {
1581 case IW_AUTH_CIPHER_PAIRWISE:
1582 case IW_AUTH_CIPHER_GROUP:
1583 if (vwrq->value & IW_AUTH_CIPHER_NONE)
1584 encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
1585 else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
1586 encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
1587 else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
1588 encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
1589 else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
1590 encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
1591 else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
1592 encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
1593 if (MLAN_STATUS_SUCCESS !=
1594 woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
1595 ret = -EFAULT;
1596 break;
1597 case IW_AUTH_80211_AUTH_ALG:
1598 switch (vwrq->value) {
1599 case IW_AUTH_ALG_SHARED_KEY:
1600 PRINTM(MINFO, "Auth mode shared key!\n");
1601 auth_mode = MLAN_AUTH_MODE_SHARED;
1602 break;
1603 case IW_AUTH_ALG_LEAP:
1604 PRINTM(MINFO, "Auth mode LEAP!\n");
1605 auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
1606 break;
1607 case IW_AUTH_ALG_OPEN_SYSTEM:
1608 PRINTM(MINFO, "Auth mode open!\n");
1609 auth_mode = MLAN_AUTH_MODE_OPEN;
1610 break;
1611 case IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM:
1612 default:
1613 PRINTM(MINFO, "Auth mode auto!\n");
1614 auth_mode = MLAN_AUTH_MODE_AUTO;
1615 break;
1616 }
1617 if (MLAN_STATUS_SUCCESS !=
1618 woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
1619 ret = -EFAULT;
1620 break;
1621 case IW_AUTH_WPA_ENABLED:
1622 if (MLAN_STATUS_SUCCESS !=
1623 woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
1624 ret = -EFAULT;
1625 break;
1626 #define IW_AUTH_WAPI_ENABLED 0x20
1627 case IW_AUTH_WAPI_ENABLED:
1628 if (MLAN_STATUS_SUCCESS !=
1629 woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
1630 ret = -EFAULT;
1631 break;
1632 case IW_AUTH_WPA_VERSION:
1633 /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
1634 priv->wpa_version = vwrq->value;
1635 break;
1636 case IW_AUTH_KEY_MGMT:
1637 /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
1638 priv->key_mgmt = vwrq->value;
1639 break;
1640 case IW_AUTH_TKIP_COUNTERMEASURES:
1641 case IW_AUTH_DROP_UNENCRYPTED:
1642 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1643 case IW_AUTH_ROAMING_CONTROL:
1644 case IW_AUTH_PRIVACY_INVOKED:
1645 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
1646 case IW_AUTH_MFP:
1647 #endif
1648 break;
1649 default:
1650 ret = -EOPNOTSUPP;
1651 break;
1652 }
1653 LEAVE();
1654 return ret;
1655 }
1656
1657 /**
1658 * @brief Get authentication mode parameters
1659 *
1660 * @param dev A pointer to net_device structure
1661 * @param info A pointer to iw_request_info structure
1662 * @param vwrq A pointer to iw_param structure
1663 * @param extra A pointer to extra data buf
1664 *
1665 * @return 0 --success, otherwise fail
1666 */
1667 static int
woal_get_auth(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1668 woal_get_auth(struct net_device *dev, struct iw_request_info *info,
1669 struct iw_param *vwrq, char *extra)
1670 {
1671 int ret = 0;
1672 moal_private *priv = (moal_private *)netdev_priv(dev);
1673 t_u32 encrypt_mode = 0;
1674 t_u32 auth_mode;
1675 t_u32 wpa_enable;
1676 ENTER();
1677 switch (vwrq->flags & IW_AUTH_INDEX) {
1678 case IW_AUTH_CIPHER_PAIRWISE:
1679 case IW_AUTH_CIPHER_GROUP:
1680 if (MLAN_STATUS_SUCCESS !=
1681 woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode))
1682 ret = -EFAULT;
1683 else {
1684 if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE)
1685 vwrq->value = IW_AUTH_CIPHER_NONE;
1686 else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40)
1687 vwrq->value = IW_AUTH_CIPHER_WEP40;
1688 else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP)
1689 vwrq->value = IW_AUTH_CIPHER_TKIP;
1690 else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP)
1691 vwrq->value = IW_AUTH_CIPHER_CCMP;
1692 else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104)
1693 vwrq->value = IW_AUTH_CIPHER_WEP104;
1694 }
1695 break;
1696 case IW_AUTH_80211_AUTH_ALG:
1697 if (MLAN_STATUS_SUCCESS !=
1698 woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode))
1699 ret = -EFAULT;
1700 else {
1701 if (auth_mode == MLAN_AUTH_MODE_SHARED)
1702 vwrq->value = IW_AUTH_ALG_SHARED_KEY;
1703 else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
1704 vwrq->value = IW_AUTH_ALG_LEAP;
1705 else
1706 vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
1707 }
1708 break;
1709 case IW_AUTH_WPA_ENABLED:
1710 if (MLAN_STATUS_SUCCESS !=
1711 woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable))
1712 ret = -EFAULT;
1713 else
1714 vwrq->value = wpa_enable;
1715 break;
1716 case IW_AUTH_WPA_VERSION:
1717 vwrq->value = priv->wpa_version;
1718 break;
1719 case IW_AUTH_KEY_MGMT:
1720 vwrq->value = priv->key_mgmt;
1721 break;
1722 case IW_AUTH_TKIP_COUNTERMEASURES:
1723 case IW_AUTH_DROP_UNENCRYPTED:
1724 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1725 case IW_AUTH_ROAMING_CONTROL:
1726 case IW_AUTH_PRIVACY_INVOKED:
1727 default:
1728 ret = -EOPNOTSUPP;
1729 goto done;
1730 }
1731
1732 done:
1733 LEAVE();
1734 return ret;
1735 }
1736
1737 /**
1738 * @brief Set PMKSA Cache
1739 *
1740 * @param dev A pointer to net_device structure
1741 * @param info A pointer to iw_request_info structure
1742 * @param vwrq A pointer to iw_param structure
1743 * @param extra A pointer to extra data buf
1744 *
1745 * @return -EOPNOTSUPP
1746 */
1747 static int
woal_set_pmksa(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1748 woal_set_pmksa(struct net_device *dev, struct iw_request_info *info,
1749 struct iw_param *vwrq, char *extra)
1750 {
1751 ENTER();
1752 LEAVE();
1753 return -EOPNOTSUPP;
1754 }
1755
1756 #endif /* WE >= 18 */
1757
1758 /* Data rate listing
1759 * MULTI_BANDS:
1760 * abg a b b/g
1761 * Infra G(12) A(8) B(4) G(12)
1762 * Adhoc A+B(12) A(8) B(4) B(4)
1763 * non-MULTI_BANDS:
1764 b b/g
1765 * Infra B(4) G(12)
1766 * Adhoc B(4) B(4)
1767 */
1768 /**
1769 * @brief Get Range Info
1770 *
1771 * @param dev A pointer to net_device structure
1772 * @param info A pointer to iw_request_info structure
1773 * @param dwrq A pointer to iw_point structure
1774 * @param extra A pointer to extra data buf
1775 *
1776 * @return 0 --success, otherwise fail
1777 */
1778 static int
woal_get_range(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1779 woal_get_range(struct net_device *dev, struct iw_request_info *info,
1780 struct iw_point *dwrq, char *extra)
1781 {
1782 int i;
1783 moal_private *priv = (moal_private *)netdev_priv(dev);
1784 struct iw_range *range = (struct iw_range *)extra;
1785 moal_802_11_rates rates;
1786 mlan_chan_list *pchan_list = NULL;
1787 mlan_bss_info bss_info;
1788 gfp_t flag;
1789
1790 ENTER();
1791
1792 flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
1793 pchan_list = kzalloc(sizeof(mlan_chan_list), flag);
1794 if (!pchan_list) {
1795 LEAVE();
1796 return -ENOMEM;
1797 }
1798
1799 dwrq->length = sizeof(struct iw_range);
1800 memset(range, 0, sizeof(struct iw_range));
1801
1802 range->min_nwid = 0;
1803 range->max_nwid = 0;
1804
1805 memset(&rates, 0, sizeof(rates));
1806 woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates);
1807 range->num_bitrates = rates.num_of_rates;
1808
1809 for (i = 0;
1810 i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i];
1811 i++) {
1812 range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000;
1813 }
1814 range->num_bitrates = i;
1815 PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
1816 range->num_bitrates);
1817
1818 range->num_frequency = 0;
1819
1820 woal_get_channel_list(priv, MOAL_IOCTL_WAIT, pchan_list);
1821
1822 range->num_frequency = MIN(pchan_list->num_of_chan, IW_MAX_FREQUENCIES);
1823
1824 for (i = 0; i < range->num_frequency; i++) {
1825 range->freq[i].i = (long)pchan_list->cf[i].channel;
1826 range->freq[i].m = (long)pchan_list->cf[i].freq * 100000;
1827 range->freq[i].e = 1;
1828 }
1829 kfree(pchan_list);
1830
1831 PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
1832 IW_MAX_FREQUENCIES, range->num_frequency);
1833
1834 range->num_channels = range->num_frequency;
1835
1836 woal_sort_channels(&range->freq[0], range->num_frequency);
1837
1838 /*
1839 * Set an indication of the max TCP throughput in bit/s that we can
1840 * expect using this interface
1841 */
1842 if (i > 2)
1843 range->throughput = 5000 * 1000;
1844 else
1845 range->throughput = 1500 * 1000;
1846
1847 range->min_rts = MLAN_RTS_MIN_VALUE;
1848 range->max_rts = MLAN_RTS_MAX_VALUE;
1849 range->min_frag = MLAN_FRAG_MIN_VALUE;
1850 range->max_frag = MLAN_FRAG_MAX_VALUE;
1851
1852 range->encoding_size[0] = 5;
1853 range->encoding_size[1] = 13;
1854 range->num_encoding_sizes = 2;
1855 range->max_encoding_tokens = 4;
1856
1857 /** Minimum power period */
1858 #define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
1859 /** Maximum power period */
1860 #define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
1861 /** Minimum power timeout value */
1862 #define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
1863 /** Maximim power timeout value */
1864 #define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
1865
1866 /* Power Management duration & timeout */
1867 range->min_pmp = IW_POWER_PERIOD_MIN;
1868 range->max_pmp = IW_POWER_PERIOD_MAX;
1869 range->min_pmt = IW_POWER_TIMEOUT_MIN;
1870 range->max_pmt = IW_POWER_TIMEOUT_MAX;
1871 range->pmp_flags = IW_POWER_PERIOD;
1872 range->pmt_flags = IW_POWER_TIMEOUT;
1873 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
1874
1875 /*
1876 * Minimum version we recommend
1877 */
1878 range->we_version_source = 15;
1879
1880 /*
1881 * Version we are compiled with
1882 */
1883 range->we_version_compiled = WIRELESS_EXT;
1884
1885 range->retry_capa = IW_RETRY_LIMIT;
1886 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
1887
1888 range->min_retry = MLAN_TX_RETRY_MIN;
1889 range->max_retry = MLAN_TX_RETRY_MAX;
1890
1891 /*
1892 * Set the qual, level and noise range values
1893 */
1894 /*
1895 * need to put the right values here
1896 */
1897 /** Maximum quality percentage */
1898 #define IW_MAX_QUAL_PERCENT 5
1899 /** Average quality percentage */
1900 #define IW_AVG_QUAL_PERCENT 3
1901 range->max_qual.qual = IW_MAX_QUAL_PERCENT;
1902 range->max_qual.level = 0;
1903 range->max_qual.noise = 0;
1904
1905 range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
1906 range->avg_qual.level = 0;
1907 range->avg_qual.noise = 0;
1908
1909 range->sensitivity = 0;
1910
1911 /*
1912 * Setup the supported power level ranges
1913 */
1914 memset(range->txpower, 0, sizeof(range->txpower));
1915
1916 memset(&bss_info, 0, sizeof(bss_info));
1917
1918 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1919
1920 range->txpower[0] = bss_info.min_power_level;
1921 range->txpower[1] = bss_info.max_power_level;
1922 range->num_txpower = 2;
1923 range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
1924
1925 #if (WIRELESS_EXT >= 18)
1926 range->enc_capa = IW_ENC_CAPA_WPA |
1927 IW_ENC_CAPA_WPA2 |
1928 IW_ENC_CAPA_CIPHER_CCMP | IW_ENC_CAPA_CIPHER_TKIP;
1929 #endif
1930
1931 LEAVE();
1932 return 0;
1933 }
1934
1935 #ifdef MEF_CFG_RX_FILTER
1936 /**
1937 * @brief Enable/disable Rx broadcast/multicast filter in non-HS mode
1938 *
1939 * @param priv A pointer to moal_private structure
1940 * @param enable MTRUE/MFALSE: enable/disable
1941 *
1942 * @return 0 -- success, otherwise fail
1943 */
1944 static int
woal_set_rxfilter(moal_private * priv,BOOLEAN enable)1945 woal_set_rxfilter(moal_private *priv, BOOLEAN enable)
1946 {
1947 int ret = 0;
1948 mlan_ioctl_req *req = NULL;
1949 mlan_ds_misc_cfg *misc = NULL;
1950 mlan_ds_misc_mef_cfg *mef_cfg = NULL;
1951 mlan_status status = MLAN_STATUS_SUCCESS;
1952
1953 ENTER();
1954
1955 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1956 if (req == NULL) {
1957 ret = -ENOMEM;
1958 goto done;
1959 }
1960 misc = (mlan_ds_misc_cfg *)req->pbuf;
1961 mef_cfg = &misc->param.mef_cfg;
1962 req->req_id = MLAN_IOCTL_MISC_CFG;
1963 misc->sub_command = MLAN_OID_MISC_MEF_CFG;
1964 req->action = MLAN_ACT_SET;
1965
1966 mef_cfg->sub_id = (enable ? MEF_CFG_RX_FILTER_ENABLE : MEF_CFG_DISABLE);
1967 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1968 if (status != MLAN_STATUS_SUCCESS) {
1969 ret = -EFAULT;
1970 goto done;
1971 }
1972
1973 done:
1974 if (status != MLAN_STATUS_PENDING)
1975 kfree(req);
1976 LEAVE();
1977 return ret;
1978 }
1979 #endif
1980
1981 /**
1982 * @brief Set priv command
1983 *
1984 * @param dev A pointer to net_device structure
1985 * @param info A pointer to iw_request_info structure
1986 * @param dwrq A pointer to iw_point structure
1987 * @param extra A pointer to extra data buf
1988 *
1989 * @return 0 --success, otherwise fail
1990 */
1991 static int
woal_set_priv(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1992 woal_set_priv(struct net_device *dev, struct iw_request_info *info,
1993 struct iw_point *dwrq, char *extra)
1994 {
1995 int ret = 0;
1996 moal_private *priv = (moal_private *)netdev_priv(dev);
1997 char *buf = NULL;
1998 int power_mode = 0;
1999 int band = 0;
2000 char *pband = NULL;
2001 mlan_bss_info bss_info;
2002 mlan_ds_get_signal signal;
2003 mlan_rate_cfg_t rate;
2004 char *pdata = NULL;
2005 t_u8 country_code[COUNTRY_CODE_LEN];
2006 int len = 0;
2007 gfp_t flag;
2008 ENTER();
2009 if (!priv || !priv->phandle) {
2010 PRINTM(MERROR, "priv or handle is NULL\n");
2011 ret = -EFAULT;
2012 goto done;
2013 }
2014 flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
2015 buf = kzalloc(dwrq->length + 1, flag);
2016 if (!buf) {
2017 ret = -ENOMEM;
2018 goto done;
2019 }
2020 if (copy_from_user(buf, dwrq->pointer, dwrq->length)) {
2021 ret = -EFAULT;
2022 goto done;
2023 }
2024 PRINTM(MIOCTL, "SIOCSIWPRIV request = %s\n", buf);
2025 if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) {
2026 if (dwrq->length > strlen("RSSILOW-THRESHOLD") + 1) {
2027 pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
2028 if (MLAN_STATUS_SUCCESS !=
2029 woal_set_rssi_low_threshold(priv, pdata,
2030 MOAL_IOCTL_WAIT)) {
2031 ret = -EFAULT;
2032 goto done;
2033 }
2034 len = sprintf(buf, "OK\n") + 1;
2035 } else {
2036 ret = -EFAULT;
2037 goto done;
2038 }
2039 } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
2040 if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
2041 MOAL_IOCTL_WAIT,
2042 &bss_info)) {
2043 ret = -EFAULT;
2044 goto done;
2045 }
2046 if (bss_info.media_connected) {
2047 if (MLAN_STATUS_SUCCESS !=
2048 woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
2049 &signal)) {
2050 ret = -EFAULT;
2051 goto done;
2052 }
2053 len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
2054 signal.bcn_rssi_avg) + 1;
2055 } else {
2056 len = sprintf(buf, "OK\n") + 1;
2057 }
2058 } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
2059 if (MLAN_STATUS_SUCCESS !=
2060 woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
2061 ret = -EFAULT;
2062 goto done;
2063 }
2064 PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
2065 len = sprintf(buf, "LinkSpeed %d\n",
2066 (int)(rate.rate * 500000 / 1000000)) + 1;
2067 } else if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
2068 len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2069 priv->current_addr[0], priv->current_addr[1],
2070 priv->current_addr[2], priv->current_addr[3],
2071 priv->current_addr[4], priv->current_addr[5]) + 1;
2072 } else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
2073 if (MLAN_STATUS_SUCCESS !=
2074 woal_get_powermode(priv, &power_mode)) {
2075 ret = -EFAULT;
2076 goto done;
2077 }
2078 len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
2079 } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
2080 if (MLAN_STATUS_SUCCESS !=
2081 woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
2082 ret = -EFAULT;
2083 goto done;
2084 }
2085 priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
2086 PRINTM(MIOCTL, "Set Active Scan\n");
2087 len = sprintf(buf, "OK\n") + 1;
2088 } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
2089 if (MLAN_STATUS_SUCCESS !=
2090 woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
2091 ret = -EFAULT;
2092 goto done;
2093 }
2094 priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
2095 PRINTM(MIOCTL, "Set Passive Scan\n");
2096 len = sprintf(buf, "OK\n") + 1;
2097 } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
2098 if (dwrq->length > strlen("POWERMODE") + 1) {
2099 pdata = buf + strlen("POWERMODE") + 1;
2100 if (!hw_test) {
2101 if (MLAN_STATUS_SUCCESS !=
2102 woal_set_powermode(priv, pdata)) {
2103 ret = -EFAULT;
2104 goto done;
2105 }
2106 }
2107 len = sprintf(buf, "OK\n") + 1;
2108 } else {
2109 ret = -EFAULT;
2110 goto done;
2111 }
2112 } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
2113 memset(country_code, 0, sizeof(country_code));
2114 if ((strlen(buf) - strlen("COUNTRY") - 1) > COUNTRY_CODE_LEN) {
2115 ret = -EFAULT;
2116 goto done;
2117 }
2118 memcpy(country_code, buf + strlen("COUNTRY") + 1,
2119 COUNTRY_CODE_LEN - 1);
2120 PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
2121 if (MLAN_STATUS_SUCCESS !=
2122 woal_set_region_code(priv, country_code)) {
2123 ret = -EFAULT;
2124 goto done;
2125 }
2126 len = sprintf(buf, "OK\n") + 1;
2127 } else if (memcmp(buf, WEXT_CSCAN_HEADER, strlen(WEXT_CSCAN_HEADER)) ==
2128 0) {
2129 PRINTM(MIOCTL, "Set Combo Scan\n");
2130 if (MLAN_STATUS_SUCCESS !=
2131 woal_set_combo_scan(priv, buf, dwrq->length)) {
2132 ret = -EFAULT;
2133 goto done;
2134 }
2135 len = sprintf(buf, "OK\n") + 1;
2136 } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
2137 if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
2138 ret = -EFAULT;
2139 goto done;
2140 }
2141 len = sprintf(buf, "Band %d\n", band) + 1;
2142 } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
2143 pband = buf + strlen("SETBAND") + 1;
2144 if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
2145 ret = -EFAULT;
2146 goto done;
2147 }
2148 len = sprintf(buf, "OK\n") + 1;
2149 } else if (strncmp(buf, "START", strlen("START")) == 0) {
2150 len = sprintf(buf, "OK\n") + 1;
2151 } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
2152 len = sprintf(buf, "OK\n") + 1;
2153 } else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
2154 /* it will be done by GUI */
2155 len = sprintf(buf, "OK\n") + 1;
2156 } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
2157 len = sprintf(buf, "OK\n") + 1;
2158 } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START"))
2159 == 0) {
2160 len = sprintf(buf, "OK\n") + 1;
2161 } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
2162 0) {
2163 len = sprintf(buf, "OK\n") + 1;
2164 } else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
2165 len = sprintf(buf, "OK\n") + 1;
2166 } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) {
2167 if (MLAN_STATUS_SUCCESS !=
2168 woal_set_bg_scan(priv, buf, dwrq->length)) {
2169 ret = -EFAULT;
2170 goto done;
2171 }
2172 priv->bg_scan_start = MTRUE;
2173 priv->bg_scan_reported = MFALSE;
2174 len = sprintf(buf, "OK\n") + 1;
2175 } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
2176 if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
2177 if (MLAN_STATUS_SUCCESS !=
2178 woal_stop_bg_scan(priv, MOAL_IOCTL_WAIT)) {
2179 ret = -EFAULT;
2180 goto done;
2181 }
2182 priv->bg_scan_start = MFALSE;
2183 priv->bg_scan_reported = MFALSE;
2184 }
2185 len = sprintf(buf, "OK\n") + 1;
2186 } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
2187 0) {
2188 #ifdef MEF_CFG_RX_FILTER
2189 ret = woal_set_rxfilter(priv, MTRUE);
2190 if (ret)
2191 goto done;
2192 #endif
2193 len = sprintf(buf, "OK\n") + 1;
2194 } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) {
2195 #ifdef MEF_CFG_RX_FILTER
2196 ret = woal_set_rxfilter(priv, MFALSE);
2197 if (ret)
2198 goto done;
2199 #endif
2200 len = sprintf(buf, "OK\n") + 1;
2201 } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
2202 if (dwrq->length > strlen("RXFILTER-ADD") + 1) {
2203 pdata = buf + strlen("RXFILTER-ADD") + 1;
2204 if (MLAN_STATUS_SUCCESS !=
2205 woal_add_rxfilter(priv, pdata)) {
2206 ret = -EFAULT;
2207 goto done;
2208 }
2209 len = sprintf(buf, "OK\n") + 1;
2210 } else {
2211 ret = -EFAULT;
2212 goto done;
2213 }
2214 } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
2215 0) {
2216 if (dwrq->length > strlen("RXFILTER-REMOVE") + 1) {
2217 pdata = buf + strlen("RXFILTER-REMOVE") + 1;
2218 if (MLAN_STATUS_SUCCESS !=
2219 woal_remove_rxfilter(priv, pdata)) {
2220 ret = -EFAULT;
2221 goto done;
2222 }
2223 len = sprintf(buf, "OK\n") + 1;
2224 } else {
2225 ret = -EFAULT;
2226 goto done;
2227 }
2228 } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
2229 if (dwrq->length > strlen("QOSINFO") + 1) {
2230 pdata = buf + strlen("QOSINFO") + 1;
2231 if (MLAN_STATUS_SUCCESS !=
2232 woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
2233 ret = -EFAULT;
2234 goto done;
2235 }
2236 len = sprintf(buf, "OK\n") + 1;
2237 } else {
2238 ret = -EFAULT;
2239 goto done;
2240 }
2241 } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
2242 if (dwrq->length > strlen("SLEEPPD") + 1) {
2243 pdata = buf + strlen("SLEEPPD") + 1;
2244 if (MLAN_STATUS_SUCCESS !=
2245 woal_set_sleeppd(priv, pdata)) {
2246 ret = -EFAULT;
2247 goto done;
2248 }
2249 len = sprintf(buf, "OK\n") + 1;
2250 } else {
2251 ret = -EFAULT;
2252 goto done;
2253 }
2254 } else {
2255 PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
2256 ret = -EFAULT;
2257 goto done;
2258 }
2259 PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
2260 dwrq->length = (t_u16)len;
2261 if (copy_to_user(dwrq->pointer, buf, dwrq->length))
2262 ret = -EFAULT;
2263 done:
2264 kfree(buf);
2265 LEAVE();
2266 return ret;
2267 }
2268
2269 /**
2270 * @brief Scan Network
2271 *
2272 * @param dev A pointer to net_device structure
2273 * @param info A pointer to iw_request_info structure
2274 * @param vwrq A pointer to iw_param structure
2275 * @param extra A pointer to extra data buf
2276 *
2277 * @return 0--success, otherwise fail
2278 */
2279 static int
woal_set_scan(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2280 woal_set_scan(struct net_device *dev, struct iw_request_info *info,
2281 struct iw_param *vwrq, char *extra)
2282 {
2283 int ret = 0;
2284 moal_private *priv = (moal_private *)netdev_priv(dev);
2285 moal_handle *handle = priv->phandle;
2286 #if WIRELESS_EXT >= 18
2287 struct iw_scan_req *req;
2288 struct iw_point *dwrq = (struct iw_point *)vwrq;
2289 #endif
2290 mlan_802_11_ssid req_ssid;
2291
2292 ENTER();
2293 if (handle->scan_pending_on_block == MTRUE) {
2294 PRINTM(MINFO, "scan already in processing...\n");
2295 LEAVE();
2296 return ret;
2297 }
2298 #ifdef REASSOCIATION
2299 if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2300 PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n");
2301 LEAVE();
2302 return -EBUSY;
2303 }
2304 #endif /* REASSOCIATION */
2305 priv->report_scan_result = MTRUE;
2306
2307 memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
2308
2309 #if WIRELESS_EXT >= 18
2310 if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
2311 (dwrq->length == sizeof(struct iw_scan_req))) {
2312 req = (struct iw_scan_req *)extra;
2313
2314 if (req->essid_len <= MLAN_MAX_SSID_LENGTH) {
2315
2316 req_ssid.ssid_len = req->essid_len;
2317 memcpy(req_ssid.ssid,
2318 (t_u8 *)req->essid, req->essid_len);
2319 if (MLAN_STATUS_SUCCESS !=
2320 woal_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
2321 ret = -EFAULT;
2322 goto done;
2323 }
2324 }
2325 } else {
2326 #endif
2327 if (MLAN_STATUS_SUCCESS !=
2328 woal_request_scan(priv, MOAL_NO_WAIT, NULL)) {
2329 ret = -EFAULT;
2330 goto done;
2331 }
2332 #if WIRELESS_EXT >= 18
2333 }
2334 #endif
2335
2336 if (priv->phandle->surprise_removed) {
2337 ret = -EFAULT;
2338 goto done;
2339 }
2340
2341 done:
2342 #ifdef REASSOCIATION
2343 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2344 #endif
2345
2346 LEAVE();
2347 return ret;
2348 }
2349
2350 /**
2351 * @brief Set essid
2352 *
2353 * @param dev A pointer to net_device structure
2354 * @param info A pointer to iw_request_info structure
2355 * @param dwrq A pointer to iw_point structure
2356 * @param extra A pointer to extra data buf
2357 *
2358 * @return 0--success, otherwise fail
2359 */
2360 static int
woal_set_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2361 woal_set_essid(struct net_device *dev, struct iw_request_info *info,
2362 struct iw_point *dwrq, char *extra)
2363 {
2364 moal_private *priv = (moal_private *)netdev_priv(dev);
2365 mlan_802_11_ssid req_ssid;
2366 mlan_ssid_bssid ssid_bssid;
2367 #ifdef REASSOCIATION
2368 moal_handle *handle = priv->phandle;
2369 mlan_bss_info bss_info;
2370 #endif
2371 int ret = 0;
2372 t_u32 mode = 0;
2373
2374 ENTER();
2375
2376 #ifdef REASSOCIATION
2377 /* Cancel re-association */
2378 priv->reassoc_required = MFALSE;
2379
2380 if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2381 PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
2382 LEAVE();
2383 return -EBUSY;
2384 }
2385 #endif /* REASSOCIATION */
2386
2387 /* Check the size of the string */
2388 if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
2389 ret = -E2BIG;
2390 goto setessid_ret;
2391 }
2392 if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
2393 woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
2394 memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
2395 memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
2396
2397 #if WIRELESS_EXT > 20
2398 req_ssid.ssid_len = dwrq->length;
2399 #else
2400 req_ssid.ssid_len = dwrq->length - 1;
2401 #endif
2402
2403 /*
2404 * Check if we asked for `any' or 'particular'
2405 */
2406 if (!dwrq->flags) {
2407 #ifdef REASSOCIATION
2408 if (!req_ssid.ssid_len) {
2409 memset(&priv->prev_ssid_bssid.ssid, 0x00,
2410 sizeof(mlan_802_11_ssid));
2411 memset(&priv->prev_ssid_bssid.bssid, 0x00,
2412 MLAN_MAC_ADDR_LENGTH);
2413 goto setessid_ret;
2414 }
2415 #endif
2416 /* Do normal SSID scanning */
2417 if (MLAN_STATUS_SUCCESS !=
2418 woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
2419 ret = -EFAULT;
2420 goto setessid_ret;
2421 }
2422 } else {
2423 /* Set the SSID */
2424 memcpy(req_ssid.ssid, extra,
2425 MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
2426 if (!req_ssid.ssid_len ||
2427 (MFALSE == woal_ssid_valid(&req_ssid))) {
2428 PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
2429 ret = -EINVAL;
2430 goto setessid_ret;
2431 }
2432
2433 PRINTM(MINFO, "Requested new SSID = %s\n",
2434 (char *)req_ssid.ssid);
2435 memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
2436 if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
2437 PRINTM(MIOCTL, "Already connect to the network\n");
2438 goto setessid_ret;
2439 }
2440
2441 if (dwrq->flags != 0xFFFF) {
2442 if (MLAN_STATUS_SUCCESS !=
2443 woal_find_essid(priv, &ssid_bssid,
2444 MOAL_IOCTL_WAIT)) {
2445 /* Do specific SSID scanning */
2446 if (MLAN_STATUS_SUCCESS !=
2447 woal_request_scan(priv, MOAL_IOCTL_WAIT,
2448 &req_ssid)) {
2449 ret = -EFAULT;
2450 goto setessid_ret;
2451 }
2452 }
2453 }
2454
2455 }
2456
2457 mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
2458 if (mode == IW_MODE_ADHOC)
2459 /* disconnect before try to associate */
2460 woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
2461 DEF_DEAUTH_REASON_CODE);
2462
2463 if (mode != IW_MODE_ADHOC) {
2464 if (MLAN_STATUS_SUCCESS !=
2465 woal_find_best_network(priv, MOAL_IOCTL_WAIT,
2466 &ssid_bssid)) {
2467 ret = -EFAULT;
2468 goto setessid_ret;
2469 }
2470 if (MLAN_STATUS_SUCCESS !=
2471 woal_11d_check_ap_channel(priv, MOAL_IOCTL_WAIT,
2472 &ssid_bssid)) {
2473 PRINTM(MERROR,
2474 "The AP's channel is invalid for current region\n");
2475 ret = -EFAULT;
2476 goto setessid_ret;
2477 }
2478 } else if (MLAN_STATUS_SUCCESS !=
2479 woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
2480 /* Adhoc start, Check the channel command */
2481 woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
2482
2483 /* Connect to BSS by ESSID */
2484 memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
2485
2486 if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
2487 MOAL_IOCTL_WAIT,
2488 &ssid_bssid)) {
2489 ret = -EFAULT;
2490 goto setessid_ret;
2491 }
2492 #ifdef REASSOCIATION
2493 memset(&bss_info, 0, sizeof(bss_info));
2494 if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
2495 MOAL_IOCTL_WAIT,
2496 &bss_info)) {
2497 ret = -EFAULT;
2498 goto setessid_ret;
2499 }
2500 memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
2501 sizeof(mlan_802_11_ssid));
2502 memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid,
2503 MLAN_MAC_ADDR_LENGTH);
2504 #endif /* REASSOCIATION */
2505
2506 setessid_ret:
2507 if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
2508 woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
2509 #ifdef REASSOCIATION
2510 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2511 #endif
2512
2513 LEAVE();
2514 return ret;
2515 }
2516
2517 /**
2518 * @brief Get current essid
2519 *
2520 * @param dev A pointer to net_device structure
2521 * @param info A pointer to iw_request_info structure
2522 * @param dwrq A pointer to iw_point structure
2523 * @param extra A pointer to extra data buf
2524 *
2525 * @return 0--success, otherwise fail
2526 */
2527 static int
woal_get_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2528 woal_get_essid(struct net_device *dev, struct iw_request_info *info,
2529 struct iw_point *dwrq, char *extra)
2530 {
2531 moal_private *priv = (moal_private *)netdev_priv(dev);
2532 mlan_bss_info bss_info;
2533 int ret = 0;
2534
2535 ENTER();
2536
2537 memset(&bss_info, 0, sizeof(bss_info));
2538
2539 if (MLAN_STATUS_SUCCESS !=
2540 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2541 ret = -EFAULT;
2542 goto done;
2543 }
2544
2545 if (bss_info.media_connected) {
2546 dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len);
2547 memcpy(extra, bss_info.ssid.ssid, dwrq->length);
2548 } else
2549 dwrq->length = 0;
2550
2551 if (bss_info.scan_table_idx)
2552 dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX;
2553 else
2554 dwrq->flags = 1;
2555
2556 done:
2557 LEAVE();
2558 return ret;
2559 }
2560
2561 /**
2562 * @brief Retrieve the scan table entries via wireless tools IOCTL call
2563 *
2564 * @param dev A pointer to net_device structure
2565 * @param info A pointer to iw_request_info structure
2566 * @param dwrq A pointer to iw_point structure
2567 * @param extra A pointer to extra data buf
2568 *
2569 * @return 0--success, otherwise fail
2570 */
2571 static int
woal_get_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2572 woal_get_scan(struct net_device *dev, struct iw_request_info *info,
2573 struct iw_point *dwrq, char *extra)
2574 {
2575 moal_private *priv = (moal_private *)netdev_priv(dev);
2576 int ret = 0;
2577 char *current_ev = extra;
2578 char *end_buf = extra + IW_SCAN_MAX_DATA;
2579 char *current_val; /* For rates */
2580 struct iw_event iwe; /* Temporary buffer */
2581 unsigned int i;
2582 unsigned int j;
2583 mlan_scan_resp scan_resp;
2584 mlan_bss_info bss_info;
2585 BSSDescriptor_t *scan_table;
2586 mlan_ds_get_signal rssi;
2587 t_u16 buf_size = 16 + 256 * 2;
2588 char *buf = NULL;
2589 char *ptr;
2590 #if WIRELESS_EXT >= 18
2591 t_u8 *praw_data;
2592 #endif
2593 int beacon_size;
2594 t_u8 *pbeacon;
2595 IEEEtypes_ElementId_e element_id;
2596 t_u8 element_len;
2597 gfp_t flag;
2598
2599 ENTER();
2600
2601 if (priv->phandle->scan_pending_on_block == MTRUE) {
2602 LEAVE();
2603 return -EAGAIN;
2604 }
2605 flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
2606 buf = kzalloc((buf_size), flag);
2607 if (!buf) {
2608 PRINTM(MERROR, "Cannot allocate buffer!\n");
2609 ret = -EFAULT;
2610 goto done;
2611 }
2612
2613 memset(&bss_info, 0, sizeof(bss_info));
2614 if (MLAN_STATUS_SUCCESS !=
2615 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2616 ret = -EFAULT;
2617 goto done;
2618 }
2619 memset(&scan_resp, 0, sizeof(scan_resp));
2620 if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
2621 MOAL_IOCTL_WAIT,
2622 &scan_resp)) {
2623 ret = -EFAULT;
2624 goto done;
2625 }
2626 scan_table = (BSSDescriptor_t *)scan_resp.pscan_table;
2627 if (dwrq->length)
2628 end_buf = extra + dwrq->length;
2629 if (priv->media_connected == MTRUE)
2630 PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid);
2631 PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n",
2632 (int)scan_resp.num_in_scan_table);
2633
2634 #if WIRELESS_EXT > 13
2635 /* The old API using SIOCGIWAPLIST had a hard limit of
2636 * IW_MAX_AP. The new API using SIOCGIWSCAN is only
2637 * limited by buffer size WE-14 -> WE-16 the buffer is
2638 * limited to IW_SCAN_MAX_DATA bytes which is 4096.
2639 */
2640 for (i = 0; i < MIN(scan_resp.num_in_scan_table, 64); i++) {
2641 if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
2642 PRINTM(MINFO,
2643 "i=%d break out: current_ev=%p end_buf=%p "
2644 "MAX_SCAN_CELL_SIZE=%d\n", i, current_ev,
2645 end_buf, (t_u32)MAX_SCAN_CELL_SIZE);
2646 ret = -E2BIG;
2647 break;
2648 }
2649 if (!scan_table[i].freq) {
2650 PRINTM(MWARN, "Invalid channel number %d\n",
2651 (int)scan_table[i].channel);
2652 continue;
2653 }
2654 PRINTM(MINFO, "i=%d Ssid: %-32s\n", i,
2655 scan_table[i].ssid.ssid);
2656
2657 /* check ssid is valid or not, ex. hidden ssid will be filter out */
2658 if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE)
2659 continue;
2660
2661 /* First entry *MUST* be the AP MAC address */
2662 iwe.cmd = SIOCGIWAP;
2663 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
2664 memcpy(iwe.u.ap_addr.sa_data, &scan_table[i].mac_address,
2665 ETH_ALEN);
2666
2667 iwe.len = IW_EV_ADDR_LEN;
2668 current_ev =
2669 IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2670 iwe.len);
2671
2672 /* Add the ESSID */
2673 iwe.u.data.length = scan_table[i].ssid.ssid_len;
2674
2675 if (iwe.u.data.length > 32)
2676 iwe.u.data.length = 32;
2677
2678 iwe.cmd = SIOCGIWESSID;
2679 iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
2680 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2681 current_ev =
2682 IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2683 (char *)scan_table[i].ssid.ssid);
2684
2685 /* Add mode */
2686 iwe.cmd = SIOCGIWMODE;
2687 if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS)
2688 iwe.u.mode = IW_MODE_ADHOC;
2689 else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA)
2690 iwe.u.mode = IW_MODE_MASTER;
2691 else
2692 iwe.u.mode = IW_MODE_AUTO;
2693
2694 iwe.len = IW_EV_UINT_LEN;
2695 current_ev =
2696 IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2697 iwe.len);
2698
2699 /* Frequency */
2700 iwe.cmd = SIOCGIWFREQ;
2701 iwe.u.freq.m = (long)scan_table[i].freq;
2702 iwe.u.freq.e = 6;
2703 iwe.u.freq.flags = IW_FREQ_FIXED;
2704 iwe.len = IW_EV_FREQ_LEN;
2705 current_ev =
2706 IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2707 iwe.len);
2708
2709 memset(&iwe, 0, sizeof(iwe));
2710 /* Add quality statistics */
2711 iwe.cmd = IWEVQUAL;
2712 iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi);
2713 if (!bss_info.bcn_nf_last)
2714 iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
2715 else
2716 iwe.u.qual.noise = bss_info.bcn_nf_last;
2717
2718 if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
2719 !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
2720 && bss_info.adhoc_state == ADHOC_STARTED) {
2721 memset(&rssi, 0, sizeof(mlan_ds_get_signal));
2722 if (MLAN_STATUS_SUCCESS !=
2723 woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
2724 &rssi)) {
2725 ret = -EFAULT;
2726 break;
2727 }
2728 iwe.u.qual.level = rssi.data_rssi_avg;
2729 }
2730 iwe.u.qual.qual =
2731 woal_rssi_to_quality((t_s16)(iwe.u.qual.level - 0x100));
2732 iwe.len = IW_EV_QUAL_LEN;
2733 current_ev =
2734 IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2735 iwe.len);
2736
2737 /* Add encryption capability */
2738 iwe.cmd = SIOCGIWENCODE;
2739 if (scan_table[i].privacy)
2740 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
2741 else
2742 iwe.u.data.flags = IW_ENCODE_DISABLED;
2743
2744 iwe.u.data.length = 0;
2745 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2746 current_ev =
2747 IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2748 NULL);
2749
2750 current_val = current_ev + IW_EV_LCP_LEN;
2751
2752 iwe.cmd = SIOCGIWRATE;
2753
2754 iwe.u.bitrate.fixed = 0;
2755 iwe.u.bitrate.disabled = 0;
2756 iwe.u.bitrate.value = 0;
2757
2758 /* Bit rate given in 500 kb/s units (+ 0x80) */
2759 for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
2760 if (!scan_table[i].supported_rates[j])
2761 break;
2762
2763 iwe.u.bitrate.value =
2764 (scan_table[i].supported_rates[j] & 0x7f) *
2765 500000;
2766 iwe.len = IW_EV_PARAM_LEN;
2767 current_val =
2768 IWE_STREAM_ADD_VALUE(info, current_ev,
2769 current_val, end_buf, &iwe,
2770 iwe.len);
2771
2772 }
2773 if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
2774 !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
2775 && bss_info.adhoc_state == ADHOC_STARTED) {
2776 iwe.u.bitrate.value = 22 * 500000;
2777 iwe.len = IW_EV_PARAM_LEN;
2778 current_val =
2779 IWE_STREAM_ADD_VALUE(info, current_ev,
2780 current_val, end_buf, &iwe,
2781 iwe.len);
2782 }
2783
2784 /* Check if an event is added */
2785 if ((unsigned int)(current_val - current_ev) >= IW_EV_PARAM_LEN)
2786 current_ev = current_val;
2787
2788 /* Beacon Interval */
2789 memset(&iwe, 0, sizeof(iwe));
2790 ptr = buf;
2791 ptr += sprintf(ptr, "Beacon interval=%d",
2792 scan_table[i].beacon_period);
2793
2794 iwe.u.data.length = strlen(buf);
2795 iwe.cmd = IWEVCUSTOM;
2796 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2797 current_ev =
2798 IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2799 buf);
2800 current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
2801
2802 /* Parse and send the IEs */
2803 pbeacon = scan_table[i].pbeacon_buf;
2804 beacon_size = scan_table[i].beacon_buf_size;
2805
2806 /* Skip time stamp, beacon interval and capability */
2807 if (pbeacon) {
2808 pbeacon += sizeof(scan_table[i].beacon_period) +
2809 sizeof(scan_table[i].time_stamp) +
2810 sizeof(scan_table[i].cap_info);
2811 beacon_size -= sizeof(scan_table[i].beacon_period) +
2812 sizeof(scan_table[i].time_stamp) +
2813 sizeof(scan_table[i].cap_info);
2814
2815 while ((unsigned int)beacon_size >=
2816 sizeof(IEEEtypes_Header_t)) {
2817 element_id =
2818 (IEEEtypes_ElementId_e)(*(t_u8 *)
2819 pbeacon);
2820 element_len = *((t_u8 *)pbeacon + 1);
2821 if ((unsigned int)beacon_size <
2822 (unsigned int)element_len +
2823 sizeof(IEEEtypes_Header_t)) {
2824 PRINTM(MERROR,
2825 "Get scan: Error in processing IE, "
2826 "bytes left < IE length\n");
2827 break;
2828 }
2829
2830 switch (element_id) {
2831 #if WIRELESS_EXT >= 18
2832 case VENDOR_SPECIFIC_221:
2833 case RSN_IE:
2834 case WAPI_IE:
2835 praw_data = (t_u8 *)pbeacon;
2836 memset(&iwe, 0, sizeof(iwe));
2837 memset(buf, 0, buf_size);
2838 ptr = buf;
2839 memcpy(buf, praw_data,
2840 element_len +
2841 sizeof(IEEEtypes_Header_t));
2842 iwe.cmd = IWEVGENIE;
2843 iwe.u.data.length =
2844 element_len +
2845 sizeof(IEEEtypes_Header_t);
2846 iwe.len =
2847 IW_EV_POINT_LEN +
2848 iwe.u.data.length;
2849 current_ev =
2850 IWE_STREAM_ADD_POINT(info,
2851 current_ev,
2852 end_buf,
2853 &iwe, buf);
2854 current_val =
2855 current_ev + IW_EV_LCP_LEN +
2856 strlen(buf);
2857 break;
2858 #endif
2859 default:
2860 break;
2861 }
2862 pbeacon +=
2863 element_len +
2864 sizeof(IEEEtypes_Header_t);
2865 beacon_size -=
2866 element_len +
2867 sizeof(IEEEtypes_Header_t);
2868 }
2869 }
2870 #if WIRELESS_EXT > 14
2871 memset(&iwe, 0, sizeof(iwe));
2872 memset(buf, 0, buf_size);
2873 ptr = buf;
2874 ptr += sprintf(ptr, "band=");
2875 memset(&iwe, 0, sizeof(iwe));
2876 if (scan_table[i].bss_band == BAND_A)
2877 ptr += sprintf(ptr, "a");
2878 else
2879 ptr += sprintf(ptr, "bg");
2880 iwe.u.data.length = strlen(buf);
2881 PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length);
2882 PRINTM(MINFO, "BUF: %s\n", buf);
2883 iwe.cmd = IWEVCUSTOM;
2884 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2885 current_ev =
2886 IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2887 buf);
2888 current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
2889 #endif
2890 current_val = current_ev + IW_EV_LCP_LEN;
2891
2892 /*
2893 * Check if we added any event
2894 */
2895 if ((unsigned int)(current_val - current_ev) > IW_EV_LCP_LEN)
2896 current_ev = current_val;
2897 }
2898
2899 dwrq->length = (current_ev - extra);
2900 dwrq->flags = 0;
2901 #endif
2902
2903 done:
2904 kfree(buf);
2905 LEAVE();
2906 return ret;
2907 }
2908
2909 /**
2910 * iwconfig settable callbacks
2911 */
2912 static const iw_handler woal_handler[] = {
2913 (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */
2914 (iw_handler) woal_get_name, /* SIOCGIWNAME */
2915 (iw_handler) NULL, /* SIOCSIWNWID */
2916 (iw_handler) NULL, /* SIOCGIWNWID */
2917 (iw_handler) woal_set_freq, /* SIOCSIWFREQ */
2918 (iw_handler) woal_get_freq, /* SIOCGIWFREQ */
2919 (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */
2920 (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */
2921 (iw_handler) woal_set_sens, /* SIOCSIWSENS */
2922 (iw_handler) woal_get_sens, /* SIOCGIWSENS */
2923 (iw_handler) NULL, /* SIOCSIWRANGE */
2924 (iw_handler) woal_get_range, /* SIOCGIWRANGE */
2925 (iw_handler) woal_set_priv, /* SIOCSIWPRIV */
2926 (iw_handler) NULL, /* SIOCGIWPRIV */
2927 (iw_handler) NULL, /* SIOCSIWSTATS */
2928 (iw_handler) NULL, /* SIOCGIWSTATS */
2929 #if WIRELESS_EXT > 15
2930 #ifdef CONFIG_WEXT_SPY
2931 iw_handler_set_spy, /* SIOCSIWSPY */
2932 iw_handler_get_spy, /* SIOCGIWSPY */
2933 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2934 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2935 #else
2936 (iw_handler) NULL, /* -- hole -- */
2937 (iw_handler) NULL, /* -- hole -- */
2938 (iw_handler) NULL, /* -- hole -- */
2939 (iw_handler) NULL, /* -- hole -- */
2940 #endif
2941 #else /* WIRELESS_EXT > 15 */
2942 (iw_handler) NULL, /* -- hole -- */
2943 (iw_handler) NULL, /* -- hole -- */
2944 (iw_handler) NULL, /* -- hole -- */
2945 (iw_handler) NULL, /* -- hole -- */
2946 #endif /* WIRELESS_EXT > 15 */
2947 (iw_handler) woal_set_wap, /* SIOCSIWAP */
2948 (iw_handler) woal_get_wap, /* SIOCGIWAP */
2949 #if WIRELESS_EXT >= 18
2950 (iw_handler) woal_set_mlme, /* SIOCSIWMLME */
2951 #else
2952 (iw_handler) NULL, /* -- hole -- */
2953 #endif
2954 /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */
2955 NULL, /* SIOCGIWAPLIST */
2956 #if WIRELESS_EXT > 13
2957 (iw_handler) woal_set_scan, /* SIOCSIWSCAN */
2958 (iw_handler) woal_get_scan, /* SIOCGIWSCAN */
2959 #else /* WIRELESS_EXT > 13 */
2960 (iw_handler) NULL, /* SIOCSIWSCAN */
2961 (iw_handler) NULL, /* SIOCGIWSCAN */
2962 #endif /* WIRELESS_EXT > 13 */
2963 (iw_handler) woal_set_essid, /* SIOCSIWESSID */
2964 (iw_handler) woal_get_essid, /* SIOCGIWESSID */
2965 (iw_handler) woal_set_nick, /* SIOCSIWNICKN */
2966 (iw_handler) woal_get_nick, /* SIOCGIWNICKN */
2967 (iw_handler) NULL, /* -- hole -- */
2968 (iw_handler) NULL, /* -- hole -- */
2969 (iw_handler) woal_set_rate, /* SIOCSIWRATE */
2970 (iw_handler) woal_get_rate, /* SIOCGIWRATE */
2971 (iw_handler) woal_set_rts, /* SIOCSIWRTS */
2972 (iw_handler) woal_get_rts, /* SIOCGIWRTS */
2973 (iw_handler) woal_set_frag, /* SIOCSIWFRAG */
2974 (iw_handler) woal_get_frag, /* SIOCGIWFRAG */
2975 (iw_handler) woal_set_txpow, /* SIOCSIWTXPOW */
2976 (iw_handler) woal_get_txpow, /* SIOCGIWTXPOW */
2977 (iw_handler) woal_set_retry, /* SIOCSIWRETRY */
2978 (iw_handler) woal_get_retry, /* SIOCGIWRETRY */
2979 (iw_handler) woal_set_encode, /* SIOCSIWENCODE */
2980 (iw_handler) woal_get_encode, /* SIOCGIWENCODE */
2981 (iw_handler) woal_set_power, /* SIOCSIWPOWER */
2982 (iw_handler) woal_get_power, /* SIOCGIWPOWER */
2983 #if (WIRELESS_EXT >= 18)
2984 (iw_handler) NULL, /* -- hole -- */
2985 (iw_handler) NULL, /* -- hole -- */
2986 (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */
2987 (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */
2988 (iw_handler) woal_set_auth, /* SIOCSIWAUTH */
2989 (iw_handler) woal_get_auth, /* SIOCGIWAUTH */
2990 (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */
2991 (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */
2992 (iw_handler) woal_set_pmksa, /* SIOCSIWPMKSA */
2993 #endif /* WIRELESSS_EXT >= 18 */
2994 };
2995
2996 /**
2997 * iwpriv settable callbacks
2998 */
2999 static const iw_handler woal_private_handler[] = {
3000 NULL, /* SIOCIWFIRSTPRIV */
3001 };
3002 #endif /* STA_SUPPORT */
3003
3004 /********************************************************
3005 Global Functions
3006 ********************************************************/
3007
3008 #if WIRELESS_EXT > 14
3009
3010 /**
3011 * @brief This function sends customized event to application.
3012 *
3013 * @param priv A pointer to moal_private structure
3014 * @param str A pointer to event string
3015 *
3016 * @return N/A
3017 */
3018 void
woal_send_iwevcustom_event(moal_private * priv,char * str)3019 woal_send_iwevcustom_event(moal_private *priv, char *str)
3020 {
3021 union iwreq_data iwrq;
3022 char buf[IW_CUSTOM_MAX];
3023
3024 ENTER();
3025
3026 memset(&iwrq, 0, sizeof(union iwreq_data));
3027 memset(buf, 0, sizeof(buf));
3028
3029 snprintf(buf, sizeof(buf) - 1, "%s", str);
3030
3031 iwrq.data.pointer = buf;
3032 iwrq.data.length = strlen(buf) + 1;
3033
3034 /* Send Event to upper layer */
3035 wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf);
3036 PRINTM(MINFO, "Wireless event %s is sent to application\n", str);
3037
3038 LEAVE();
3039 return;
3040 }
3041 #endif
3042
3043 #if WIRELESS_EXT >= 18
3044 /**
3045 * @brief This function sends mic error event to application.
3046 *
3047 * @param priv A pointer to moal_private structure
3048 * @param event MIC MERROR EVENT.
3049 *
3050 * @return N/A
3051 */
3052 void
woal_send_mic_error_event(moal_private * priv,t_u32 event)3053 woal_send_mic_error_event(moal_private *priv, t_u32 event)
3054 {
3055 union iwreq_data iwrq;
3056 struct iw_michaelmicfailure mic;
3057
3058 ENTER();
3059
3060 memset(&iwrq, 0, sizeof(iwrq));
3061 memset(&mic, 0, sizeof(mic));
3062 if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI)
3063 mic.flags = IW_MICFAILURE_PAIRWISE;
3064 else
3065 mic.flags = IW_MICFAILURE_GROUP;
3066 iwrq.data.pointer = &mic;
3067 iwrq.data.length = sizeof(mic);
3068
3069 wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq,
3070 (char *)&mic);
3071
3072 LEAVE();
3073 return;
3074 }
3075 #endif
3076
3077 #ifdef STA_SUPPORT
3078 /** wlan_handler_def */
3079 struct iw_handler_def woal_handler_def = {
3080 num_standard:ARRAY_SIZE(woal_handler),
3081 num_private:ARRAY_SIZE(woal_private_handler),
3082 num_private_args:ARRAY_SIZE(woal_private_args),
3083 standard:(iw_handler *) woal_handler,
3084 private:(iw_handler *) woal_private_handler,
3085 private_args:(struct iw_priv_args *)woal_private_args,
3086 #if WIRELESS_EXT > 20
3087 get_wireless_stats:woal_get_wireless_stats,
3088 #endif
3089 };
3090
3091 /**
3092 * @brief Get wireless statistics
3093 *
3094 * @param dev A pointer to net_device structure
3095 *
3096 * @return A pointer to iw_statistics buf
3097 */
3098 struct iw_statistics *
woal_get_wireless_stats(struct net_device * dev)3099 woal_get_wireless_stats(struct net_device *dev)
3100 {
3101 moal_private *priv = (moal_private *)netdev_priv(dev);
3102 t_u16 wait_option = MOAL_IOCTL_WAIT;
3103
3104 ENTER();
3105
3106 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
3107 /*
3108 * Since schedule() is not allowed from an atomic context
3109 * such as when dev_base_lock for netdevices is acquired
3110 * for reading/writing in kernel before this call, HostCmd
3111 * is issued in non-blocking way in such contexts and
3112 * blocking in other cases.
3113 */
3114 if (in_atomic() || !write_can_lock(&dev_base_lock))
3115 wait_option = MOAL_NO_WAIT;
3116 #endif
3117
3118 priv->w_stats.status = woal_get_mode(priv, wait_option);
3119 priv->w_stats.discard.retries = priv->stats.tx_errors;
3120 priv->w_stats.qual.qual = 0;
3121
3122 /* Send RSSI command to get beacon RSSI/NF, valid only if associated */
3123 if (priv->media_connected == MTRUE) {
3124 if (MLAN_STATUS_SUCCESS ==
3125 woal_get_signal_info(priv, wait_option, NULL))
3126 priv->w_stats.qual.qual =
3127 woal_rssi_to_quality((t_s16)
3128 (priv->w_stats.qual.level -
3129 0x100));
3130 }
3131 #if WIRELESS_EXT > 18
3132 priv->w_stats.qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
3133 #else
3134 priv->w_stats.qual.updated |= 7;
3135 #endif
3136 if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE)
3137 priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
3138
3139 PRINTM(MINFO, "Link Quality = %#x\n", priv->w_stats.qual.qual);
3140 PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level);
3141 PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise);
3142 priv->w_stats.discard.code = 0;
3143 woal_get_stats_info(priv, wait_option, NULL);
3144
3145 LEAVE();
3146 return &priv->w_stats;
3147 }
3148 #endif /* STA_SUPPORT */
3149