aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_iw.c')
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c8894
1 files changed, 8894 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
new file mode 100644
index 00000000000..d60c21c0367
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -0,0 +1,8894 @@
1/*
2 * Linux Wireless Extensions support
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 $
25 */
26
27#include <wlioctl.h>
28
29#include <typedefs.h>
30#include <linuxver.h>
31#include <osl.h>
32
33#include <bcmutils.h>
34#include <bcmendian.h>
35#include <proto/ethernet.h>
36
37#include <linux/if_arp.h>
38#include <asm/uaccess.h>
39
40#include <dngl_stats.h>
41#include <dhd.h>
42#include <dhdioctl.h>
43
44typedef void wlc_info_t;
45typedef void wl_info_t;
46typedef const struct si_pub si_t;
47#include <wlioctl.h>
48
49#include <proto/ethernet.h>
50#include <dngl_stats.h>
51#include <dhd.h>
52#define WL_ERROR(x) printf x
53#define WL_TRACE(x)
54#define WL_ASSOC(x)
55#define WL_INFORM(x)
56#define WL_WSEC(x)
57#define WL_SCAN(x)
58
59
60#ifdef PNO_SET_DEBUG
61#define WL_PNO(x) printf x
62#else
63#define WL_PNO(x)
64#endif
65
66
67#define JF2MS jiffies_to_msecs(jiffies)
68
69#ifdef COEX_DBG
70#define WL_TRACE_COEX(x) printf("TS:%lu ", JF2MS); \
71 printf x
72#else
73#define WL_TRACE_COEX(x)
74#endif
75
76#ifdef SCAN_DBG
77#define WL_TRACE_SCAN(x) printf("TS:%lu ", JF2MS); \
78 printf x
79#else
80#define WL_TRACE_SCAN(x)
81#endif
82
83
84#include <wl_iw.h>
85
86
87
88
89#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
90
91#include <linux/rtnetlink.h>
92
93#define WL_IW_USE_ISCAN 1
94#define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1
95
96#ifdef OEM_CHROMIUMOS
97bool g_set_essid_before_scan = TRUE;
98#endif
99
100#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
101 struct mutex g_wl_ss_scan_lock;
102#endif
103
104#if defined(SOFTAP)
105#define WL_SOFTAP(x)
106static struct net_device *priv_dev;
107extern bool ap_cfg_running;
108extern bool ap_fw_loaded;
109struct net_device *ap_net_dev = NULL;
110tsk_ctl_t ap_eth_ctl;
111static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap);
112static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac);
113#endif
114
115
116#define WL_IW_IOCTL_CALL(func_call) \
117 do { \
118 func_call; \
119 } while (0)
120
121#define RETURN_IF_EXTRA_NULL(extra) \
122 if (!extra) { \
123 WL_ERROR(("%s: error : extra is null pointer\n", __FUNCTION__)); \
124 return -EINVAL; \
125 }
126
127static int g_onoff = G_WLAN_SET_ON;
128wl_iw_extra_params_t g_wl_iw_params;
129
130
131#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
132
133static struct mutex wl_cache_lock;
134static struct mutex wl_softap_lock;
135
136#define DHD_OS_MUTEX_INIT(a) mutex_init(a)
137#define DHD_OS_MUTEX_LOCK(a) mutex_lock(a)
138#define DHD_OS_MUTEX_UNLOCK(a) mutex_unlock(a)
139
140#else
141
142#define DHD_OS_MUTEX_INIT(a)
143#define DHD_OS_MUTEX_LOCK(a)
144#define DHD_OS_MUTEX_UNLOCK(a)
145
146#endif
147
148#include <bcmsdbus.h>
149extern void dhd_customer_gpio_wlan_ctrl(int onoff);
150extern uint dhd_dev_reset(struct net_device *dev, uint8 flag);
151extern int dhd_dev_init_ioctl(struct net_device *dev);
152
153uint wl_msg_level = WL_ERROR_VAL;
154
155#define MAX_WLIW_IOCTL_LEN 1024
156
157
158#define htod32(i) i
159#define htod16(i) i
160#define dtoh32(i) i
161#define dtoh16(i) i
162#define htodchanspec(i) i
163#define dtohchanspec(i) i
164
165extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
166extern int dhd_wait_pend8021x(struct net_device *dev);
167
168#if WIRELESS_EXT < 19
169#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
170#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
171#endif
172
173static void *g_scan = NULL;
174static volatile uint g_scan_specified_ssid;
175static wlc_ssid_t g_specific_ssid;
176
177static wlc_ssid_t g_ssid;
178
179#ifdef CONFIG_WPS2
180static char *g_wps_probe_req_ie;
181static int g_wps_probe_req_ie_len;
182#endif
183
184bool btcoex_is_sco_active(struct net_device *dev);
185static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl;
186#if defined(CONFIG_FIRST_SCAN)
187static volatile uint g_first_broadcast_scan;
188static volatile uint g_first_counter_scans;
189#define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3
190#endif
191
192#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
193#define DAEMONIZE(a) daemonize(a); \
194 allow_signal(SIGKILL); \
195 allow_signal(SIGTERM);
196#else
197#define RAISE_RX_SOFTIRQ() \
198 cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
199#define DAEMONIZE(a) daemonize(); \
200 do { if (a) \
201 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
202 } while (0);
203#endif
204
205#if defined(WL_IW_USE_ISCAN)
206#if !defined(CSCAN)
207static void wl_iw_free_ss_cache(void);
208static int wl_iw_run_ss_cache_timer(int kick_off);
209#endif
210#if defined(CONFIG_FIRST_SCAN)
211int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
212#endif
213static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len);
214#define ISCAN_STATE_IDLE 0
215#define ISCAN_STATE_SCANING 1
216
217
218#define WLC_IW_ISCAN_MAXLEN 2048
219typedef struct iscan_buf {
220 struct iscan_buf * next;
221 char iscan_buf[WLC_IW_ISCAN_MAXLEN];
222} iscan_buf_t;
223
224typedef struct iscan_info {
225 struct net_device *dev;
226 struct timer_list timer;
227 uint32 timer_ms;
228 uint32 timer_on;
229 int iscan_state;
230 iscan_buf_t * list_hdr;
231 iscan_buf_t * list_cur;
232
233
234 tsk_ctl_t tsk_ctl;
235
236 uint32 scan_flag;
237#if defined CSCAN
238 char ioctlbuf[WLC_IOCTL_MEDLEN];
239#else
240 char ioctlbuf[WLC_IOCTL_SMLEN];
241#endif
242
243 wl_iscan_params_t *iscan_ex_params_p;
244 int iscan_ex_param_size;
245} iscan_info_t;
246
247
248
249#define COEX_DHCP 1
250#ifdef COEX_DHCP
251
252#define BT_DHCP_eSCO_FIX
253#define BT_DHCP_USE_FLAGS
254#define BT_DHCP_OPPORTUNITY_WINDOW_TIME 2500
255#define BT_DHCP_FLAG_FORCE_TIME 5500
256
257
258
259static int wl_iw_set_btcoex_dhcp(
260 struct net_device *dev,
261 struct iw_request_info *info,
262 union iwreq_data *wrqu,
263 char *extra
264);
265
266static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
267static void wl_iw_bt_release(void);
268
269typedef enum bt_coex_status {
270 BT_DHCP_IDLE = 0,
271 BT_DHCP_START,
272 BT_DHCP_OPPORTUNITY_WINDOW,
273 BT_DHCP_FLAG_FORCE_TIMEOUT
274} coex_status_t;
275
276
277typedef struct bt_info {
278 struct net_device *dev;
279 struct timer_list timer;
280 uint32 timer_ms;
281 uint32 timer_on;
282 uint32 ts_dhcp_start;
283 uint32 ts_dhcp_ok;
284 bool dhcp_done;
285 int bt_state;
286
287
288 tsk_ctl_t tsk_ctl;
289
290} bt_info_t;
291
292bt_info_t *g_bt = NULL;
293static void wl_iw_bt_timerfunc(ulong data);
294#endif
295iscan_info_t *g_iscan = NULL;
296void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
297static void wl_iw_timerfunc(ulong data);
298static void wl_iw_set_event_mask(struct net_device *dev);
299static int
300wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action);
301#endif
302
303static int
304wl_iw_set_scan(
305 struct net_device *dev,
306 struct iw_request_info *info,
307 union iwreq_data *wrqu,
308 char *extra
309);
310
311#ifndef CSCAN
312static int
313wl_iw_get_scan(
314 struct net_device *dev,
315 struct iw_request_info *info,
316 struct iw_point *dwrq,
317 char *extra
318);
319
320static uint
321wl_iw_get_scan_prep(
322 wl_scan_results_t *list,
323 struct iw_request_info *info,
324 char *extra,
325 short max_size
326);
327#endif
328
329static void
330swap_key_from_BE(
331 wl_wsec_key_t *key
332)
333{
334 key->index = htod32(key->index);
335 key->len = htod32(key->len);
336 key->algo = htod32(key->algo);
337 key->flags = htod32(key->flags);
338 key->rxiv.hi = htod32(key->rxiv.hi);
339 key->rxiv.lo = htod16(key->rxiv.lo);
340 key->iv_initialized = htod32(key->iv_initialized);
341}
342
343static void
344swap_key_to_BE(
345 wl_wsec_key_t *key
346)
347{
348 key->index = dtoh32(key->index);
349 key->len = dtoh32(key->len);
350 key->algo = dtoh32(key->algo);
351 key->flags = dtoh32(key->flags);
352 key->rxiv.hi = dtoh32(key->rxiv.hi);
353 key->rxiv.lo = dtoh16(key->rxiv.lo);
354 key->iv_initialized = dtoh32(key->iv_initialized);
355}
356
357static int
358dev_wlc_ioctl(
359 struct net_device *dev,
360 int cmd,
361 void *arg,
362 int len
363)
364{
365 struct ifreq ifr;
366 wl_ioctl_t ioc;
367 mm_segment_t fs;
368 int ret = -EINVAL;
369
370 if (!dev) {
371 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
372 return ret;
373 }
374
375 net_os_wake_lock(dev);
376
377 WL_INFORM(("%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n",
378 __FUNCTION__, current->pid, cmd, arg, len));
379
380 if (g_onoff == G_WLAN_SET_ON) {
381 memset(&ioc, 0, sizeof(ioc));
382 ioc.cmd = cmd;
383 ioc.buf = arg;
384 ioc.len = len;
385
386 strcpy(ifr.ifr_name, dev->name);
387 ifr.ifr_data = (caddr_t) &ioc;
388
389
390 ret = dev_open(dev);
391 if (ret) {
392 WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret));
393 net_os_wake_unlock(dev);
394 return ret;
395 }
396
397 fs = get_fs();
398 set_fs(get_ds());
399#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)
400 ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
401#else
402 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
403#endif
404 set_fs(fs);
405 }
406 else {
407 WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__));
408 }
409
410 net_os_wake_unlock(dev);
411
412 return ret;
413}
414
415
416static int
417dev_wlc_intvar_get_reg(
418 struct net_device *dev,
419 char *name,
420 uint reg,
421 int *retval)
422{
423 union {
424 char buf[WLC_IOCTL_SMLEN];
425 int val;
426 } var;
427 int error;
428
429 uint len;
430 len = bcm_mkiovar(name, (char *)(&reg), sizeof(reg), (char *)(&var), sizeof(var.buf));
431 ASSERT(len);
432 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
433
434 *retval = dtoh32(var.val);
435 return (error);
436}
437
438
439static int
440dev_wlc_intvar_set_reg(
441 struct net_device *dev,
442 char *name,
443 char *addr,
444 char * val)
445{
446 char reg_addr[8];
447
448 memset(reg_addr, 0, sizeof(reg_addr));
449 memcpy((char *)&reg_addr[0], (char *)addr, 4);
450 memcpy((char *)&reg_addr[4], (char *)val, 4);
451
452 return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
453}
454
455
456
457
458static int
459dev_wlc_intvar_set(
460 struct net_device *dev,
461 char *name,
462 int val)
463{
464 char buf[WLC_IOCTL_SMLEN];
465 uint len;
466
467 val = htod32(val);
468 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
469 ASSERT(len);
470
471 return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
472}
473
474#if defined(WL_IW_USE_ISCAN)
475static int
476dev_iw_iovar_setbuf(
477 struct net_device *dev,
478 char *iovar,
479 void *param,
480 int paramlen,
481 void *bufptr,
482 int buflen)
483{
484 int iolen;
485
486 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
487 ASSERT(iolen);
488
489 if (iolen == 0)
490 return 0;
491
492 return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen));
493}
494
495static int
496dev_iw_iovar_getbuf(
497 struct net_device *dev,
498 char *iovar,
499 void *param,
500 int paramlen,
501 void *bufptr,
502 int buflen)
503{
504 int iolen;
505
506 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
507 ASSERT(iolen);
508
509 return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen));
510}
511#endif
512
513
514#if WIRELESS_EXT > 17
515static int
516dev_wlc_bufvar_set(
517 struct net_device *dev,
518 char *name,
519 char *buf, int len)
520{
521#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
522 char ioctlbuf[MAX_WLIW_IOCTL_LEN];
523#else
524 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
525#endif
526 uint buflen;
527
528 buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
529 ASSERT(buflen);
530
531 return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen));
532}
533#endif
534
535
536static int
537dev_wlc_bufvar_get(
538 struct net_device *dev,
539 char *name,
540 char *buf, int buflen)
541{
542#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
543 char ioctlbuf[MAX_WLIW_IOCTL_LEN];
544#else
545 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
546#endif
547 int error;
548 uint len;
549
550 len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
551 ASSERT(len);
552 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN);
553 if (!error)
554 bcopy(ioctlbuf, buf, buflen);
555
556 return (error);
557}
558
559
560
561static int
562dev_wlc_intvar_get(
563 struct net_device *dev,
564 char *name,
565 int *retval)
566{
567 union {
568 char buf[WLC_IOCTL_SMLEN];
569 int val;
570 } var;
571 int error;
572
573 uint len;
574 uint data_null;
575
576 len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
577 ASSERT(len);
578 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
579
580 *retval = dtoh32(var.val);
581
582 return (error);
583}
584
585
586#if WIRELESS_EXT > 12
587static int
588wl_iw_set_active_scan(
589 struct net_device *dev,
590 struct iw_request_info *info,
591 union iwreq_data *wrqu,
592 char *extra
593)
594{
595 int as = 0;
596 int error = 0;
597 char *p = extra;
598
599#if defined(WL_IW_USE_ISCAN)
600 if (g_iscan->iscan_state == ISCAN_STATE_IDLE)
601#endif
602 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
603#if defined(WL_IW_USE_ISCAN)
604 else
605 g_iscan->scan_flag = as;
606#endif
607 p += snprintf(p, MAX_WX_STRING, "OK");
608
609 wrqu->data.length = p - extra + 1;
610 return error;
611}
612
613static int
614wl_iw_set_passive_scan(
615 struct net_device *dev,
616 struct iw_request_info *info,
617 union iwreq_data *wrqu,
618 char *extra
619)
620{
621 int ps = 1;
622 int error = 0;
623 char *p = extra;
624
625#if defined(WL_IW_USE_ISCAN)
626 if (g_iscan->iscan_state == ISCAN_STATE_IDLE) {
627#endif
628
629
630 if (g_scan_specified_ssid == 0) {
631 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &ps, sizeof(ps));
632 }
633#if defined(WL_IW_USE_ISCAN)
634 }
635 else
636 g_iscan->scan_flag = ps;
637#endif
638
639 p += snprintf(p, MAX_WX_STRING, "OK");
640
641 wrqu->data.length = p - extra + 1;
642 return error;
643}
644
645
646static int
647wl_iw_set_txpower(
648 struct net_device *dev,
649 struct iw_request_info *info,
650 union iwreq_data *wrqu,
651 char *extra
652)
653{
654 int error = 0;
655 char *p = extra;
656 int txpower = -1;
657
658 txpower = bcm_atoi(extra + strlen(TXPOWER_SET_CMD) + 1);
659 if ((txpower >= 0) && (txpower <= 127))
660 {
661 txpower |= WL_TXPWR_OVERRIDE;
662 txpower = htod32(txpower);
663
664 error = dev_wlc_intvar_set(dev, "qtxpower", txpower);
665 p += snprintf(p, MAX_WX_STRING, "OK");
666 WL_TRACE(("%s: set TXpower 0x%X is OK\n", __FUNCTION__, txpower));
667 } else {
668 WL_ERROR(("%s: set tx power failed\n", __FUNCTION__));
669 p += snprintf(p, MAX_WX_STRING, "FAIL");
670 }
671
672 wrqu->data.length = p - extra + 1;
673 return error;
674}
675
676static int
677wl_iw_get_macaddr(
678 struct net_device *dev,
679 struct iw_request_info *info,
680 union iwreq_data *wrqu,
681 char *extra
682)
683{
684 int error;
685 char buf[128];
686 struct ether_addr *id;
687 char *p = extra;
688
689
690 strcpy(buf, "cur_etheraddr");
691 error = dev_wlc_ioctl(dev, WLC_GET_VAR, buf, sizeof(buf));
692 id = (struct ether_addr *) buf;
693 p += snprintf(p, MAX_WX_STRING, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
694 id->octet[0], id->octet[1], id->octet[2],
695 id->octet[3], id->octet[4], id->octet[5]);
696 wrqu->data.length = p - extra + 1;
697
698 return error;
699}
700
701
702
703static int
704wl_iw_set_country(
705 struct net_device *dev,
706 struct iw_request_info *info,
707 union iwreq_data *wrqu,
708 char *extra
709)
710{
711 char country_code[WLC_CNTRY_BUF_SZ];
712 int error = 0;
713 char *p = extra;
714 int country_offset;
715 int country_code_size;
716 wl_country_t cspec = {{0}, 0, {0}};
717 char smbuf[WLC_IOCTL_SMLEN];
718 scb_val_t scbval;
719
720 cspec.rev = -1;
721 memset(country_code, 0, sizeof(country_code));
722 memset(smbuf, 0, sizeof(smbuf));
723
724
725 country_offset = strcspn(extra, " ");
726 country_code_size = strlen(extra) - country_offset;
727
728
729 if (country_offset != 0) {
730 strncpy(country_code, extra + country_offset +1,
731 MIN(country_code_size, sizeof(country_code)));
732
733
734 bzero(&scbval, sizeof(scb_val_t));
735 if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) {
736 WL_ERROR(("%s: set country failed due to Disassoc error\n", __FUNCTION__));
737 goto exit_failed;
738 }
739
740 memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
741 memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
742
743 get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
744
745
746 if ((error = dev_iw_iovar_setbuf(dev, "country", &cspec,
747 sizeof(cspec), smbuf, sizeof(smbuf))) >= 0) {
748 p += snprintf(p, MAX_WX_STRING, "OK");
749 WL_ERROR(("%s: set country for %s as %s rev %d is OK\n",
750 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
751 dhd_bus_country_set(dev, &cspec);
752 goto exit;
753 }
754 }
755
756 WL_ERROR(("%s: set country for %s as %s rev %d failed\n",
757 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
758
759exit_failed:
760 p += snprintf(p, MAX_WX_STRING, "FAIL");
761
762exit:
763 wrqu->data.length = p - extra + 1;
764 return error;
765}
766
767static int
768wl_iw_set_power_mode(
769 struct net_device *dev,
770 struct iw_request_info *info,
771 union iwreq_data *wrqu,
772 char *extra
773)
774{
775 int error = 0;
776 char *p = extra;
777 static int pm = PM_FAST;
778 int pm_local = PM_OFF;
779 char powermode_val = 0;
780
781 WL_TRACE_COEX(("%s: DHCP session cmd:%s\n", __FUNCTION__, extra));
782
783 strncpy((char *)&powermode_val, extra + strlen("POWERMODE") +1, 1);
784
785 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
786
787 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
788
789 dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
790 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
791
792
793 net_os_set_packet_filter(dev, 0);
794
795#ifdef COEX_DHCP
796 g_bt->ts_dhcp_start = JF2MS;
797 g_bt->dhcp_done = FALSE;
798 WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n",
799 __FUNCTION__, pm, pm_local));
800
801#endif
802 } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
803
804
805 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
806
807
808 net_os_set_packet_filter(dev, 1);
809
810#ifdef COEX_DHCP
811 g_bt->dhcp_done = TRUE;
812 g_bt->ts_dhcp_ok = JF2MS;
813 WL_TRACE_COEX(("%s: DHCP done for:%d ms, restored pm:%d\n",
814 __FUNCTION__, (g_bt->ts_dhcp_ok - g_bt->ts_dhcp_start), pm));
815#endif
816
817 } else {
818 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
819 __FUNCTION__));
820 }
821
822 p += snprintf(p, MAX_WX_STRING, "OK");
823
824 wrqu->data.length = p - extra + 1;
825
826 return error;
827}
828
829
830bool btcoex_is_sco_active(struct net_device *dev)
831{
832 int ioc_res = 0;
833 bool res = FALSE;
834 int sco_id_cnt = 0;
835 int param27;
836 int i;
837
838 for (i = 0; i < 12; i++) {
839
840 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
841
842 WL_TRACE_COEX(("%s, sample[%d], btc params: 27:%x\n",
843 __FUNCTION__, i, param27));
844
845 if (ioc_res < 0) {
846 WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__));
847 break;
848 }
849
850 if ((param27 & 0x6) == 2) {
851 sco_id_cnt++;
852 }
853
854 if (sco_id_cnt > 2) {
855 WL_TRACE_COEX(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
856 __FUNCTION__, sco_id_cnt, i));
857 res = TRUE;
858 break;
859 }
860
861 msleep(5);
862 }
863
864 return res;
865}
866
867#if defined(BT_DHCP_eSCO_FIX)
868
869static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
870{
871 static bool saved_status = FALSE;
872
873 char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
874 char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
875 char buf_reg64va_dhcp_on[8] = { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
876 char buf_reg65va_dhcp_on[8] = { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
877 char buf_reg71va_dhcp_on[8] = { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
878
879 uint32 regaddr;
880 static uint32 saved_reg50;
881 static uint32 saved_reg51;
882 static uint32 saved_reg64;
883 static uint32 saved_reg65;
884 static uint32 saved_reg71;
885
886 if (trump_sco) {
887
888
889 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
890
891
892 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
893 (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
894 (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
895 (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
896 (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
897
898 saved_status = TRUE;
899 WL_TRACE_COEX(("%s saved bt_params[50,51,64,65,71]:"
900 " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
901 __FUNCTION__, saved_reg50, saved_reg51,
902 saved_reg64, saved_reg65, saved_reg71));
903
904 } else {
905 WL_ERROR((":%s: save btc_params failed\n",
906 __FUNCTION__));
907 saved_status = FALSE;
908 return -1;
909 }
910
911 WL_TRACE_COEX(("override with [50,51,64,65,71]:"
912 " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
913 *(u32 *)(buf_reg50va_dhcp_on+4),
914 *(u32 *)(buf_reg51va_dhcp_on+4),
915 *(u32 *)(buf_reg64va_dhcp_on+4),
916 *(u32 *)(buf_reg65va_dhcp_on+4),
917 *(u32 *)(buf_reg71va_dhcp_on+4)));
918
919 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg50va_dhcp_on[0], 8);
920 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg51va_dhcp_on[0], 8);
921 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg64va_dhcp_on[0], 8);
922 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8);
923 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8);
924
925 saved_status = TRUE;
926
927 } else if (saved_status) {
928
929 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
930
931 regaddr = 50;
932 dev_wlc_intvar_set_reg(dev, "btc_params",
933 (char *)&regaddr, (char *)&saved_reg50);
934 regaddr = 51;
935 dev_wlc_intvar_set_reg(dev, "btc_params",
936 (char *)&regaddr, (char *)&saved_reg51);
937 regaddr = 64;
938 dev_wlc_intvar_set_reg(dev, "btc_params",
939 (char *)&regaddr, (char *)&saved_reg64);
940 regaddr = 65;
941 dev_wlc_intvar_set_reg(dev, "btc_params",
942 (char *)&regaddr, (char *)&saved_reg65);
943 regaddr = 71;
944 dev_wlc_intvar_set_reg(dev, "btc_params",
945 (char *)&regaddr, (char *)&saved_reg71);
946
947 WL_TRACE_COEX(("restore bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
948 saved_reg50, saved_reg51, saved_reg64,
949 saved_reg65, saved_reg71));
950
951 saved_status = FALSE;
952 } else {
953 WL_ERROR((":%s att to restore not saved BTCOEX params\n",
954 __FUNCTION__));
955 return -1;
956 }
957 return 0;
958}
959#endif
960
961
962static int
963wl_iw_get_power_mode(
964 struct net_device *dev,
965 struct iw_request_info *info,
966 union iwreq_data *wrqu,
967 char *extra
968)
969{
970 int error = 0;
971 int pm_local;
972 char *p = extra;
973
974 error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local));
975 if (!error) {
976 WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local));
977 if (pm_local == PM_OFF)
978 pm_local = 1;
979 else
980 pm_local = 0;
981 p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local);
982 }
983 else {
984 WL_TRACE(("%s: Error = %d\n", __func__, error));
985 p += snprintf(p, MAX_WX_STRING, "FAIL");
986 }
987 wrqu->data.length = p - extra + 1;
988 return error;
989}
990
991static int
992wl_iw_set_btcoex_dhcp(
993 struct net_device *dev,
994 struct iw_request_info *info,
995 union iwreq_data *wrqu,
996 char *extra
997)
998{
999 int error = 0;
1000 char *p = extra;
1001 char powermode_val = 0;
1002 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
1003 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
1004 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
1005
1006 uint32 regaddr;
1007 static uint32 saved_reg66;
1008 static uint32 saved_reg41;
1009 static uint32 saved_reg68;
1010 static bool saved_status = FALSE;
1011
1012#ifdef COEX_DHCP
1013 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
1014#endif
1015
1016
1017 strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") +1, 1);
1018
1019 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
1020
1021 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
1022
1023
1024 if ((saved_status == FALSE) &&
1025 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
1026 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
1027 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
1028 saved_status = TRUE;
1029 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
1030 saved_reg66, saved_reg41, saved_reg68));
1031
1032
1033
1034
1035#ifdef COEX_DHCP
1036
1037 if (btcoex_is_sco_active(dev)) {
1038
1039 dev_wlc_bufvar_set(dev, "btc_params",
1040 (char *)&buf_reg66va_dhcp_on[0],
1041 sizeof(buf_reg66va_dhcp_on));
1042
1043 dev_wlc_bufvar_set(dev, "btc_params",
1044 (char *)&buf_reg41va_dhcp_on[0],
1045 sizeof(buf_reg41va_dhcp_on));
1046
1047 dev_wlc_bufvar_set(dev, "btc_params",
1048 (char *)&buf_reg68va_dhcp_on[0],
1049 sizeof(buf_reg68va_dhcp_on));
1050 saved_status = TRUE;
1051
1052 g_bt->bt_state = BT_DHCP_START;
1053 g_bt->timer_on = 1;
1054 mod_timer(&g_bt->timer, g_bt->timer.expires);
1055 WL_TRACE_COEX(("%s enable BT DHCP Timer\n",
1056 __FUNCTION__));
1057 }
1058#endif
1059 }
1060 else if (saved_status == TRUE) {
1061 WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
1062 }
1063 }
1064 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
1065
1066
1067
1068
1069#ifdef COEX_DHCP
1070
1071 WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
1072 if (g_bt->timer_on) {
1073 g_bt->timer_on = 0;
1074 del_timer_sync(&g_bt->timer);
1075
1076 if (g_bt->bt_state != BT_DHCP_IDLE) {
1077
1078 WL_TRACE_COEX(("%s bt->bt_state:%d\n",
1079 __FUNCTION__, g_bt->bt_state));
1080
1081 up(&g_bt->tsk_ctl.sema);
1082 }
1083 }
1084
1085
1086 if (saved_status == TRUE)
1087 dev_wlc_bufvar_set(dev, "btc_flags",
1088 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
1089#endif
1090
1091
1092 if (saved_status == TRUE) {
1093 regaddr = 66;
1094 dev_wlc_intvar_set_reg(dev, "btc_params",
1095 (char *)&regaddr, (char *)&saved_reg66);
1096 regaddr = 41;
1097 dev_wlc_intvar_set_reg(dev, "btc_params",
1098 (char *)&regaddr, (char *)&saved_reg41);
1099 regaddr = 68;
1100 dev_wlc_intvar_set_reg(dev, "btc_params",
1101 (char *)&regaddr, (char *)&saved_reg68);
1102
1103 WL_TRACE_COEX(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
1104 saved_reg66, saved_reg41, saved_reg68));
1105 }
1106 saved_status = FALSE;
1107
1108 }
1109 else {
1110 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
1111 __FUNCTION__));
1112 }
1113
1114 p += snprintf(p, MAX_WX_STRING, "OK");
1115
1116 wrqu->data.length = p - extra + 1;
1117
1118 return error;
1119}
1120
1121static int
1122wl_iw_set_suspend_opt(
1123struct net_device *dev,
1124struct iw_request_info *info,
1125union iwreq_data *wrqu,
1126char *extra
1127)
1128{
1129 int suspend_flag;
1130 int ret_now;
1131 int ret = 0;
1132
1133 suspend_flag = *(extra + strlen(SETSUSPENDOPT_CMD) + 1) - '0';
1134
1135 if (suspend_flag != 0)
1136 suspend_flag = 1;
1137
1138 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1139
1140 if (ret_now != suspend_flag) {
1141 if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
1142 WL_ERROR(("%s: Suspend Flag %d -> %d\n",
1143 __FUNCTION__, ret_now, suspend_flag));
1144 else
1145 WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1146 }
1147
1148 return ret;
1149}
1150
1151static int
1152wl_iw_set_suspend_mode(
1153struct net_device *dev,
1154struct iw_request_info *info,
1155union iwreq_data *wrqu,
1156char *extra
1157)
1158{
1159 int ret = 0;
1160
1161#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
1162 int suspend_flag;
1163
1164 suspend_flag = *(extra + strlen(SETSUSPENDMODE_CMD) + 1) - '0';
1165
1166 if (suspend_flag != 0)
1167 suspend_flag = 1;
1168
1169 if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
1170 WL_ERROR(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag));
1171 else
1172 WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1173#endif
1174 return ret;
1175}
1176
1177static int
1178wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
1179{
1180 int i, c;
1181 char *p = ssid_buf;
1182
1183 if (ssid_len > 32) ssid_len = 32;
1184
1185 for (i = 0; i < ssid_len; i++) {
1186 c = (int)ssid[i];
1187 if (c == '\\') {
1188 *p++ = '\\';
1189 *p++ = '\\';
1190 } else if (isprint((uchar)c)) {
1191 *p++ = (char)c;
1192 } else {
1193 p += sprintf(p, "\\x%02X", c);
1194 }
1195 }
1196 *p = '\0';
1197
1198 return p - ssid_buf;
1199}
1200
1201static int
1202wl_iw_get_link_speed(
1203 struct net_device *dev,
1204 struct iw_request_info *info,
1205 union iwreq_data *wrqu,
1206 char *extra
1207)
1208{
1209 int error = 0;
1210 char *p = extra;
1211 static int link_speed;
1212
1213
1214 net_os_wake_lock(dev);
1215 if (g_onoff == G_WLAN_SET_ON) {
1216 error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed));
1217 link_speed *= 500000;
1218 }
1219
1220 p += snprintf(p, MAX_WX_STRING, "LinkSpeed %d", link_speed/1000000);
1221
1222 wrqu->data.length = p - extra + 1;
1223
1224 net_os_wake_unlock(dev);
1225 return error;
1226}
1227
1228
1229static int
1230wl_iw_get_dtim_skip(
1231 struct net_device *dev,
1232 struct iw_request_info *info,
1233 union iwreq_data *wrqu,
1234 char *extra
1235)
1236{
1237 int error = -1;
1238 char *p = extra;
1239 char iovbuf[32];
1240
1241 net_os_wake_lock(dev);
1242 if (g_onoff == G_WLAN_SET_ON) {
1243
1244 memset(iovbuf, 0, sizeof(iovbuf));
1245 strcpy(iovbuf, "bcn_li_dtim");
1246
1247 if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR,
1248 &iovbuf, sizeof(iovbuf))) >= 0) {
1249
1250 p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]);
1251 WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0]));
1252 wrqu->data.length = p - extra + 1;
1253 }
1254 else
1255 WL_ERROR(("%s: get dtim_skip failed code %d\n",
1256 __FUNCTION__, error));
1257 }
1258 net_os_wake_unlock(dev);
1259 return error;
1260}
1261
1262
1263static int
1264wl_iw_set_dtim_skip(
1265 struct net_device *dev,
1266 struct iw_request_info *info,
1267 union iwreq_data *wrqu,
1268 char *extra
1269)
1270{
1271 int error = -1;
1272 char *p = extra;
1273 int bcn_li_dtim;
1274 char iovbuf[32];
1275
1276 net_os_wake_lock(dev);
1277 if (g_onoff == G_WLAN_SET_ON) {
1278
1279 bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0');
1280
1281 if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) {
1282
1283 memset(iovbuf, 0, sizeof(iovbuf));
1284 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1285 4, iovbuf, sizeof(iovbuf));
1286
1287 if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR,
1288 &iovbuf, sizeof(iovbuf))) >= 0) {
1289 p += snprintf(p, MAX_WX_STRING, "OK");
1290
1291
1292 net_os_set_dtim_skip(dev, bcn_li_dtim);
1293
1294 WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__,
1295 bcn_li_dtim));
1296 goto exit;
1297 }
1298 else WL_ERROR(("%s: set dtim_skip %d failed code %d\n",
1299 __FUNCTION__, bcn_li_dtim, error));
1300 }
1301 else WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n",
1302 __FUNCTION__, bcn_li_dtim));
1303 }
1304
1305 p += snprintf(p, MAX_WX_STRING, "FAIL");
1306
1307exit:
1308 wrqu->data.length = p - extra + 1;
1309 net_os_wake_unlock(dev);
1310 return error;
1311}
1312
1313
1314static int
1315wl_iw_get_band(
1316 struct net_device *dev,
1317 struct iw_request_info *info,
1318 union iwreq_data *wrqu,
1319 char *extra
1320)
1321{
1322 int error = -1;
1323 char *p = extra;
1324 static int band;
1325
1326 net_os_wake_lock(dev);
1327
1328 if (g_onoff == G_WLAN_SET_ON) {
1329 error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band));
1330
1331 p += snprintf(p, MAX_WX_STRING, "Band %d", band);
1332
1333 wrqu->data.length = p - extra + 1;
1334 }
1335
1336 net_os_wake_unlock(dev);
1337 return error;
1338}
1339
1340
1341static int
1342wl_iw_set_band(
1343 struct net_device *dev,
1344 struct iw_request_info *info,
1345 union iwreq_data *wrqu,
1346 char *extra
1347)
1348{
1349 int error = -1;
1350 char *p = extra;
1351 uint band;
1352
1353 net_os_wake_lock(dev);
1354
1355 if (g_onoff == G_WLAN_SET_ON) {
1356
1357 band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0');
1358
1359 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
1360
1361 if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND,
1362 &band, sizeof(band))) >= 0) {
1363 p += snprintf(p, MAX_WX_STRING, "OK");
1364 WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band));
1365 goto exit;
1366 } else {
1367 WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__,
1368 band, error));
1369 }
1370 } else {
1371 WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band));
1372 }
1373 }
1374
1375 p += snprintf(p, MAX_WX_STRING, "FAIL");
1376
1377exit:
1378 wrqu->data.length = p - extra + 1;
1379 net_os_wake_unlock(dev);
1380 return error;
1381}
1382
1383#ifdef PNO_SUPPORT
1384
1385static int
1386wl_iw_set_pno_reset(
1387 struct net_device *dev,
1388 struct iw_request_info *info,
1389 union iwreq_data *wrqu,
1390 char *extra
1391)
1392{
1393 int error = -1;
1394 char *p = extra;
1395
1396 net_os_wake_lock(dev);
1397 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1398
1399 if ((error = dhd_dev_pno_reset(dev)) >= 0) {
1400 p += snprintf(p, MAX_WX_STRING, "OK");
1401 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1402 goto exit;
1403 }
1404 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1405 }
1406
1407 p += snprintf(p, MAX_WX_STRING, "FAIL");
1408
1409exit:
1410 wrqu->data.length = p - extra + 1;
1411 net_os_wake_unlock(dev);
1412 return error;
1413}
1414
1415
1416
1417static int
1418wl_iw_set_pno_enable(
1419 struct net_device *dev,
1420 struct iw_request_info *info,
1421 union iwreq_data *wrqu,
1422 char *extra
1423)
1424{
1425 int error = -1;
1426 char *p = extra;
1427 int pfn_enabled;
1428
1429 net_os_wake_lock(dev);
1430 pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0');
1431
1432 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1433
1434 if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) {
1435 p += snprintf(p, MAX_WX_STRING, "OK");
1436 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1437 goto exit;
1438 }
1439 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1440 }
1441
1442 p += snprintf(p, MAX_WX_STRING, "FAIL");
1443
1444exit:
1445 wrqu->data.length = p - extra + 1;
1446 net_os_wake_unlock(dev);
1447 return error;
1448}
1449
1450
1451
1452static int
1453wl_iw_set_pno_set(
1454 struct net_device *dev,
1455 struct iw_request_info *info,
1456 union iwreq_data *wrqu,
1457 char *extra
1458)
1459{
1460 int res = -1;
1461 wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
1462 int nssid = 0;
1463 cmd_tlv_t *cmd_tlv_temp;
1464 char *str_ptr;
1465 int tlv_size_left;
1466 int pno_time;
1467 int pno_repeat;
1468 int pno_freq_expo_max;
1469#ifdef PNO_SET_DEBUG
1470 int i;
1471 char pno_in_example[] = {
1472 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
1473 'S', '1', '2', '0',
1474 'S',
1475 0x04,
1476 'B', 'R', 'C', 'M',
1477 'S',
1478 0x04,
1479 'G', 'O', 'O', 'G',
1480 'T',
1481 '1', 'E',
1482 'R',
1483 '2',
1484 'M',
1485 '2',
1486 0x00
1487 };
1488#endif
1489
1490 net_os_wake_lock(dev);
1491 WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
1492 __FUNCTION__, info->cmd, info->flags,
1493 wrqu->data.pointer, wrqu->data.length));
1494
1495 if (g_onoff == G_WLAN_SET_OFF) {
1496 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
1497 goto exit_proc;
1498 }
1499
1500 if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) {
1501 WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
1502 wrqu->data.length, (int)(strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))));
1503 goto exit_proc;
1504 }
1505
1506#ifdef PNO_SET_DEBUG
1507 if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) {
1508 res = -ENOMEM;
1509 goto exit_proc;
1510 }
1511 memcpy(extra, pno_in_example, sizeof(pno_in_example));
1512 wrqu->data.length = sizeof(pno_in_example);
1513 for (i = 0; i < wrqu->data.length; i++)
1514 printf("%02X ", extra[i]);
1515 printf("\n");
1516#endif
1517
1518 str_ptr = extra;
1519#ifdef PNO_SET_DEBUG
1520 str_ptr += strlen("PNOSETUP ");
1521 tlv_size_left = wrqu->data.length - strlen("PNOSETUP ");
1522#else
1523 str_ptr += strlen(PNOSETUP_SET_CMD);
1524 tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
1525#endif
1526
1527 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
1528 memset(ssids_local, 0, sizeof(ssids_local));
1529 pno_repeat = pno_freq_expo_max = 0;
1530
1531 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
1532 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
1533 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION))
1534 {
1535 str_ptr += sizeof(cmd_tlv_t);
1536 tlv_size_left -= sizeof(cmd_tlv_t);
1537
1538
1539 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
1540 MAX_PFN_LIST_COUNT,
1541 &tlv_size_left)) <= 0) {
1542 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
1543 goto exit_proc;
1544 }
1545 else {
1546 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
1547 WL_ERROR(("%s scan duration corrupted field size %d\n",
1548 __FUNCTION__, tlv_size_left));
1549 goto exit_proc;
1550 }
1551 str_ptr++;
1552 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
1553 WL_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
1554
1555
1556 if (str_ptr[0] != 0) {
1557 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
1558 WL_ERROR(("%s pno repeat : corrupted field\n",
1559 __FUNCTION__));
1560 goto exit_proc;
1561 }
1562 str_ptr++;
1563 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
1564 WL_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
1565 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
1566 WL_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
1567 __FUNCTION__));
1568 goto exit_proc;
1569 }
1570 str_ptr++;
1571 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
1572 WL_PNO(("%s: pno_freq_expo_max=%d\n",
1573 __FUNCTION__, pno_freq_expo_max));
1574 }
1575 }
1576 }
1577 else {
1578 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
1579 goto exit_proc;
1580 }
1581
1582
1583 res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
1584
1585exit_proc:
1586 net_os_wake_unlock(dev);
1587 return res;
1588}
1589
1590static int
1591wl_iw_set_pno_setadd(
1592 struct net_device *dev,
1593 struct iw_request_info *info,
1594 union iwreq_data *wrqu,
1595 char *extra
1596)
1597{
1598 int ret = -1;
1599 char *tmp_ptr;
1600 int size, tmp_size;
1601
1602 net_os_wake_lock(dev);
1603 WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
1604 __FUNCTION__, info->cmd, info->flags,
1605 wrqu->data.pointer, wrqu->data.length));
1606
1607 if (g_onoff == G_WLAN_SET_OFF) {
1608 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
1609 goto exit_proc;
1610 }
1611
1612 if (wrqu->data.length <= strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t)) {
1613 WL_ERROR(("%s argument=%d less than %d\n", __FUNCTION__,
1614 wrqu->data.length, (int)(strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t))));
1615 goto exit_proc;
1616 }
1617
1618
1619 bcopy(PNOSETUP_SET_CMD, extra, strlen(PNOSETUP_SET_CMD));
1620
1621 tmp_ptr = extra + strlen(PNOSETUP_SET_CMD);
1622 size = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
1623 tmp_size = size;
1624
1625 while (*tmp_ptr && tmp_size > 0) {
1626 if ((*tmp_ptr == 'S') && (size - tmp_size) >= sizeof(cmd_tlv_t)) {
1627 *(tmp_ptr + 1) = ((*(tmp_ptr + 1) - '0') << 4) + (*(tmp_ptr + 2) - '0');
1628 memmove(tmp_ptr + 2, tmp_ptr + 3, tmp_size - 3);
1629 tmp_size -= 2 + *(tmp_ptr + 1);
1630 tmp_ptr += 2 + *(tmp_ptr + 1);
1631 size--;
1632 } else {
1633 tmp_ptr++;
1634 tmp_size--;
1635 }
1636 }
1637
1638 wrqu->data.length = strlen(PNOSETUP_SET_CMD) + size;
1639 ret = wl_iw_set_pno_set(dev, info, wrqu, extra);
1640
1641exit_proc:
1642 net_os_wake_unlock(dev);
1643 return ret;
1644
1645}
1646#endif
1647
1648static int
1649wl_iw_get_rssi(
1650 struct net_device *dev,
1651 struct iw_request_info *info,
1652 union iwreq_data *wrqu,
1653 char *extra
1654)
1655{
1656 static int rssi = 0;
1657 static wlc_ssid_t ssid = {0};
1658 int error = 0;
1659 char *p = extra;
1660 static char ssidbuf[SSID_FMT_BUF_LEN];
1661 scb_val_t scb_val;
1662
1663 net_os_wake_lock(dev);
1664
1665 bzero(&scb_val, sizeof(scb_val_t));
1666
1667 if (g_onoff == G_WLAN_SET_ON) {
1668 error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
1669 if (error) {
1670 WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error));
1671 net_os_wake_unlock(dev);
1672 return error;
1673 }
1674 rssi = dtoh32(scb_val.val);
1675
1676 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1677 if (!error) {
1678 ssid.SSID_len = dtoh32(ssid.SSID_len);
1679 wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len));
1680 }
1681 }
1682
1683 p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi);
1684 wrqu->data.length = p - extra + 1;
1685
1686 net_os_wake_unlock(dev);
1687 return error;
1688}
1689
1690int
1691wl_iw_send_priv_event(
1692 struct net_device *dev,
1693 char *flag
1694)
1695{
1696 union iwreq_data wrqu;
1697 char extra[IW_CUSTOM_MAX + 1];
1698 int cmd;
1699
1700 cmd = IWEVCUSTOM;
1701 memset(&wrqu, 0, sizeof(wrqu));
1702 if (strlen(flag) > sizeof(extra))
1703 return -1;
1704
1705 strcpy(extra, flag);
1706 wrqu.data.length = strlen(extra);
1707 wireless_send_event(dev, cmd, &wrqu, extra);
1708 net_os_wake_lock_ctrl_timeout_enable(dev, DHD_EVENT_TIMEOUT_MS);
1709 WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
1710
1711 return 0;
1712}
1713
1714
1715int
1716wl_control_wl_start(struct net_device *dev)
1717{
1718 wl_iw_t *iw;
1719 int ret = 0;
1720
1721 WL_TRACE(("Enter %s \n", __FUNCTION__));
1722
1723 if (!dev) {
1724 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1725 return -1;
1726 }
1727
1728 iw = *(wl_iw_t **)netdev_priv(dev);
1729
1730 if (!iw) {
1731 WL_ERROR(("%s: wl is null\n", __FUNCTION__));
1732 return -1;
1733 }
1734
1735 dhd_net_if_lock(dev);
1736
1737 if (g_onoff == G_WLAN_SET_OFF) {
1738 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
1739
1740#if defined(BCMLXSDMMC)
1741 sdioh_start(NULL, 0);
1742#endif
1743
1744 ret = dhd_dev_reset(dev, 0);
1745
1746#if defined(BCMLXSDMMC)
1747 sdioh_start(NULL, 1);
1748#endif
1749 if (!ret)
1750 dhd_dev_init_ioctl(dev);
1751
1752 g_onoff = G_WLAN_SET_ON;
1753 }
1754 WL_TRACE(("Exited %s\n", __FUNCTION__));
1755
1756 dhd_net_if_unlock(dev);
1757 return ret;
1758}
1759
1760
1761static int
1762wl_iw_control_wl_off(
1763 struct net_device *dev,
1764 struct iw_request_info *info
1765)
1766{
1767 wl_iw_t *iw;
1768 int ret = 0;
1769
1770 WL_TRACE(("Enter %s\n", __FUNCTION__));
1771
1772 if (!dev) {
1773 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1774 return -1;
1775 }
1776
1777 iw = *(wl_iw_t **)netdev_priv(dev);
1778
1779 if (!iw) {
1780 WL_ERROR(("%s: wl is null\n", __FUNCTION__));
1781 return -1;
1782 }
1783
1784 dhd_net_if_lock(dev);
1785
1786#ifdef SOFTAP
1787 ap_cfg_running = FALSE;
1788#endif
1789
1790 if (g_onoff == G_WLAN_SET_ON) {
1791 g_onoff = G_WLAN_SET_OFF;
1792
1793#if defined(WL_IW_USE_ISCAN)
1794 g_iscan->iscan_state = ISCAN_STATE_IDLE;
1795#endif
1796
1797 ret = dhd_dev_reset(dev, 1);
1798
1799#if defined(WL_IW_USE_ISCAN)
1800#if !defined(CSCAN)
1801
1802 wl_iw_free_ss_cache();
1803 wl_iw_run_ss_cache_timer(0);
1804
1805 g_ss_cache_ctrl.m_link_down = 1;
1806#endif
1807 memset(g_scan, 0, G_SCAN_RESULTS);
1808 g_scan_specified_ssid = 0;
1809#if defined(CONFIG_FIRST_SCAN)
1810
1811 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
1812 g_first_counter_scans = 0;
1813#endif
1814#endif
1815
1816#if defined(BCMLXSDMMC)
1817 sdioh_stop(NULL);
1818#endif
1819
1820 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1821
1822 wl_iw_send_priv_event(dev, "STOP");
1823 }
1824
1825 dhd_net_if_unlock(dev);
1826
1827 WL_TRACE(("Exited %s\n", __FUNCTION__));
1828
1829 return ret;
1830}
1831
1832static int
1833wl_iw_control_wl_on(
1834 struct net_device *dev,
1835 struct iw_request_info *info
1836)
1837{
1838 int ret = 0;
1839
1840 WL_TRACE(("Enter %s \n", __FUNCTION__));
1841
1842 ret = wl_control_wl_start(dev);
1843
1844 wl_iw_send_priv_event(dev, "START");
1845
1846#ifdef SOFTAP
1847 if (!ap_fw_loaded) {
1848 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1849 }
1850#else
1851 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1852#endif
1853
1854 WL_TRACE(("Exited %s\n", __FUNCTION__));
1855
1856 return ret;
1857}
1858
1859#ifdef SOFTAP
1860static struct ap_profile my_ap;
1861static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap);
1862static int get_assoc_sta_list(struct net_device *dev, char *buf, int len);
1863static int set_ap_mac_list(struct net_device *dev, void *buf);
1864
1865#define PTYPE_STRING 0
1866#define PTYPE_INTDEC 1
1867#define PTYPE_INTHEX 2
1868#define PTYPE_STR_HEX 3
1869
1870static int get_parameter_from_string(
1871 char **str_ptr, const char *token, int param_type, void *dst, int param_max_len);
1872
1873static int
1874hex2num(char c)
1875{
1876 if (c >= '0' && c <= '9')
1877 return c - '0';
1878 if (c >= 'a' && c <= 'f')
1879 return c - 'a' + 10;
1880 if (c >= 'A' && c <= 'F')
1881 return c - 'A' + 10;
1882 return -1;
1883}
1884
1885
1886
1887static int
1888hstr_2_buf(const char *txt, u8 *buf, int len)
1889{
1890 int i;
1891
1892 for (i = 0; i < len; i++) {
1893 int a, b;
1894
1895 a = hex2num(*txt++);
1896 if (a < 0)
1897 return -1;
1898 b = hex2num(*txt++);
1899 if (b < 0)
1900 return -1;
1901 *buf++ = (a << 4) | b;
1902 }
1903
1904 return 0;
1905}
1906
1907
1908
1909static int
1910init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg)
1911{
1912 char *str_ptr = param_str;
1913 char sub_cmd[16];
1914 int ret = 0;
1915
1916 memset(sub_cmd, 0, sizeof(sub_cmd));
1917 memset(ap_cfg, 0, sizeof(struct ap_profile));
1918
1919
1920 if (get_parameter_from_string(&str_ptr, "ASCII_CMD=",
1921 PTYPE_STRING, sub_cmd, SSID_LEN) != 0) {
1922 return -1;
1923 }
1924 if (strncmp(sub_cmd, "AP_CFG", 6)) {
1925 WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd));
1926 return -1;
1927 }
1928
1929
1930
1931 ret = get_parameter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN);
1932
1933 ret |= get_parameter_from_string(&str_ptr, "SEC=", PTYPE_STRING, ap_cfg->sec, SEC_LEN);
1934
1935 ret |= get_parameter_from_string(&str_ptr, "KEY=", PTYPE_STRING, ap_cfg->key, KEY_LEN);
1936
1937 ret |= get_parameter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5);
1938
1939
1940 get_parameter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5);
1941
1942
1943 get_parameter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5);
1944
1945
1946 get_parameter_from_string(&str_ptr, "HIDDEN=",
1947 PTYPE_INTDEC, &ap_cfg->closednet, 5);
1948
1949
1950 get_parameter_from_string(&str_ptr, "COUNTRY=",
1951 PTYPE_STRING, &ap_cfg->country_code, 3);
1952
1953 return ret;
1954}
1955#endif
1956
1957
1958
1959#ifdef SOFTAP
1960static int
1961iwpriv_set_ap_config(struct net_device *dev,
1962 struct iw_request_info *info,
1963 union iwreq_data *wrqu,
1964 char *ext)
1965{
1966 int res = 0;
1967 char *extra = NULL;
1968 struct ap_profile *ap_cfg = &my_ap;
1969
1970 WL_TRACE(("> Got IWPRIV SET_AP IOCTL: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
1971 info->cmd, info->flags,
1972 wrqu->data.pointer, wrqu->data.length));
1973
1974 if (!ap_fw_loaded) {
1975 WL_ERROR(("Can't execute %s(), SOFTAP fw is not Loaded\n",
1976 __FUNCTION__));
1977 return -1;
1978 }
1979
1980 if (wrqu->data.length != 0) {
1981
1982 char *str_ptr;
1983
1984 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
1985 return -ENOMEM;
1986
1987 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
1988 kfree(extra);
1989 return -EFAULT;
1990 }
1991
1992 extra[wrqu->data.length] = 0;
1993 WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra));
1994
1995 memset(ap_cfg, 0, sizeof(struct ap_profile));
1996
1997
1998
1999 str_ptr = extra;
2000
2001 if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) {
2002 WL_ERROR(("%s failed to parse %d\n", __FUNCTION__, res));
2003 kfree(extra);
2004 return -1;
2005 }
2006
2007 } else {
2008
2009 WL_ERROR(("IWPRIV argument len = 0 \n"));
2010 return -1;
2011 }
2012
2013 if ((res = set_ap_cfg(dev, ap_cfg)) < 0)
2014 WL_ERROR(("%s failed to set_ap_cfg %d\n", __FUNCTION__, res));
2015
2016 kfree(extra);
2017
2018 return res;
2019}
2020#endif
2021
2022
2023
2024#ifdef SOFTAP
2025static int iwpriv_get_assoc_list(struct net_device *dev,
2026 struct iw_request_info *info,
2027 union iwreq_data *p_iwrq,
2028 char *extra)
2029{
2030 int i, ret = 0;
2031 char mac_buf[256];
2032 struct maclist *sta_maclist = (struct maclist *)mac_buf;
2033
2034 char mac_lst[384];
2035 char *p_mac_str;
2036 char *p_mac_str_end;
2037 wl_iw_t *iw;
2038
2039 if ((!dev) || (!extra)) {
2040
2041 return -EINVAL;
2042 }
2043
2044
2045 iw = *(wl_iw_t **)netdev_priv(dev);
2046
2047 net_os_wake_lock(dev);
2048 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
2049
2050 WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d,"
2051 "iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags,
2052 extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags));
2053
2054
2055 memset(sta_maclist, 0, sizeof(mac_buf));
2056
2057 sta_maclist->count = 8;
2058
2059 WL_SOFTAP(("%s: net device:%s, buf_sz:%d\n",
2060 __FUNCTION__, dev->name, sizeof(mac_buf)));
2061
2062 if ((ret = get_assoc_sta_list(dev, mac_buf, sizeof(mac_buf))) < 0) {
2063 WL_ERROR(("%s: sta list ioctl error:%d\n",
2064 __FUNCTION__, ret));
2065 goto func_exit;
2066 }
2067
2068 WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__,
2069 sta_maclist->count));
2070
2071
2072
2073 memset(mac_lst, 0, sizeof(mac_lst));
2074 p_mac_str = mac_lst;
2075 p_mac_str_end = &mac_lst[sizeof(mac_lst)-1];
2076
2077 for (i = 0; i < 8; i++) {
2078 struct ether_addr * id = &sta_maclist->ea[i];
2079 if (!ETHER_ISNULLADDR(id->octet)) {
2080 scb_val_t scb_val;
2081 int rssi = 0;
2082 bzero(&scb_val, sizeof(scb_val_t));
2083
2084
2085 if ((p_mac_str_end - p_mac_str) <= 36) {
2086 WL_ERROR(("%s: mac list buf is < 36 for item[%i] item\n",
2087 __FUNCTION__, i));
2088 break;
2089 }
2090
2091 p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
2092 "\nMac[%d]=%02X:%02X:%02X:%02X:%02X:%02X,", i,
2093 id->octet[0], id->octet[1], id->octet[2],
2094 id->octet[3], id->octet[4], id->octet[5]);
2095
2096
2097 bcopy(id->octet, &scb_val.ea, 6);
2098 ret = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
2099 if (ret < 0) {
2100 snprintf(p_mac_str, MAX_WX_STRING, "RSSI:ERR");
2101 WL_ERROR(("%s: RSSI ioctl error:%d\n",
2102 __FUNCTION__, ret));
2103 break;
2104 }
2105
2106 rssi = dtoh32(scb_val.val);
2107 p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
2108 "RSSI:%d", rssi);
2109 }
2110 }
2111
2112 p_iwrq->data.length = strlen(mac_lst)+1;
2113
2114 WL_SOFTAP(("%s: data to user:\n%s\n usr_ptr:%p\n", __FUNCTION__,
2115 mac_lst, p_iwrq->data.pointer));
2116
2117 if (p_iwrq->data.length) {
2118 bcopy(mac_lst, extra, p_iwrq->data.length);
2119 }
2120
2121func_exit:
2122
2123 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
2124 net_os_wake_unlock(dev);
2125
2126 WL_SOFTAP(("%s: Exited\n", __FUNCTION__));
2127 return ret;
2128}
2129#endif
2130
2131
2132#ifdef SOFTAP
2133
2134#define MAC_FILT_MAX 8
2135static int iwpriv_set_mac_filters(struct net_device *dev,
2136 struct iw_request_info *info,
2137 union iwreq_data *wrqu,
2138 char *ext)
2139{
2140 int i, ret = -1;
2141 char * extra = NULL;
2142 int mac_cnt = 0;
2143 int mac_mode = 0;
2144 struct ether_addr *p_ea;
2145 struct mac_list_set mflist_set;
2146
2147 WL_SOFTAP((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x,"
2148 "info->flags:%x, u.data:%p, u.len:%d\n",
2149 info->cmd, info->flags,
2150 wrqu->data.pointer, wrqu->data.length));
2151
2152 if (wrqu->data.length != 0) {
2153
2154 char *str_ptr;
2155
2156 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
2157 return -ENOMEM;
2158
2159 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
2160 kfree(extra);
2161 return -EFAULT;
2162 }
2163
2164 extra[wrqu->data.length] = 0;
2165 WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra));
2166
2167 memset(&mflist_set, 0, sizeof(mflist_set));
2168
2169
2170 str_ptr = extra;
2171
2172
2173
2174 if (get_parameter_from_string(&str_ptr, "MAC_MODE=",
2175 PTYPE_INTDEC, &mac_mode, 4) != 0) {
2176 WL_ERROR(("ERROR: 'MAC_MODE=' token is missing\n"));
2177 goto exit_proc;
2178 }
2179
2180 p_ea = &mflist_set.mac_list.ea[0];
2181
2182 if (get_parameter_from_string(&str_ptr, "MAC_CNT=",
2183 PTYPE_INTDEC, &mac_cnt, 4) != 0) {
2184 WL_ERROR(("ERROR: 'MAC_CNT=' token param is missing \n"));
2185 goto exit_proc;
2186 }
2187
2188 if (mac_cnt > MAC_FILT_MAX) {
2189 WL_ERROR(("ERROR: number of MAC filters > MAX\n"));
2190 goto exit_proc;
2191 }
2192
2193 for (i=0; i< mac_cnt; i++)
2194 if (get_parameter_from_string(&str_ptr, "MAC=",
2195 PTYPE_STR_HEX, &p_ea[i], 12) != 0) {
2196 WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i));
2197 goto exit_proc;
2198 }
2199
2200 WL_SOFTAP(("MAC_MODE=:%d, MAC_CNT=%d, MACs:..\n", mac_mode, mac_cnt));
2201 for (i = 0; i < mac_cnt; i++) {
2202 WL_SOFTAP(("mac_filt[%d]:", i));
2203 dhd_print_buf(&p_ea[i], 6, 0);
2204 }
2205
2206
2207 mflist_set.mode = mac_mode;
2208 mflist_set.mac_list.count = mac_cnt;
2209 set_ap_mac_list(dev, &mflist_set);
2210
2211
2212 wrqu->data.pointer = NULL;
2213 wrqu->data.length = 0;
2214 ret = 0;
2215
2216 } else {
2217
2218 WL_ERROR(("IWPRIV argument len is 0\n"));
2219 return -1;
2220 }
2221
2222 exit_proc:
2223 kfree(extra);
2224 return ret;
2225}
2226#endif
2227
2228
2229#ifdef SOFTAP
2230
2231static int iwpriv_set_ap_sta_disassoc(struct net_device *dev,
2232 struct iw_request_info *info,
2233 union iwreq_data *wrqu,
2234 char *ext)
2235{
2236 int res = 0;
2237 char sta_mac[6] = {0, 0, 0, 0, 0, 0};
2238 char cmd_buf[256];
2239 char *str_ptr = cmd_buf;
2240
2241 WL_SOFTAP((">>%s called\n args: info->cmd:%x,"
2242 " info->flags:%x, u.data.p:%p, u.data.len:%d\n",
2243 __FUNCTION__, info->cmd, info->flags,
2244 wrqu->data.pointer, wrqu->data.length));
2245
2246 if (wrqu->data.length != 0) {
2247
2248 if (copy_from_user(cmd_buf, wrqu->data.pointer, wrqu->data.length)) {
2249 return -EFAULT;
2250 }
2251
2252 if (get_parameter_from_string(&str_ptr,
2253 "MAC=", PTYPE_STR_HEX, sta_mac, 12) == 0) {
2254 res = wl_iw_softap_deassoc_stations(dev, sta_mac);
2255 } else {
2256 WL_ERROR(("ERROR: STA_MAC= token not found\n"));
2257 }
2258 }
2259
2260 return res;
2261}
2262#endif
2263
2264#endif
2265
2266#if WIRELESS_EXT < 13
2267struct iw_request_info
2268{
2269 __u16 cmd;
2270 __u16 flags;
2271};
2272
2273typedef int (*iw_handler)(struct net_device *dev,
2274 struct iw_request_info *info,
2275 void *wrqu,
2276 char *extra);
2277#endif
2278
2279static int
2280wl_iw_config_commit(
2281 struct net_device *dev,
2282 struct iw_request_info *info,
2283 void *zwrq,
2284 char *extra
2285)
2286{
2287 wlc_ssid_t ssid;
2288 int error;
2289 struct sockaddr bssid;
2290
2291 WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
2292
2293 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
2294 return error;
2295
2296 ssid.SSID_len = dtoh32(ssid.SSID_len);
2297
2298 if (!ssid.SSID_len)
2299 return 0;
2300
2301 bzero(&bssid, sizeof(struct sockaddr));
2302 if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
2303 WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __FUNCTION__, ssid.SSID));
2304 return error;
2305 }
2306
2307 return 0;
2308}
2309
2310static int
2311wl_iw_get_name(
2312 struct net_device *dev,
2313 struct iw_request_info *info,
2314 char *cwrq,
2315 char *extra
2316)
2317{
2318 WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
2319
2320 strcpy(cwrq, "IEEE 802.11-DS");
2321
2322 return 0;
2323}
2324
2325static int
2326wl_iw_set_freq(
2327 struct net_device *dev,
2328 struct iw_request_info *info,
2329 struct iw_freq *fwrq,
2330 char *extra
2331)
2332{
2333 int error, chan;
2334 uint sf = 0;
2335
2336 WL_TRACE(("%s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name));
2337
2338#if defined(SOFTAP)
2339 if (ap_cfg_running) {
2340 WL_TRACE(("%s:>> not executed, 'SOFT_AP is active' \n", __FUNCTION__));
2341 return 0;
2342 }
2343#endif
2344
2345
2346 if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
2347 chan = fwrq->m;
2348 }
2349
2350 else {
2351
2352 if (fwrq->e >= 6) {
2353 fwrq->e -= 6;
2354 while (fwrq->e--)
2355 fwrq->m *= 10;
2356 } else if (fwrq->e < 6) {
2357 while (fwrq->e++ < 6)
2358 fwrq->m /= 10;
2359 }
2360
2361 if (fwrq->m > 4000 && fwrq->m < 5000)
2362 sf = WF_CHAN_FACTOR_4_G;
2363
2364 chan = wf_mhz2channel(fwrq->m, sf);
2365 }
2366
2367 chan = htod32(chan);
2368
2369 if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
2370 return error;
2371
2372 g_wl_iw_params.target_channel = chan;
2373
2374
2375 return -EINPROGRESS;
2376}
2377
2378static int
2379wl_iw_get_freq(
2380 struct net_device *dev,
2381 struct iw_request_info *info,
2382 struct iw_freq *fwrq,
2383 char *extra
2384)
2385{
2386 channel_info_t ci;
2387 int error;
2388
2389 WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
2390
2391 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
2392 return error;
2393
2394
2395 fwrq->m = dtoh32(ci.hw_channel);
2396 fwrq->e = dtoh32(0);
2397 return 0;
2398}
2399
2400static int
2401wl_iw_set_mode(
2402 struct net_device *dev,
2403 struct iw_request_info *info,
2404 __u32 *uwrq,
2405 char *extra
2406)
2407{
2408 int infra = 0, ap = 0, error = 0;
2409
2410 WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
2411
2412 switch (*uwrq) {
2413 case IW_MODE_MASTER:
2414 infra = ap = 1;
2415 break;
2416 case IW_MODE_ADHOC:
2417 case IW_MODE_AUTO:
2418 break;
2419 case IW_MODE_INFRA:
2420 infra = 1;
2421 break;
2422 default:
2423 return -EINVAL;
2424 }
2425 infra = htod32(infra);
2426 ap = htod32(ap);
2427
2428 if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
2429 (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
2430 return error;
2431
2432
2433 return -EINPROGRESS;
2434}
2435
2436static int
2437wl_iw_get_mode(
2438 struct net_device *dev,
2439 struct iw_request_info *info,
2440 __u32 *uwrq,
2441 char *extra
2442)
2443{
2444 int error, infra = 0, ap = 0;
2445
2446 WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
2447
2448 if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
2449 (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
2450 return error;
2451
2452 infra = dtoh32(infra);
2453 ap = dtoh32(ap);
2454 *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
2455
2456 return 0;
2457}
2458
2459static int
2460wl_iw_get_range(
2461 struct net_device *dev,
2462 struct iw_request_info *info,
2463 struct iw_point *dwrq,
2464 char *extra
2465)
2466{
2467 struct iw_range *range = (struct iw_range *) extra;
2468 wl_uint32_list_t *list;
2469 wl_rateset_t rateset;
2470 int8 *channels;
2471 int error, i, k;
2472 uint sf, ch;
2473
2474 int phytype;
2475 int bw_cap = 0, sgi_tx = 0, nmode = 0;
2476 channel_info_t ci;
2477 uint8 nrate_list2copy = 0;
2478 uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
2479 {14, 29, 43, 58, 87, 116, 130, 144},
2480 {27, 54, 81, 108, 162, 216, 243, 270},
2481 {30, 60, 90, 120, 180, 240, 270, 300}};
2482
2483 WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
2484
2485 if (!extra)
2486 return -EINVAL;
2487
2488 channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL);
2489 if (!channels) {
2490 WL_ERROR(("Could not alloc channels\n"));
2491 return -ENOMEM;
2492 }
2493 list = (wl_uint32_list_t *)channels;
2494
2495 dwrq->length = sizeof(struct iw_range);
2496 memset(range, 0, sizeof(*range));
2497
2498
2499 range->min_nwid = range->max_nwid = 0;
2500
2501
2502 list->count = htod32(MAXCHANNEL);
2503 if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) {
2504 kfree(channels);
2505 return error;
2506 }
2507 for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
2508 range->freq[i].i = dtoh32(list->element[i]);
2509
2510 ch = dtoh32(list->element[i]);
2511 if (ch <= CH_MAX_2G_CHANNEL)
2512 sf = WF_CHAN_FACTOR_2_4_G;
2513 else
2514 sf = WF_CHAN_FACTOR_5_G;
2515
2516 range->freq[i].m = wf_channel2mhz(ch, sf);
2517 range->freq[i].e = 6;
2518 }
2519 range->num_frequency = range->num_channels = i;
2520
2521
2522 range->max_qual.qual = 5;
2523
2524 range->max_qual.level = 0x100 - 200;
2525
2526 range->max_qual.noise = 0x100 - 200;
2527
2528 range->sensitivity = 65535;
2529
2530#if WIRELESS_EXT > 11
2531
2532 range->avg_qual.qual = 3;
2533
2534 range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
2535
2536 range->avg_qual.noise = 0x100 - 75;
2537#endif
2538
2539
2540 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) {
2541 kfree(channels);
2542 return error;
2543 }
2544 rateset.count = dtoh32(rateset.count);
2545 range->num_bitrates = rateset.count;
2546 for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
2547 range->bitrate[i] = (rateset.rates[i]& 0x7f) * 500000;
2548 dev_wlc_intvar_get(dev, "nmode", &nmode);
2549 dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
2550
2551 if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
2552 dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
2553 dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
2554 dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t));
2555 ci.hw_channel = dtoh32(ci.hw_channel);
2556
2557 if (bw_cap == 0 ||
2558 (bw_cap == 2 && ci.hw_channel <= 14)) {
2559 if (sgi_tx == 0)
2560 nrate_list2copy = 0;
2561 else
2562 nrate_list2copy = 1;
2563 }
2564 if (bw_cap == 1 ||
2565 (bw_cap == 2 && ci.hw_channel >= 36)) {
2566 if (sgi_tx == 0)
2567 nrate_list2copy = 2;
2568 else
2569 nrate_list2copy = 3;
2570 }
2571 range->num_bitrates += 8;
2572 for (k = 0; i < range->num_bitrates; k++, i++) {
2573
2574 range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000;
2575 }
2576 }
2577
2578
2579 if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) {
2580 kfree(channels);
2581 return error;
2582 }
2583 i = dtoh32(i);
2584 if (i == WLC_PHY_TYPE_A)
2585 range->throughput = 24000000;
2586 else
2587 range->throughput = 1500000;
2588
2589
2590 range->min_rts = 0;
2591 range->max_rts = 2347;
2592 range->min_frag = 256;
2593 range->max_frag = 2346;
2594
2595 range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
2596 range->num_encoding_sizes = 4;
2597 range->encoding_size[0] = WEP1_KEY_SIZE;
2598 range->encoding_size[1] = WEP128_KEY_SIZE;
2599#if WIRELESS_EXT > 17
2600 range->encoding_size[2] = TKIP_KEY_SIZE;
2601#else
2602 range->encoding_size[2] = 0;
2603#endif
2604 range->encoding_size[3] = AES_KEY_SIZE;
2605
2606
2607 range->min_pmp = 0;
2608 range->max_pmp = 0;
2609 range->min_pmt = 0;
2610 range->max_pmt = 0;
2611 range->pmp_flags = 0;
2612 range->pm_capa = 0;
2613
2614
2615 range->num_txpower = 2;
2616 range->txpower[0] = 1;
2617 range->txpower[1] = 255;
2618 range->txpower_capa = IW_TXPOW_MWATT;
2619
2620#if WIRELESS_EXT > 10
2621 range->we_version_compiled = WIRELESS_EXT;
2622 range->we_version_source = 19;
2623
2624
2625 range->retry_capa = IW_RETRY_LIMIT;
2626 range->retry_flags = IW_RETRY_LIMIT;
2627 range->r_time_flags = 0;
2628
2629 range->min_retry = 1;
2630 range->max_retry = 255;
2631
2632 range->min_r_time = 0;
2633 range->max_r_time = 0;
2634#endif
2635
2636#if WIRELESS_EXT > 17
2637 range->enc_capa = IW_ENC_CAPA_WPA;
2638 range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
2639 range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
2640 range->enc_capa |= IW_ENC_CAPA_WPA2;
2641
2642
2643 IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
2644
2645 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
2646 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
2647 IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
2648 IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
2649 IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE);
2650 IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE);
2651 IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
2652#endif
2653
2654 kfree(channels);
2655
2656 return 0;
2657}
2658
2659static int
2660rssi_to_qual(int rssi)
2661{
2662 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
2663 return 0;
2664 else if (rssi <= WL_IW_RSSI_VERY_LOW)
2665 return 1;
2666 else if (rssi <= WL_IW_RSSI_LOW)
2667 return 2;
2668 else if (rssi <= WL_IW_RSSI_GOOD)
2669 return 3;
2670 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
2671 return 4;
2672 else
2673 return 5;
2674}
2675
2676static int
2677wl_iw_set_spy(
2678 struct net_device *dev,
2679 struct iw_request_info *info,
2680 struct iw_point *dwrq,
2681 char *extra
2682)
2683{
2684 wl_iw_t *iw = NETDEV_PRIV(dev);
2685 struct sockaddr *addr = (struct sockaddr *) extra;
2686 int i;
2687
2688 WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
2689
2690 if (!extra)
2691 return -EINVAL;
2692
2693 iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
2694 for (i = 0; i < iw->spy_num; i++)
2695 memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
2696 memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
2697
2698 return 0;
2699}
2700
2701static int
2702wl_iw_get_spy(
2703 struct net_device *dev,
2704 struct iw_request_info *info,
2705 struct iw_point *dwrq,
2706 char *extra
2707)
2708{
2709 wl_iw_t *iw = NETDEV_PRIV(dev);
2710 struct sockaddr *addr = (struct sockaddr *) extra;
2711 struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
2712 int i;
2713
2714 WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
2715
2716 if (!extra)
2717 return -EINVAL;
2718
2719 dwrq->length = iw->spy_num;
2720 for (i = 0; i < iw->spy_num; i++) {
2721 memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
2722 addr[i].sa_family = AF_UNIX;
2723 memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
2724 iw->spy_qual[i].updated = 0;
2725 }
2726
2727 return 0;
2728}
2729
2730
2731static int
2732wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size)
2733{
2734 chanspec_t chanspec = 0;
2735
2736 if (ch != 0) {
2737
2738 join_params->params.chanspec_num = 1;
2739 join_params->params.chanspec_list[0] = ch;
2740
2741 if (join_params->params.chanspec_list[0])
2742 chanspec |= WL_CHANSPEC_BAND_2G;
2743 else
2744 chanspec |= WL_CHANSPEC_BAND_5G;
2745
2746 chanspec |= WL_CHANSPEC_BW_20;
2747 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
2748
2749
2750 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
2751 join_params->params.chanspec_num * sizeof(chanspec_t);
2752
2753
2754 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
2755 join_params->params.chanspec_list[0] |= chanspec;
2756 join_params->params.chanspec_list[0] =
2757 htodchanspec(join_params->params.chanspec_list[0]);
2758
2759 join_params->params.chanspec_num = htod32(join_params->params.chanspec_num);
2760
2761 WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n",
2762 __FUNCTION__, join_params->params.chanspec_list[0]));
2763 }
2764 return 1;
2765}
2766
2767static int
2768wl_iw_set_wap(
2769 struct net_device *dev,
2770 struct iw_request_info *info,
2771 struct sockaddr *awrq,
2772 char *extra
2773)
2774{
2775 int error = -EINVAL;
2776 wl_join_params_t join_params;
2777 int join_params_size;
2778
2779 WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
2780
2781 if (awrq->sa_family != ARPHRD_ETHER) {
2782 WL_ERROR(("Invalid Header...sa_family\n"));
2783 return -EINVAL;
2784 }
2785
2786
2787 if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
2788 scb_val_t scbval;
2789
2790 bzero(&scbval, sizeof(scb_val_t));
2791
2792 (void) dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2793 return 0;
2794 }
2795
2796
2797
2798 memset(&join_params, 0, sizeof(join_params));
2799 join_params_size = sizeof(join_params.ssid);
2800
2801 memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
2802 join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
2803 memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN);
2804
2805
2806
2807 WL_TRACE(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel));
2808 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
2809
2810 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
2811 WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error));
2812 return error;
2813 }
2814
2815 if (g_ssid.SSID_len) {
2816 WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__,
2817 g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data),
2818 g_wl_iw_params.target_channel));
2819 }
2820
2821
2822 memset(&g_ssid, 0, sizeof(g_ssid));
2823 return 0;
2824}
2825
2826static int
2827wl_iw_get_wap(
2828 struct net_device *dev,
2829 struct iw_request_info *info,
2830 struct sockaddr *awrq,
2831 char *extra
2832)
2833{
2834 WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
2835
2836 awrq->sa_family = ARPHRD_ETHER;
2837 memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
2838
2839
2840 (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
2841
2842 return 0;
2843}
2844
2845#if WIRELESS_EXT > 17
2846static int
2847wl_iw_mlme(
2848 struct net_device *dev,
2849 struct iw_request_info *info,
2850 struct sockaddr *awrq,
2851 char *extra
2852)
2853{
2854 struct iw_mlme *mlme;
2855 scb_val_t scbval;
2856 int error = -EINVAL;
2857
2858 WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name));
2859
2860 mlme = (struct iw_mlme *)extra;
2861 if (mlme == NULL) {
2862 WL_ERROR(("Invalid ioctl data.\n"));
2863 return error;
2864 }
2865
2866 scbval.val = mlme->reason_code;
2867 bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
2868
2869 if (mlme->cmd == IW_MLME_DISASSOC) {
2870 scbval.val = htod32(scbval.val);
2871 error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2872 }
2873 else if (mlme->cmd == IW_MLME_DEAUTH) {
2874 scbval.val = htod32(scbval.val);
2875 error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
2876 sizeof(scb_val_t));
2877 }
2878 else {
2879 WL_ERROR(("Invalid ioctl data.\n"));
2880 return error;
2881 }
2882
2883 return error;
2884}
2885#endif
2886
2887#ifndef WL_IW_USE_ISCAN
2888static int
2889wl_iw_get_aplist(
2890 struct net_device *dev,
2891 struct iw_request_info *info,
2892 struct iw_point *dwrq,
2893 char *extra
2894)
2895{
2896 wl_scan_results_t *list;
2897 struct sockaddr *addr = (struct sockaddr *) extra;
2898 struct iw_quality qual[IW_MAX_AP];
2899 wl_bss_info_t *bi = NULL;
2900 int error, i;
2901 uint buflen = dwrq->length;
2902
2903 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2904
2905 if (!extra)
2906 return -EINVAL;
2907
2908
2909 list = kmalloc(buflen, GFP_KERNEL);
2910 if (!list)
2911 return -ENOMEM;
2912 memset(list, 0, buflen);
2913 list->buflen = htod32(buflen);
2914 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
2915 WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
2916 kfree(list);
2917 return error;
2918 }
2919 list->buflen = dtoh32(list->buflen);
2920 list->version = dtoh32(list->version);
2921 list->count = dtoh32(list->count);
2922 if (list->version != WL_BSS_INFO_VERSION) {
2923 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
2924 __FUNCTION__, list->version));
2925 kfree(list);
2926 return -EINVAL;
2927 }
2928
2929 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
2930 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
2931 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
2932 buflen));
2933
2934
2935 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
2936 continue;
2937
2938
2939 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
2940 addr[dwrq->length].sa_family = ARPHRD_ETHER;
2941 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
2942 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
2943 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
2944
2945
2946#if WIRELESS_EXT > 18
2947 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
2948#else
2949 qual[dwrq->length].updated = 7;
2950#endif
2951
2952 dwrq->length++;
2953 }
2954
2955 kfree(list);
2956
2957 if (dwrq->length) {
2958 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
2959
2960 dwrq->flags = 1;
2961 }
2962
2963 return 0;
2964}
2965#endif
2966
2967#ifdef WL_IW_USE_ISCAN
2968static int
2969wl_iw_iscan_get_aplist(
2970 struct net_device *dev,
2971 struct iw_request_info *info,
2972 struct iw_point *dwrq,
2973 char *extra
2974)
2975{
2976 wl_scan_results_t *list;
2977 iscan_buf_t * buf;
2978 iscan_info_t *iscan = g_iscan;
2979
2980 struct sockaddr *addr = (struct sockaddr *) extra;
2981 struct iw_quality qual[IW_MAX_AP];
2982 wl_bss_info_t *bi = NULL;
2983 int i;
2984
2985 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2986
2987 if (!extra)
2988 return -EINVAL;
2989
2990 if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
2991 WL_ERROR(("%s error\n", __FUNCTION__));
2992 return 0;
2993 }
2994
2995 buf = iscan->list_hdr;
2996
2997 while (buf) {
2998 list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
2999 if (list->version != WL_BSS_INFO_VERSION) {
3000 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
3001 __FUNCTION__, list->version));
3002 return -EINVAL;
3003 }
3004
3005 bi = NULL;
3006 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
3007 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
3008 : list->bss_info;
3009 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
3010 WLC_IW_ISCAN_MAXLEN));
3011
3012
3013 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
3014 continue;
3015
3016
3017 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
3018 addr[dwrq->length].sa_family = ARPHRD_ETHER;
3019 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
3020 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
3021 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
3022
3023
3024#if WIRELESS_EXT > 18
3025 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
3026#else
3027 qual[dwrq->length].updated = 7;
3028#endif
3029
3030 dwrq->length++;
3031 }
3032 buf = buf->next;
3033 }
3034 if (dwrq->length) {
3035 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
3036
3037 dwrq->flags = 1;
3038 }
3039
3040 return 0;
3041}
3042
3043static int
3044wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
3045{
3046 int err = 0;
3047
3048 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
3049 params->bss_type = DOT11_BSSTYPE_ANY;
3050 params->scan_type = 0;
3051 params->nprobes = -1;
3052 params->active_time = -1;
3053 params->passive_time = -1;
3054 params->home_time = -1;
3055 params->channel_num = 0;
3056
3057#if defined(CONFIG_FIRST_SCAN)
3058
3059 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
3060 params->passive_time = 30;
3061#endif
3062 params->nprobes = htod32(params->nprobes);
3063 params->active_time = htod32(params->active_time);
3064 params->passive_time = htod32(params->passive_time);
3065 params->home_time = htod32(params->home_time);
3066 if (ssid && ssid->SSID_len)
3067 memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
3068
3069 return err;
3070}
3071
3072static int
3073wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
3074{
3075 int err = 0;
3076
3077 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
3078 iscan->iscan_ex_params_p->action = htod16(action);
3079 iscan->iscan_ex_params_p->scan_duration = htod16(0);
3080
3081 WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes));
3082 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
3083 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
3084 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
3085 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
3086 WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
3087
3088 if ((dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p,
3089 iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
3090 WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
3091 err = -1;
3092 }
3093
3094 return err;
3095}
3096
3097static void
3098wl_iw_timerfunc(ulong data)
3099{
3100 iscan_info_t *iscan = (iscan_info_t *)data;
3101 if (iscan) {
3102 iscan->timer_on = 0;
3103 if (iscan->iscan_state != ISCAN_STATE_IDLE) {
3104 WL_TRACE(("timer trigger\n"));
3105 up(&iscan->tsk_ctl.sema);
3106 }
3107 }
3108}
3109
3110static void
3111wl_iw_set_event_mask(struct net_device *dev)
3112{
3113 char eventmask[WL_EVENTING_MASK_LEN];
3114 char iovbuf[WL_EVENTING_MASK_LEN + 12];
3115
3116 dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
3117 bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
3118 setbit(eventmask, WLC_E_SCAN_COMPLETE);
3119 dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
3120 iovbuf, sizeof(iovbuf));
3121}
3122
3123static uint32
3124wl_iw_iscan_get(iscan_info_t *iscan)
3125{
3126 iscan_buf_t * buf;
3127 iscan_buf_t * ptr;
3128 wl_iscan_results_t * list_buf;
3129 wl_iscan_results_t list;
3130 wl_scan_results_t *results;
3131 uint32 status;
3132 int res = 0;
3133
3134 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3135 if (iscan->list_cur) {
3136 buf = iscan->list_cur;
3137 iscan->list_cur = buf->next;
3138 }
3139 else {
3140 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
3141 if (!buf) {
3142 WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n",
3143 __FUNCTION__));
3144 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3145 return WL_SCAN_RESULTS_NO_MEM;
3146 }
3147 buf->next = NULL;
3148 if (!iscan->list_hdr)
3149 iscan->list_hdr = buf;
3150 else {
3151 ptr = iscan->list_hdr;
3152 while (ptr->next) {
3153 ptr = ptr->next;
3154 }
3155 ptr->next = buf;
3156 }
3157 }
3158 memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
3159 list_buf = (wl_iscan_results_t*)buf->iscan_buf;
3160 results = &list_buf->results;
3161 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
3162 results->version = 0;
3163 results->count = 0;
3164
3165 memset(&list, 0, sizeof(list));
3166 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
3167 res = dev_iw_iovar_getbuf(
3168 iscan->dev,
3169 "iscanresults",
3170 &list,
3171 WL_ISCAN_RESULTS_FIXED_SIZE,
3172 buf->iscan_buf,
3173 WLC_IW_ISCAN_MAXLEN);
3174 if (res == 0) {
3175 results->buflen = dtoh32(results->buflen);
3176 results->version = dtoh32(results->version);
3177 results->count = dtoh32(results->count);
3178 WL_TRACE(("results->count = %d\n", results->count));
3179 WL_TRACE(("results->buflen = %d\n", results->buflen));
3180 status = dtoh32(list_buf->status);
3181 } else {
3182 WL_ERROR(("%s returns error %d\n", __FUNCTION__, res));
3183
3184 status = WL_SCAN_RESULTS_NO_MEM;
3185 }
3186 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3187 return status;
3188}
3189
3190static void
3191wl_iw_force_specific_scan(iscan_info_t *iscan)
3192{
3193 WL_TRACE(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID));
3194#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3195 rtnl_lock();
3196#endif
3197
3198 (void) dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid));
3199
3200#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3201 rtnl_unlock();
3202#endif
3203}
3204
3205static void
3206wl_iw_send_scan_complete(iscan_info_t *iscan)
3207{
3208 union iwreq_data wrqu;
3209
3210 memset(&wrqu, 0, sizeof(wrqu));
3211
3212
3213 wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
3214#if defined(CONFIG_FIRST_SCAN)
3215 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
3216 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY;
3217#endif
3218 WL_TRACE(("Send Event ISCAN complete\n"));
3219}
3220
3221static int
3222_iscan_sysioc_thread(void *data)
3223{
3224 uint32 status;
3225
3226 tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
3227 iscan_info_t *iscan = (iscan_info_t *) tsk_ctl->parent;
3228
3229
3230 static bool iscan_pass_abort = FALSE;
3231
3232 DAEMONIZE("iscan_sysioc");
3233
3234 status = WL_SCAN_RESULTS_PARTIAL;
3235
3236
3237 complete(&tsk_ctl->completed);
3238
3239 while (down_interruptible(&tsk_ctl->sema) == 0) {
3240
3241 SMP_RD_BARRIER_DEPENDS();
3242 if (tsk_ctl->terminated) {
3243 break;
3244 }
3245#if defined(SOFTAP)
3246
3247 if (ap_cfg_running) {
3248 WL_TRACE(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__));
3249 net_os_wake_unlock(iscan->dev);
3250 continue;
3251 }
3252#endif
3253
3254 if (iscan->timer_on) {
3255
3256 iscan->timer_on = 0;
3257 del_timer_sync(&iscan->timer);
3258 }
3259
3260#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3261 rtnl_lock();
3262#endif
3263 status = wl_iw_iscan_get(iscan);
3264#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3265 rtnl_unlock();
3266#endif
3267
3268 if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) {
3269 WL_TRACE(("%s Get results from specific scan status=%d\n", __FUNCTION__, status));
3270 wl_iw_send_scan_complete(iscan);
3271 iscan_pass_abort = FALSE;
3272 status = -1;
3273 }
3274
3275 switch (status) {
3276 case WL_SCAN_RESULTS_PARTIAL:
3277 WL_TRACE(("iscanresults incomplete\n"));
3278#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3279 rtnl_lock();
3280#endif
3281
3282 wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
3283#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3284 rtnl_unlock();
3285#endif
3286
3287 mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms));
3288 iscan->timer_on = 1;
3289 break;
3290 case WL_SCAN_RESULTS_SUCCESS:
3291 WL_TRACE(("iscanresults complete\n"));
3292 iscan->iscan_state = ISCAN_STATE_IDLE;
3293 wl_iw_send_scan_complete(iscan);
3294 break;
3295 case WL_SCAN_RESULTS_PENDING:
3296 WL_TRACE(("iscanresults pending\n"));
3297
3298 mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms));
3299 iscan->timer_on = 1;
3300 break;
3301 case WL_SCAN_RESULTS_ABORTED:
3302 WL_TRACE(("iscanresults aborted\n"));
3303 iscan->iscan_state = ISCAN_STATE_IDLE;
3304 if (g_scan_specified_ssid == 0)
3305 wl_iw_send_scan_complete(iscan);
3306 else {
3307 iscan_pass_abort = TRUE;
3308 wl_iw_force_specific_scan(iscan);
3309 }
3310 break;
3311 case WL_SCAN_RESULTS_NO_MEM:
3312 WL_TRACE(("iscanresults can't alloc memory: skip\n"));
3313 iscan->iscan_state = ISCAN_STATE_IDLE;
3314 break;
3315 default:
3316 WL_TRACE(("iscanresults returned unknown status %d\n", status));
3317 break;
3318 }
3319
3320 net_os_wake_unlock(iscan->dev);
3321 }
3322
3323 if (iscan->timer_on) {
3324 iscan->timer_on = 0;
3325 del_timer_sync(&iscan->timer);
3326 }
3327 complete_and_exit(&tsk_ctl->completed, 0);
3328}
3329#endif
3330
3331#if !defined(CSCAN)
3332
3333static void
3334wl_iw_set_ss_cache_timer_flag(void)
3335{
3336 g_ss_cache_ctrl.m_timer_expired = 1;
3337 WL_TRACE(("%s called\n", __FUNCTION__));
3338}
3339
3340
3341static int
3342wl_iw_init_ss_cache_ctrl(void)
3343{
3344 WL_TRACE(("%s :\n", __FUNCTION__));
3345 g_ss_cache_ctrl.m_prev_scan_mode = 0;
3346 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
3347 g_ss_cache_ctrl.m_cache_head = NULL;
3348 g_ss_cache_ctrl.m_link_down = 0;
3349 g_ss_cache_ctrl.m_timer_expired = 0;
3350 memset(g_ss_cache_ctrl.m_active_bssid, 0, ETHER_ADDR_LEN);
3351
3352 g_ss_cache_ctrl.m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
3353 if (!g_ss_cache_ctrl.m_timer) {
3354 return -ENOMEM;
3355 }
3356 g_ss_cache_ctrl.m_timer->function = (void *)wl_iw_set_ss_cache_timer_flag;
3357 init_timer(g_ss_cache_ctrl.m_timer);
3358
3359 return 0;
3360}
3361
3362
3363
3364static void
3365wl_iw_free_ss_cache(void)
3366{
3367 wl_iw_ss_cache_t *node, *cur;
3368 wl_iw_ss_cache_t **spec_scan_head;
3369
3370 WL_TRACE(("%s called\n", __FUNCTION__));
3371
3372 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3373 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3374 node = *spec_scan_head;
3375
3376 for (;node;) {
3377 WL_TRACE(("%s : SSID - %s\n", __FUNCTION__, node->bss_info->SSID));
3378 cur = node;
3379 node = cur->next;
3380 kfree(cur);
3381 }
3382 *spec_scan_head = NULL;
3383 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3384}
3385
3386
3387
3388static int
3389wl_iw_run_ss_cache_timer(int kick_off)
3390{
3391 struct timer_list **timer;
3392
3393 timer = &g_ss_cache_ctrl.m_timer;
3394
3395 if (*timer) {
3396 if (kick_off) {
3397#ifdef CONFIG_PRESCANNED
3398 (*timer)->expires = jiffies + msecs_to_jiffies(70000);
3399#else
3400 (*timer)->expires = jiffies + msecs_to_jiffies(30000);
3401#endif
3402 add_timer(*timer);
3403 WL_TRACE(("%s : timer starts \n", __FUNCTION__));
3404 } else {
3405 del_timer_sync(*timer);
3406 WL_TRACE(("%s : timer stops \n", __FUNCTION__));
3407 }
3408 }
3409
3410 return 0;
3411}
3412
3413
3414static void
3415wl_iw_release_ss_cache_ctrl(void)
3416{
3417 WL_TRACE(("%s :\n", __FUNCTION__));
3418 wl_iw_free_ss_cache();
3419 wl_iw_run_ss_cache_timer(0);
3420 if (g_ss_cache_ctrl.m_timer) {
3421 kfree(g_ss_cache_ctrl.m_timer);
3422 }
3423}
3424
3425
3426
3427static void
3428wl_iw_reset_ss_cache(void)
3429{
3430 wl_iw_ss_cache_t *node, *prev, *cur;
3431 wl_iw_ss_cache_t **spec_scan_head;
3432
3433 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3434 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3435 node = *spec_scan_head;
3436 prev = node;
3437
3438 for (;node;) {
3439 WL_TRACE(("%s : node SSID %s \n", __FUNCTION__, node->bss_info->SSID));
3440 if (!node->dirty) {
3441 cur = node;
3442 if (cur == *spec_scan_head) {
3443 *spec_scan_head = cur->next;
3444 prev = *spec_scan_head;
3445 }
3446 else {
3447 prev->next = cur->next;
3448 }
3449 node = cur->next;
3450
3451 WL_TRACE(("%s : Del node : SSID %s\n", __FUNCTION__, cur->bss_info->SSID));
3452 kfree(cur);
3453 continue;
3454 }
3455
3456 node->dirty = 0;
3457 prev = node;
3458 node = node->next;
3459 }
3460 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3461}
3462
3463
3464static int
3465wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list)
3466{
3467
3468 wl_iw_ss_cache_t *node, *prev, *leaf;
3469 wl_iw_ss_cache_t **spec_scan_head;
3470 wl_bss_info_t *bi = NULL;
3471 int i;
3472
3473
3474 if (!ss_list->count) {
3475 return 0;
3476 }
3477
3478 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3479 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3480
3481 for (i = 0; i < ss_list->count; i++) {
3482
3483 node = *spec_scan_head;
3484 prev = node;
3485
3486 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3487
3488 WL_TRACE(("%s : find %d with specific SSID %s\n", __FUNCTION__, i, bi->SSID));
3489 for (;node;) {
3490 if (!memcmp(&node->bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3491
3492 WL_TRACE(("dirty marked : SSID %s\n", bi->SSID));
3493 node->dirty = 1;
3494 break;
3495 }
3496 prev = node;
3497 node = node->next;
3498 }
3499
3500 if (node) {
3501 continue;
3502 }
3503
3504 leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
3505 if (!leaf) {
3506 WL_ERROR(("Memory alloc failure %d\n",
3507 bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
3508 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3509 return -ENOMEM;
3510 }
3511
3512 memcpy(leaf->bss_info, bi, bi->length);
3513 leaf->next = NULL;
3514 leaf->dirty = 1;
3515 leaf->count = 1;
3516 leaf->version = ss_list->version;
3517
3518 if (!prev) {
3519 *spec_scan_head = leaf;
3520 }
3521 else {
3522 prev->next = leaf;
3523 }
3524 }
3525 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3526 return 0;
3527}
3528
3529
3530static int
3531wl_iw_merge_scan_cache(struct iw_request_info *info, char *extra, uint buflen_from_user,
3532__u16 *merged_len)
3533{
3534 wl_iw_ss_cache_t *node;
3535 wl_scan_results_t *list_merge;
3536
3537 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3538 node = g_ss_cache_ctrl.m_cache_head;
3539 for (;node;) {
3540 list_merge = (wl_scan_results_t *)&node->buflen;
3541 WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count));
3542 if (buflen_from_user - *merged_len > 0) {
3543 *merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info,
3544 extra + *merged_len, buflen_from_user - *merged_len);
3545 }
3546 else {
3547 WL_TRACE(("%s: exit with break\n", __FUNCTION__));
3548 break;
3549 }
3550 node = node->next;
3551 }
3552 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3553 return 0;
3554}
3555
3556
3557static int
3558wl_iw_delete_bss_from_ss_cache(void *addr)
3559{
3560
3561 wl_iw_ss_cache_t *node, *prev;
3562 wl_iw_ss_cache_t **spec_scan_head;
3563
3564 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3565 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3566 node = *spec_scan_head;
3567 prev = node;
3568 for (;node;) {
3569 if (!memcmp(&node->bss_info->BSSID, addr, ETHER_ADDR_LEN)) {
3570 if (node == *spec_scan_head) {
3571 *spec_scan_head = node->next;
3572 }
3573 else {
3574 prev->next = node->next;
3575 }
3576
3577 WL_TRACE(("%s : Del node : %s\n", __FUNCTION__, node->bss_info->SSID));
3578 kfree(node);
3579 break;
3580 }
3581
3582 prev = node;
3583 node = node->next;
3584 }
3585
3586 memset(addr, 0, ETHER_ADDR_LEN);
3587 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3588 return 0;
3589}
3590
3591#endif
3592
3593static int
3594wl_iw_set_scan(
3595 struct net_device *dev,
3596 struct iw_request_info *info,
3597 union iwreq_data *wrqu,
3598 char *extra
3599)
3600{
3601 int error;
3602 WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name));
3603
3604#ifdef OEM_CHROMIUMOS
3605 g_set_essid_before_scan = FALSE;
3606#endif
3607
3608#if defined(CSCAN)
3609 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3610 return -EINVAL;
3611#endif
3612
3613#if defined(SOFTAP)
3614
3615 if (ap_cfg_running) {
3616 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3617 return 0;
3618 }
3619#endif
3620
3621
3622 if (g_onoff == G_WLAN_SET_OFF)
3623 return 0;
3624
3625
3626 memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
3627#ifndef WL_IW_USE_ISCAN
3628
3629 g_scan_specified_ssid = 0;
3630#endif
3631
3632#if WIRELESS_EXT > 17
3633
3634 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3635 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3636 struct iw_scan_req *req = (struct iw_scan_req *)extra;
3637#if defined(CONFIG_FIRST_SCAN)
3638 if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3639
3640 WL_TRACE(("%s Ignoring SC %s first BC is not done = %d\n",
3641 __FUNCTION__, req->essid,
3642 g_first_broadcast_scan));
3643 return -EBUSY;
3644 }
3645#endif
3646 if (g_scan_specified_ssid) {
3647 WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n",
3648 __FUNCTION__, req->essid));
3649
3650 return -EBUSY;
3651 }
3652 else {
3653 g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID),
3654 req->essid_len);
3655 memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len);
3656 g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len);
3657 g_scan_specified_ssid = 1;
3658 WL_TRACE(("### Specific scan ssid=%s len=%d\n",
3659 g_specific_ssid.SSID, g_specific_ssid.SSID_len));
3660 }
3661 }
3662 }
3663#endif
3664
3665 if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) {
3666 WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error));
3667
3668 g_scan_specified_ssid = 0;
3669 return -EBUSY;
3670 }
3671
3672 return 0;
3673}
3674
3675#ifdef WL_IW_USE_ISCAN
3676int
3677wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
3678{
3679 wlc_ssid_t ssid;
3680 iscan_info_t *iscan = g_iscan;
3681
3682#if defined(CONFIG_FIRST_SCAN)
3683
3684 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) {
3685 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED;
3686 WL_TRACE(("%s: First Brodcast scan was forced\n", __FUNCTION__));
3687 }
3688 else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) {
3689 WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__));
3690 return 0;
3691 }
3692#endif
3693
3694#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3695 if (flag)
3696 rtnl_lock();
3697#endif
3698
3699 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag));
3700 wl_iw_set_event_mask(dev);
3701
3702 WL_TRACE(("+++: Set Broadcast ISCAN\n"));
3703
3704 memset(&ssid, 0, sizeof(ssid));
3705
3706 iscan->list_cur = iscan->list_hdr;
3707 iscan->iscan_state = ISCAN_STATE_SCANING;
3708
3709 memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size);
3710 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
3711 wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
3712
3713#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3714 if (flag)
3715 rtnl_unlock();
3716#endif
3717
3718 mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms));
3719
3720 iscan->timer_on = 1;
3721
3722 return 0;
3723}
3724
3725static int
3726wl_iw_iscan_set_scan(
3727 struct net_device *dev,
3728 struct iw_request_info *info,
3729 union iwreq_data *wrqu,
3730 char *extra
3731)
3732{
3733 wlc_ssid_t ssid;
3734 iscan_info_t *iscan = g_iscan;
3735 int ret = 0;
3736
3737 WL_TRACE_SCAN(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
3738
3739#if defined(CSCAN)
3740 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3741 return -EINVAL;
3742#endif
3743
3744 net_os_wake_lock(dev);
3745
3746
3747#if defined(SOFTAP)
3748 if (ap_cfg_running) {
3749 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3750 goto set_scan_end;
3751 }
3752#endif
3753
3754 if (g_onoff == G_WLAN_SET_OFF) {
3755 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
3756 goto set_scan_end;
3757 }
3758
3759#ifdef PNO_SUPPORT
3760
3761 if (dhd_dev_get_pno_status(dev)) {
3762 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
3763 }
3764#endif
3765
3766
3767 if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
3768 WL_ERROR(("%s error \n", __FUNCTION__));
3769 goto set_scan_end;
3770 }
3771
3772 if (g_scan_specified_ssid) {
3773 WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n",
3774 __FUNCTION__));
3775 ret = EBUSY;
3776 goto set_scan_end;
3777 }
3778
3779
3780 memset(&ssid, 0, sizeof(ssid));
3781
3782#if WIRELESS_EXT > 17
3783
3784 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3785 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3786 int as = 0;
3787 struct iw_scan_req *req = (struct iw_scan_req *)extra;
3788
3789 ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
3790 memcpy(ssid.SSID, req->essid, ssid.SSID_len);
3791 ssid.SSID_len = htod32(ssid.SSID_len);
3792 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
3793 wl_iw_set_event_mask(dev);
3794 ret = wl_iw_set_scan(dev, info, wrqu, extra);
3795 goto set_scan_end;
3796 }
3797 else {
3798 g_scan_specified_ssid = 0;
3799
3800 if (iscan->iscan_state == ISCAN_STATE_SCANING) {
3801 WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__));
3802 goto set_scan_end;
3803 }
3804 }
3805 }
3806#endif
3807
3808#if defined(CONFIG_FIRST_SCAN) && !defined(CSCAN)
3809 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3810 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
3811
3812 WL_ERROR(("%s Clean up First scan flag which is %d\n",
3813 __FUNCTION__, g_first_broadcast_scan));
3814 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
3815 }
3816 else {
3817 WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n",
3818 __FUNCTION__, g_first_counter_scans));
3819 ret = -EBUSY;
3820 goto set_scan_end;
3821 }
3822 }
3823#endif
3824
3825 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
3826
3827set_scan_end:
3828 net_os_wake_unlock(dev);
3829 return ret;
3830}
3831#endif
3832
3833#if WIRELESS_EXT > 17
3834static bool
3835ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
3836{
3837
3838
3839 uint8 *ie = *wpaie;
3840
3841
3842 if ((ie[1] >= 6) &&
3843 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
3844 return TRUE;
3845 }
3846
3847
3848 ie += ie[1] + 2;
3849
3850 *tlvs_len -= (int)(ie - *tlvs);
3851
3852 *tlvs = ie;
3853 return FALSE;
3854}
3855
3856static bool
3857ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
3858{
3859
3860
3861 uint8 *ie = *wpsie;
3862
3863
3864 if ((ie[1] >= 4) &&
3865 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
3866 return TRUE;
3867 }
3868
3869
3870 ie += ie[1] + 2;
3871
3872 *tlvs_len -= (int)(ie - *tlvs);
3873
3874 *tlvs = ie;
3875 return FALSE;
3876}
3877#endif
3878
3879
3880static int
3881wl_iw_handle_scanresults_ies(char **event_p, char *end,
3882 struct iw_request_info *info, wl_bss_info_t *bi)
3883{
3884#if WIRELESS_EXT > 17
3885 struct iw_event iwe;
3886 char *event;
3887
3888 event = *event_p;
3889 if (bi->ie_length) {
3890
3891 bcm_tlv_t *ie;
3892 uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3893 int ptr_len = bi->ie_length;
3894
3895 if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
3896 iwe.cmd = IWEVGENIE;
3897 iwe.u.data.length = ie->len + 2;
3898 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3899 }
3900 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3901
3902 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3903
3904 if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3905 iwe.cmd = IWEVGENIE;
3906 iwe.u.data.length = ie->len + 2;
3907 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3908 break;
3909 }
3910 }
3911
3912 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3913 ptr_len = bi->ie_length;
3914 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3915 if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3916 iwe.cmd = IWEVGENIE;
3917 iwe.u.data.length = ie->len + 2;
3918 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3919 break;
3920 }
3921 }
3922
3923 *event_p = event;
3924 }
3925#endif
3926
3927 return 0;
3928}
3929
3930#ifndef CSCAN
3931static uint
3932wl_iw_get_scan_prep(
3933 wl_scan_results_t *list,
3934 struct iw_request_info *info,
3935 char *extra,
3936 short max_size)
3937{
3938 int i, j;
3939 struct iw_event iwe;
3940 wl_bss_info_t *bi = NULL;
3941 char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
3942 int ret = 0;
3943
3944 if (!list) {
3945 WL_ERROR(("%s: Null list pointer", __FUNCTION__));
3946 return ret;
3947 }
3948
3949
3950
3951 for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
3952 if (list->version != WL_BSS_INFO_VERSION) {
3953 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
3954 __FUNCTION__, list->version));
3955 return ret;
3956 }
3957
3958 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
3959
3960 WL_TRACE(("%s : %s\n", __FUNCTION__, bi->SSID));
3961
3962
3963 iwe.cmd = SIOCGIWAP;
3964 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
3965 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
3966 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
3967
3968 iwe.u.data.length = dtoh32(bi->SSID_len);
3969 iwe.cmd = SIOCGIWESSID;
3970 iwe.u.data.flags = 1;
3971 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
3972
3973
3974 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
3975 iwe.cmd = SIOCGIWMODE;
3976 if (dtoh16(bi->capability) & DOT11_CAP_ESS)
3977 iwe.u.mode = IW_MODE_INFRA;
3978 else
3979 iwe.u.mode = IW_MODE_ADHOC;
3980 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
3981 }
3982
3983
3984 iwe.cmd = SIOCGIWFREQ;
3985 iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
3986 CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
3987 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
3988 iwe.u.freq.e = 6;
3989 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
3990
3991
3992 iwe.cmd = IWEVQUAL;
3993 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
3994 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
3995 iwe.u.qual.noise = 0x100 + bi->phy_noise;
3996 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
3997
3998
3999 wl_iw_handle_scanresults_ies(&event, end, info, bi);
4000
4001
4002 iwe.cmd = SIOCGIWENCODE;
4003 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
4004 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4005 else
4006 iwe.u.data.flags = IW_ENCODE_DISABLED;
4007 iwe.u.data.length = 0;
4008 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
4009
4010
4011 if (bi->rateset.count) {
4012 if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) {
4013 value = event + IW_EV_LCP_LEN;
4014 iwe.cmd = SIOCGIWRATE;
4015
4016 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4017 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
4018 iwe.u.bitrate.value =
4019 (bi->rateset.rates[j] & 0x7f) * 500000;
4020 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
4021 IW_EV_PARAM_LEN);
4022 }
4023 event = value;
4024 }
4025 }
4026 }
4027
4028 if ((ret = (event - extra)) < 0) {
4029 WL_ERROR(("==> Wrong size\n"));
4030 ret = 0;
4031 }
4032
4033 WL_TRACE(("%s: size=%d bytes prepared \n", __FUNCTION__, (unsigned int)(event - extra)));
4034 return (uint)ret;
4035}
4036
4037static int
4038wl_iw_get_scan(
4039 struct net_device *dev,
4040 struct iw_request_info *info,
4041 struct iw_point *dwrq,
4042 char *extra
4043)
4044{
4045 channel_info_t ci;
4046 wl_scan_results_t *list_merge;
4047 wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
4048 int error;
4049 uint buflen_from_user = dwrq->length;
4050 uint len = G_SCAN_RESULTS;
4051 __u16 len_ret = 0;
4052#if !defined(CSCAN)
4053 __u16 merged_len = 0;
4054#endif
4055#if defined(WL_IW_USE_ISCAN)
4056 iscan_info_t *iscan = g_iscan;
4057 iscan_buf_t * p_buf;
4058#if !defined(CSCAN)
4059 uint32 counter = 0;
4060#endif
4061#endif
4062
4063 WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
4064
4065 if (!extra) {
4066 WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name));
4067 return -EINVAL;
4068 }
4069
4070
4071 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
4072 return error;
4073 ci.scan_channel = dtoh32(ci.scan_channel);
4074 if (ci.scan_channel)
4075 return -EAGAIN;
4076
4077#if !defined(CSCAN)
4078 if (g_ss_cache_ctrl.m_timer_expired) {
4079 wl_iw_free_ss_cache();
4080 g_ss_cache_ctrl.m_timer_expired ^= 1;
4081 }
4082 if ((!g_scan_specified_ssid && g_ss_cache_ctrl.m_prev_scan_mode) ||
4083 g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
4084 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4085
4086 wl_iw_reset_ss_cache();
4087 }
4088 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
4089 if (g_scan_specified_ssid) {
4090 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4091 }
4092 else {
4093 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
4094 }
4095#endif
4096
4097
4098
4099 if (g_scan_specified_ssid) {
4100
4101 list = kmalloc(len, GFP_KERNEL);
4102 if (!list) {
4103 WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", dev->name));
4104 g_scan_specified_ssid = 0;
4105 return -ENOMEM;
4106 }
4107 }
4108
4109 memset(list, 0, len);
4110 list->buflen = htod32(len);
4111 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) {
4112 WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error));
4113 dwrq->length = len;
4114 if (g_scan_specified_ssid) {
4115 g_scan_specified_ssid = 0;
4116 kfree(list);
4117 }
4118 return 0;
4119 }
4120 list->buflen = dtoh32(list->buflen);
4121 list->version = dtoh32(list->version);
4122 list->count = dtoh32(list->count);
4123
4124
4125 if (list->version != WL_BSS_INFO_VERSION) {
4126 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
4127 __FUNCTION__, list->version));
4128 if (g_scan_specified_ssid) {
4129 g_scan_specified_ssid = 0;
4130 kfree(list);
4131 }
4132 return -EINVAL;
4133 }
4134
4135#if !defined(CSCAN)
4136 if (g_scan_specified_ssid) {
4137
4138 wl_iw_add_bss_to_ss_cache(list);
4139 kfree(list);
4140 }
4141#endif
4142
4143#if !defined(CSCAN)
4144 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
4145#if defined(WL_IW_USE_ISCAN)
4146 if (g_scan_specified_ssid)
4147 WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count));
4148 p_buf = iscan->list_hdr;
4149
4150 while (p_buf != iscan->list_cur) {
4151 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4152 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4153 counter += list_merge->count;
4154 if (list_merge->count > 0)
4155 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4156 extra+len_ret, buflen_from_user -len_ret);
4157 p_buf = p_buf->next;
4158 }
4159 WL_TRACE(("%s merged with total Bcast APs=%d\n", __FUNCTION__, counter));
4160#else
4161 list_merge = (wl_scan_results_t *) g_scan;
4162 len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user);
4163#endif
4164 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
4165 if (g_ss_cache_ctrl.m_link_down) {
4166
4167 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4168 }
4169
4170 wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len);
4171 len_ret += merged_len;
4172 wl_iw_run_ss_cache_timer(0);
4173 wl_iw_run_ss_cache_timer(1);
4174#else
4175
4176
4177 if (g_scan_specified_ssid) {
4178 WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count));
4179 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4180 kfree(list);
4181
4182#if defined(WL_IW_USE_ISCAN)
4183 p_buf = iscan->list_hdr;
4184
4185 while (p_buf != iscan->list_cur) {
4186 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4187 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4188 if (list_merge->count > 0)
4189 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4190 extra+len_ret, buflen_from_user -len_ret);
4191 p_buf = p_buf->next;
4192 }
4193#else
4194 list_merge = (wl_scan_results_t *) g_scan;
4195 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4196 if (list_merge->count > 0)
4197 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret,
4198 buflen_from_user -len_ret);
4199#endif
4200 }
4201 else {
4202 list = (wl_scan_results_t *) g_scan;
4203 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4204 }
4205#endif
4206
4207#if defined(WL_IW_USE_ISCAN)
4208
4209 g_scan_specified_ssid = 0;
4210#endif
4211
4212 if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
4213 len = len_ret;
4214
4215 dwrq->length = len;
4216 dwrq->flags = 0;
4217
4218 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count));
4219 return 0;
4220}
4221#endif
4222
4223#if defined(WL_IW_USE_ISCAN)
4224static int
4225wl_iw_iscan_get_scan(
4226 struct net_device *dev,
4227 struct iw_request_info *info,
4228 struct iw_point *dwrq,
4229 char *extra
4230)
4231{
4232 wl_scan_results_t *list;
4233 struct iw_event iwe;
4234 wl_bss_info_t *bi = NULL;
4235 int ii, j;
4236 int apcnt;
4237 char *event = extra, *end = extra + dwrq->length, *value;
4238 iscan_info_t *iscan = g_iscan;
4239 iscan_buf_t * p_buf;
4240 uint32 counter = 0;
4241 uint8 channel;
4242#if !defined(CSCAN)
4243 __u16 merged_len = 0;
4244 uint buflen_from_user = dwrq->length;
4245#endif
4246
4247 WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length));
4248
4249#if defined(SOFTAP)
4250 if (ap_cfg_running) {
4251 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
4252 return -EINVAL;
4253 }
4254#endif
4255
4256 if (!extra) {
4257 WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", dev->name));
4258 return -EINVAL;
4259 }
4260
4261#if defined(CONFIG_FIRST_SCAN)
4262 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) {
4263 WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n",
4264 dev->name, __FUNCTION__));
4265 return -EAGAIN;
4266 }
4267#endif
4268
4269 if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
4270 WL_ERROR(("%ssysioc_pid\n", __FUNCTION__));
4271 return EAGAIN;
4272 }
4273
4274
4275
4276#if !defined(CSCAN)
4277 if (g_ss_cache_ctrl.m_timer_expired) {
4278 wl_iw_free_ss_cache();
4279 g_ss_cache_ctrl.m_timer_expired ^= 1;
4280 }
4281 if (g_scan_specified_ssid) {
4282 return wl_iw_get_scan(dev, info, dwrq, extra);
4283 }
4284 else {
4285 if (g_ss_cache_ctrl.m_link_down) {
4286
4287 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4288 }
4289 if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
4290 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4291
4292 wl_iw_reset_ss_cache();
4293 }
4294 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
4295 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
4296 }
4297#endif
4298
4299 WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
4300 apcnt = 0;
4301 p_buf = iscan->list_hdr;
4302
4303 while (p_buf != iscan->list_cur) {
4304 list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4305
4306 counter += list->count;
4307
4308 if (list->version != WL_BSS_INFO_VERSION) {
4309 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
4310 __FUNCTION__, list->version));
4311 return -EINVAL;
4312 }
4313
4314 bi = NULL;
4315 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
4316 bi = (bi ?
4317 (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) :
4318 list->bss_info);
4319 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
4320 WLC_IW_ISCAN_MAXLEN));
4321
4322
4323 if (event + ETHER_ADDR_LEN + bi->SSID_len +
4324 IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end)
4325 return -E2BIG;
4326
4327 iwe.cmd = SIOCGIWAP;
4328 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
4329 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
4330 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
4331
4332
4333 iwe.u.data.length = dtoh32(bi->SSID_len);
4334 iwe.cmd = SIOCGIWESSID;
4335 iwe.u.data.flags = 1;
4336 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
4337
4338
4339 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
4340 iwe.cmd = SIOCGIWMODE;
4341 if (dtoh16(bi->capability) & DOT11_CAP_ESS)
4342 iwe.u.mode = IW_MODE_INFRA;
4343 else
4344 iwe.u.mode = IW_MODE_ADHOC;
4345 event = IWE_STREAM_ADD_EVENT(info, event, end,
4346 &iwe, IW_EV_UINT_LEN);
4347 }
4348
4349
4350 iwe.cmd = SIOCGIWFREQ;
4351 channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
4352 iwe.u.freq.m = wf_channel2mhz(channel,
4353 channel <= CH_MAX_2G_CHANNEL ?
4354 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
4355 iwe.u.freq.e = 6;
4356 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
4357
4358
4359 iwe.cmd = IWEVQUAL;
4360 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
4361 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
4362 iwe.u.qual.noise = 0x100 + bi->phy_noise;
4363 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
4364
4365
4366 wl_iw_handle_scanresults_ies(&event, end, info, bi);
4367
4368
4369 iwe.cmd = SIOCGIWENCODE;
4370 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
4371 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4372 else
4373 iwe.u.data.flags = IW_ENCODE_DISABLED;
4374 iwe.u.data.length = 0;
4375 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
4376
4377
4378 if (bi->rateset.count) {
4379 if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
4380 return -E2BIG;
4381
4382 value = event + IW_EV_LCP_LEN;
4383 iwe.cmd = SIOCGIWRATE;
4384
4385 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4386 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
4387 iwe.u.bitrate.value =
4388 (bi->rateset.rates[j] & 0x7f) * 500000;
4389 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
4390 IW_EV_PARAM_LEN);
4391 }
4392 event = value;
4393 }
4394 }
4395 p_buf = p_buf->next;
4396 }
4397
4398 dwrq->length = event - extra;
4399 dwrq->flags = 0;
4400
4401#if !defined(CSCAN)
4402
4403 wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
4404 dwrq->length += merged_len;
4405 wl_iw_run_ss_cache_timer(0);
4406 wl_iw_run_ss_cache_timer(1);
4407#endif
4408
4409#if defined(CONFIG_FIRST_SCAN)
4410 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
4411#endif
4412
4413 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
4414
4415 return 0;
4416}
4417#endif
4418
4419#define WL_JOIN_PARAMS_MAX 1600
4420#ifdef CONFIG_PRESCANNED
4421static int
4422check_prescan(wl_join_params_t *join_params, int *join_params_size)
4423{
4424 int cnt = 0;
4425 int indx = 0;
4426 wl_iw_ss_cache_t *node = NULL;
4427 wl_bss_info_t *bi = NULL;
4428 iscan_info_t *iscan = g_iscan;
4429 iscan_buf_t * buf;
4430 wl_scan_results_t *list;
4431 char *destbuf;
4432
4433 buf = iscan->list_hdr;
4434
4435 while (buf) {
4436 list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
4437 bi = NULL;
4438 for (indx = 0; indx < list->count; indx++) {
4439 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
4440 : list->bss_info;
4441 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
4442 continue;
4443 if ((dtoh32(bi->SSID_len) != join_params->ssid.SSID_len) ||
4444 memcmp(bi->SSID, join_params->ssid.SSID,
4445 join_params->ssid.SSID_len))
4446 continue;
4447 memcpy(&join_params->params.chanspec_list[cnt],
4448 &bi->chanspec, sizeof(chanspec_t));
4449 WL_ERROR(("iscan : chanspec :%d, count %d \n", bi->chanspec, cnt));
4450 cnt++;
4451 }
4452 buf = buf->next;
4453 }
4454
4455 if (!cnt) {
4456 MUTEX_LOCK_WL_SCAN_SET();
4457 node = g_ss_cache_ctrl.m_cache_head;
4458 for (; node; ) {
4459 if (!memcmp(&node->bss_info->SSID, join_params->ssid.SSID,
4460 join_params->ssid.SSID_len)) {
4461 memcpy(&join_params->params.chanspec_list[cnt],
4462 &node->bss_info->chanspec, sizeof(chanspec_t));
4463 WL_ERROR(("cache_scan : chanspec :%d, count %d \n",
4464 (int)node->bss_info->chanspec, cnt));
4465 cnt++;
4466 }
4467 node = node->next;
4468 }
4469 MUTEX_UNLOCK_WL_SCAN_SET();
4470 }
4471
4472 if (!cnt) {
4473 return 0;
4474 }
4475
4476 destbuf = (char *)&join_params->params.chanspec_list[cnt];
4477 *join_params_size = destbuf - (char*)join_params;
4478 join_params->ssid.SSID_len = htod32(g_ssid.SSID_len);
4479 memcpy(&(join_params->params.bssid), &ether_bcast, ETHER_ADDR_LEN);
4480 join_params->params.chanspec_num = htod32(cnt);
4481
4482 if ((*join_params_size) > WL_JOIN_PARAMS_MAX) {
4483 WL_ERROR(("can't fit bssids for all %d APs found\n", cnt));
4484 kfree(join_params);
4485 return 0;
4486 }
4487
4488 WL_ERROR(("Passing %d channel/bssid pairs.\n", cnt));
4489 return cnt;
4490}
4491#endif
4492
4493static int
4494wl_iw_set_essid(
4495 struct net_device *dev,
4496 struct iw_request_info *info,
4497 struct iw_point *dwrq,
4498 char *extra
4499)
4500{
4501 int error;
4502 wl_join_params_t *join_params;
4503 int join_params_size;
4504
4505 WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
4506
4507 RETURN_IF_EXTRA_NULL(extra);
4508
4509#ifdef OEM_CHROMIUMOS
4510 if (g_set_essid_before_scan)
4511 return -EAGAIN;
4512#endif
4513 if (!(join_params = kmalloc(WL_JOIN_PARAMS_MAX, GFP_KERNEL))) {
4514 WL_ERROR(("allocation failed for join_params size is %d\n", WL_JOIN_PARAMS_MAX));
4515 return -ENOMEM;
4516 }
4517
4518 memset(join_params, 0, WL_JOIN_PARAMS_MAX);
4519
4520
4521 memset(&g_ssid, 0, sizeof(g_ssid));
4522
4523 if (dwrq->length && extra) {
4524#if WIRELESS_EXT > 20
4525 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length);
4526#else
4527 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length-1);
4528#endif
4529 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
4530
4531#ifdef CONFIG_PRESCANNED
4532 memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
4533 join_params->ssid.SSID_len = g_ssid.SSID_len;
4534
4535 if (check_prescan(join_params, &join_params_size)) {
4536 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID,
4537 join_params, join_params_size))) {
4538 WL_ERROR(("Invalid ioctl data=%d\n", error));
4539 kfree(join_params);
4540 return error;
4541 }
4542 kfree(join_params);
4543 return 0;
4544 } else {
4545 WL_ERROR(("No matched found\n Trying to join to specific channel\n"));
4546 }
4547#endif
4548 } else {
4549
4550 g_ssid.SSID_len = 0;
4551 }
4552 g_ssid.SSID_len = htod32(g_ssid.SSID_len);
4553
4554
4555 memset(join_params, 0, sizeof(*join_params));
4556 join_params_size = sizeof(join_params->ssid);
4557
4558 memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
4559 join_params->ssid.SSID_len = htod32(g_ssid.SSID_len);
4560 memcpy(&(join_params->params.bssid), &ether_bcast, ETHER_ADDR_LEN);
4561
4562
4563
4564 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, join_params, &join_params_size);
4565
4566 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, join_params, join_params_size))) {
4567 WL_ERROR(("Invalid ioctl data=%d\n", error));
4568 return error;
4569 }
4570
4571 if (g_ssid.SSID_len) {
4572 WL_ERROR(("%s: join SSID=%s ch=%d\n", __FUNCTION__,
4573 g_ssid.SSID, g_wl_iw_params.target_channel));
4574 }
4575 kfree(join_params);
4576 return 0;
4577}
4578
4579static int
4580wl_iw_get_essid(
4581 struct net_device *dev,
4582 struct iw_request_info *info,
4583 struct iw_point *dwrq,
4584 char *extra
4585)
4586{
4587 wlc_ssid_t ssid;
4588 int error;
4589
4590 WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
4591
4592 if (!extra)
4593 return -EINVAL;
4594
4595 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
4596 WL_ERROR(("Error getting the SSID\n"));
4597 return error;
4598 }
4599
4600 ssid.SSID_len = dtoh32(ssid.SSID_len);
4601
4602
4603 memcpy(extra, ssid.SSID, ssid.SSID_len);
4604
4605 dwrq->length = ssid.SSID_len;
4606
4607 dwrq->flags = 1;
4608
4609 return 0;
4610}
4611
4612static int
4613wl_iw_set_nick(
4614 struct net_device *dev,
4615 struct iw_request_info *info,
4616 struct iw_point *dwrq,
4617 char *extra
4618)
4619{
4620 wl_iw_t *iw = NETDEV_PRIV(dev);
4621
4622 WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
4623
4624 if (!extra)
4625 return -EINVAL;
4626
4627
4628 if (dwrq->length > sizeof(iw->nickname))
4629 return -E2BIG;
4630
4631 memcpy(iw->nickname, extra, dwrq->length);
4632 iw->nickname[dwrq->length - 1] = '\0';
4633
4634 return 0;
4635}
4636
4637static int
4638wl_iw_get_nick(
4639 struct net_device *dev,
4640 struct iw_request_info *info,
4641 struct iw_point *dwrq,
4642 char *extra
4643)
4644{
4645 wl_iw_t *iw = NETDEV_PRIV(dev);
4646
4647 WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
4648
4649 if (!extra)
4650 return -EINVAL;
4651
4652 strcpy(extra, iw->nickname);
4653 dwrq->length = strlen(extra) + 1;
4654
4655 return 0;
4656}
4657
4658static int
4659wl_iw_set_rate(
4660 struct net_device *dev,
4661 struct iw_request_info *info,
4662 struct iw_param *vwrq,
4663 char *extra
4664)
4665{
4666 wl_rateset_t rateset;
4667 int error, rate, i, error_bg, error_a;
4668
4669 WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
4670
4671
4672 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
4673 return error;
4674
4675 rateset.count = dtoh32(rateset.count);
4676
4677 if (vwrq->value < 0) {
4678
4679 rate = rateset.rates[rateset.count - 1] & 0x7f;
4680 } else if (vwrq->value < rateset.count) {
4681
4682 rate = rateset.rates[vwrq->value] & 0x7f;
4683 } else {
4684
4685 rate = vwrq->value / 500000;
4686 }
4687
4688 if (vwrq->fixed) {
4689
4690 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
4691 error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
4692
4693 if (error_bg && error_a)
4694 return (error_bg | error_a);
4695 } else {
4696
4697
4698 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
4699
4700 error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
4701
4702 if (error_bg && error_a)
4703 return (error_bg | error_a);
4704
4705
4706 for (i = 0; i < rateset.count; i++)
4707 if ((rateset.rates[i] & 0x7f) > rate)
4708 break;
4709 rateset.count = htod32(i);
4710
4711
4712 if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
4713 return error;
4714 }
4715
4716 return 0;
4717}
4718
4719static int
4720wl_iw_get_rate(
4721 struct net_device *dev,
4722 struct iw_request_info *info,
4723 struct iw_param *vwrq,
4724 char *extra
4725)
4726{
4727 int error, rate;
4728
4729 WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
4730
4731
4732 if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
4733 return error;
4734 rate = dtoh32(rate);
4735 vwrq->value = rate * 500000;
4736
4737 return 0;
4738}
4739
4740static int
4741wl_iw_set_rts(
4742 struct net_device *dev,
4743 struct iw_request_info *info,
4744 struct iw_param *vwrq,
4745 char *extra
4746)
4747{
4748 int error, rts;
4749
4750 WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
4751
4752 if (vwrq->disabled)
4753 rts = DOT11_DEFAULT_RTS_LEN;
4754 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
4755 return -EINVAL;
4756 else
4757 rts = vwrq->value;
4758
4759 if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
4760 return error;
4761
4762 return 0;
4763}
4764
4765static int
4766wl_iw_get_rts(
4767 struct net_device *dev,
4768 struct iw_request_info *info,
4769 struct iw_param *vwrq,
4770 char *extra
4771)
4772{
4773 int error, rts;
4774
4775 WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
4776
4777 if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
4778 return error;
4779
4780 vwrq->value = rts;
4781 vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
4782 vwrq->fixed = 1;
4783
4784 return 0;
4785}
4786
4787static int
4788wl_iw_set_frag(
4789 struct net_device *dev,
4790 struct iw_request_info *info,
4791 struct iw_param *vwrq,
4792 char *extra
4793)
4794{
4795 int error, frag;
4796
4797 WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
4798
4799 if (vwrq->disabled)
4800 frag = DOT11_DEFAULT_FRAG_LEN;
4801 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
4802 return -EINVAL;
4803 else
4804 frag = vwrq->value;
4805
4806 if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
4807 return error;
4808
4809 return 0;
4810}
4811
4812static int
4813wl_iw_get_frag(
4814 struct net_device *dev,
4815 struct iw_request_info *info,
4816 struct iw_param *vwrq,
4817 char *extra
4818)
4819{
4820 int error, fragthreshold;
4821
4822 WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
4823
4824 if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
4825 return error;
4826
4827 vwrq->value = fragthreshold;
4828 vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
4829 vwrq->fixed = 1;
4830
4831 return 0;
4832}
4833
4834static int
4835wl_iw_set_txpow(
4836 struct net_device *dev,
4837 struct iw_request_info *info,
4838 struct iw_param *vwrq,
4839 char *extra
4840)
4841{
4842 int error, disable;
4843 uint16 txpwrmw;
4844 WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
4845
4846
4847 disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
4848 disable += WL_RADIO_SW_DISABLE << 16;
4849
4850 disable = htod32(disable);
4851 if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
4852 return error;
4853
4854
4855 if (disable & WL_RADIO_SW_DISABLE)
4856 return 0;
4857
4858
4859 if (!(vwrq->flags & IW_TXPOW_MWATT))
4860 return -EINVAL;
4861
4862
4863 if (vwrq->value < 0)
4864 return 0;
4865
4866 if (vwrq->value > 0xffff) txpwrmw = 0xffff;
4867 else txpwrmw = (uint16)vwrq->value;
4868
4869
4870 error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
4871 return error;
4872}
4873
4874static int
4875wl_iw_get_txpow(
4876 struct net_device *dev,
4877 struct iw_request_info *info,
4878 struct iw_param *vwrq,
4879 char *extra
4880)
4881{
4882 int error, disable, txpwrdbm;
4883 uint8 result;
4884
4885 WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
4886
4887 if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
4888 (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
4889 return error;
4890
4891 disable = dtoh32(disable);
4892 result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
4893 vwrq->value = (int32)bcm_qdbm_to_mw(result);
4894 vwrq->fixed = 0;
4895 vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
4896 vwrq->flags = IW_TXPOW_MWATT;
4897
4898 return 0;
4899}
4900
4901#if WIRELESS_EXT > 10
4902static int
4903wl_iw_set_retry(
4904 struct net_device *dev,
4905 struct iw_request_info *info,
4906 struct iw_param *vwrq,
4907 char *extra
4908)
4909{
4910 int error, lrl, srl;
4911
4912 WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
4913
4914
4915 if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
4916 return -EINVAL;
4917
4918
4919 if (vwrq->flags & IW_RETRY_LIMIT) {
4920
4921
4922#if WIRELESS_EXT > 20
4923 if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) ||
4924 !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) {
4925#else
4926 if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
4927#endif
4928 lrl = htod32(vwrq->value);
4929 if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
4930 return error;
4931 }
4932
4933
4934#if WIRELESS_EXT > 20
4935 if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) ||
4936 !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) {
4937#else
4938 if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
4939#endif
4940 srl = htod32(vwrq->value);
4941 if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
4942 return error;
4943 }
4944 }
4945 return 0;
4946}
4947
4948static int
4949wl_iw_get_retry(
4950 struct net_device *dev,
4951 struct iw_request_info *info,
4952 struct iw_param *vwrq,
4953 char *extra
4954)
4955{
4956 int error, lrl, srl;
4957
4958 WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
4959
4960 vwrq->disabled = 0;
4961
4962
4963 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
4964 return -EINVAL;
4965
4966
4967 if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
4968 (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
4969 return error;
4970
4971 lrl = dtoh32(lrl);
4972 srl = dtoh32(srl);
4973
4974
4975 if (vwrq->flags & IW_RETRY_MAX) {
4976 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
4977 vwrq->value = lrl;
4978 } else {
4979 vwrq->flags = IW_RETRY_LIMIT;
4980 vwrq->value = srl;
4981 if (srl != lrl)
4982 vwrq->flags |= IW_RETRY_MIN;
4983 }
4984
4985 return 0;
4986}
4987#endif
4988
4989static int
4990wl_iw_set_encode(
4991 struct net_device *dev,
4992 struct iw_request_info *info,
4993 struct iw_point *dwrq,
4994 char *extra
4995)
4996{
4997 wl_wsec_key_t key;
4998 int error, val, wsec;
4999
5000 WL_TRACE(("%s: SIOCSIWENCODE index %d, len %d, flags %04x (%s%s%s%s%s)\n",
5001 dev->name, dwrq->flags & IW_ENCODE_INDEX, dwrq->length, dwrq->flags,
5002 dwrq->flags & IW_ENCODE_NOKEY ? "NOKEY" : "",
5003 dwrq->flags & IW_ENCODE_DISABLED ? " DISABLED" : "",
5004 dwrq->flags & IW_ENCODE_RESTRICTED ? " RESTRICTED" : "",
5005 dwrq->flags & IW_ENCODE_OPEN ? " OPEN" : "",
5006 dwrq->flags & IW_ENCODE_TEMP ? " TEMP" : ""));
5007
5008 memset(&key, 0, sizeof(key));
5009
5010 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
5011
5012 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
5013 val = htod32(key.index);
5014 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
5015 return error;
5016 val = dtoh32(val);
5017 if (val)
5018 break;
5019 }
5020
5021 if (key.index == DOT11_MAX_DEFAULT_KEYS)
5022 key.index = 0;
5023 } else {
5024 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5025 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
5026 return -EINVAL;
5027 }
5028
5029
5030 if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
5031
5032 val = htod32(key.index);
5033 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
5034 return error;
5035 } else {
5036 key.len = dwrq->length;
5037
5038 if (dwrq->length > sizeof(key.data))
5039 return -EINVAL;
5040
5041 memcpy(key.data, extra, dwrq->length);
5042
5043 key.flags = WL_PRIMARY_KEY;
5044 switch (key.len) {
5045 case WEP1_KEY_SIZE:
5046 key.algo = CRYPTO_ALGO_WEP1;
5047 break;
5048 case WEP128_KEY_SIZE:
5049 key.algo = CRYPTO_ALGO_WEP128;
5050 break;
5051#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
5052 case TKIP_KEY_SIZE:
5053 key.algo = CRYPTO_ALGO_TKIP;
5054 break;
5055#endif
5056 case AES_KEY_SIZE:
5057 key.algo = CRYPTO_ALGO_AES_CCM;
5058 break;
5059 default:
5060 return -EINVAL;
5061 }
5062
5063
5064 swap_key_from_BE(&key);
5065 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
5066 return error;
5067 }
5068
5069
5070 val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
5071
5072 if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
5073 return error;
5074
5075 wsec &= ~(WEP_ENABLED);
5076 wsec |= val;
5077
5078 if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
5079 return error;
5080
5081
5082 val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
5083 val = htod32(val);
5084 if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
5085 return error;
5086
5087 return 0;
5088}
5089
5090static int
5091wl_iw_get_encode(
5092 struct net_device *dev,
5093 struct iw_request_info *info,
5094 struct iw_point *dwrq,
5095 char *extra
5096)
5097{
5098 wl_wsec_key_t key;
5099 int error, val, wsec, auth;
5100
5101 WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
5102
5103
5104 bzero(&key, sizeof(wl_wsec_key_t));
5105
5106 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
5107
5108 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
5109 val = key.index;
5110 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
5111 return error;
5112 val = dtoh32(val);
5113 if (val)
5114 break;
5115 }
5116 } else
5117 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5118
5119 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
5120 key.index = 0;
5121
5122
5123
5124 if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
5125 (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
5126 return error;
5127
5128 swap_key_to_BE(&key);
5129
5130 wsec = dtoh32(wsec);
5131 auth = dtoh32(auth);
5132
5133 dwrq->length = MIN(DOT11_MAX_KEY_SIZE, key.len);
5134
5135
5136 dwrq->flags = key.index + 1;
5137 if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
5138
5139 dwrq->flags |= IW_ENCODE_DISABLED;
5140 }
5141 if (auth) {
5142
5143 dwrq->flags |= IW_ENCODE_RESTRICTED;
5144 }
5145
5146
5147 if (dwrq->length && extra)
5148 memcpy(extra, key.data, dwrq->length);
5149
5150 return 0;
5151}
5152
5153static int
5154wl_iw_set_power(
5155 struct net_device *dev,
5156 struct iw_request_info *info,
5157 struct iw_param *vwrq,
5158 char *extra
5159)
5160{
5161 int error, pm;
5162
5163 WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
5164
5165 pm = vwrq->disabled ? PM_OFF : PM_MAX;
5166
5167 pm = htod32(pm);
5168 if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
5169 return error;
5170
5171 return 0;
5172}
5173
5174static int
5175wl_iw_get_power(
5176 struct net_device *dev,
5177 struct iw_request_info *info,
5178 struct iw_param *vwrq,
5179 char *extra
5180)
5181{
5182 int error, pm;
5183
5184 WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
5185
5186 if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
5187 return error;
5188
5189 pm = dtoh32(pm);
5190 vwrq->disabled = pm ? 0 : 1;
5191 vwrq->flags = IW_POWER_ALL_R;
5192
5193 return 0;
5194}
5195
5196#if WIRELESS_EXT > 17
5197static int
5198wl_iw_set_wpaie(
5199 struct net_device *dev,
5200 struct iw_request_info *info,
5201 struct iw_point *iwp,
5202 char *extra
5203)
5204{
5205
5206 WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
5207
5208 RETURN_IF_EXTRA_NULL(extra);
5209
5210#ifdef DHD_DEBUG
5211 {
5212 int i;
5213
5214 for (i = 0; i < iwp->length; i++)
5215 WL_TRACE(("%02X ", extra[i]));
5216 WL_TRACE(("\n"));
5217 }
5218#endif
5219
5220 dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
5221
5222 return 0;
5223}
5224
5225static int
5226wl_iw_get_wpaie(
5227 struct net_device *dev,
5228 struct iw_request_info *info,
5229 struct iw_point *iwp,
5230 char *extra
5231)
5232{
5233 WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
5234 iwp->length = 64;
5235 dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
5236 return 0;
5237}
5238
5239static int
5240wl_iw_set_encodeext(
5241 struct net_device *dev,
5242 struct iw_request_info *info,
5243 struct iw_point *dwrq,
5244 char *extra
5245)
5246{
5247 wl_wsec_key_t key;
5248 int error;
5249 struct iw_encode_ext *iwe;
5250
5251 WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
5252
5253 RETURN_IF_EXTRA_NULL(extra);
5254
5255 memset(&key, 0, sizeof(key));
5256 iwe = (struct iw_encode_ext *)extra;
5257
5258
5259 if (dwrq->flags & IW_ENCODE_DISABLED) {
5260
5261 }
5262
5263
5264 key.index = 0;
5265 if (dwrq->flags & IW_ENCODE_INDEX)
5266 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5267
5268 key.len = iwe->key_len;
5269
5270
5271 if (!ETHER_ISMULTI(iwe->addr.sa_data))
5272 bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
5273
5274
5275 if (key.len == 0) {
5276 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5277 WL_WSEC(("Changing the the primary Key to %d\n", key.index));
5278
5279 key.index = htod32(key.index);
5280 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
5281 &key.index, sizeof(key.index));
5282 if (error)
5283 return error;
5284 }
5285
5286 else {
5287 swap_key_from_BE(&key);
5288 dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5289 }
5290 }
5291 else {
5292 if (iwe->key_len > sizeof(key.data))
5293 return -EINVAL;
5294
5295 WL_WSEC(("Setting the key index %d\n", key.index));
5296 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5297 WL_WSEC(("key is a Primary Key\n"));
5298 key.flags = WL_PRIMARY_KEY;
5299 }
5300
5301 bcopy((void *)iwe->key, key.data, iwe->key_len);
5302
5303 if (iwe->alg == IW_ENCODE_ALG_TKIP) {
5304 uint8 keybuf[8];
5305 bcopy(&key.data[24], keybuf, sizeof(keybuf));
5306 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
5307 bcopy(keybuf, &key.data[16], sizeof(keybuf));
5308 }
5309
5310
5311 if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
5312 uchar *ivptr;
5313 ivptr = (uchar *)iwe->rx_seq;
5314 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
5315 (ivptr[3] << 8) | ivptr[2];
5316 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
5317 key.iv_initialized = TRUE;
5318 }
5319
5320 switch (iwe->alg) {
5321 case IW_ENCODE_ALG_NONE:
5322 key.algo = CRYPTO_ALGO_OFF;
5323 break;
5324 case IW_ENCODE_ALG_WEP:
5325 if (iwe->key_len == WEP1_KEY_SIZE)
5326 key.algo = CRYPTO_ALGO_WEP1;
5327 else
5328 key.algo = CRYPTO_ALGO_WEP128;
5329 break;
5330 case IW_ENCODE_ALG_TKIP:
5331 key.algo = CRYPTO_ALGO_TKIP;
5332 break;
5333 case IW_ENCODE_ALG_CCMP:
5334 key.algo = CRYPTO_ALGO_AES_CCM;
5335 break;
5336 default:
5337 break;
5338 }
5339 swap_key_from_BE(&key);
5340
5341 dhd_wait_pend8021x(dev);
5342
5343 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5344 if (error)
5345 return error;
5346 }
5347 return 0;
5348}
5349
5350#if WIRELESS_EXT > 17
5351struct {
5352 pmkid_list_t pmkids;
5353 pmkid_t foo[MAXPMKID-1];
5354} pmkid_list;
5355
5356static int
5357wl_iw_set_pmksa(
5358 struct net_device *dev,
5359 struct iw_request_info *info,
5360 struct iw_param *vwrq,
5361 char *extra
5362)
5363{
5364 struct iw_pmksa *iwpmksa;
5365 uint i;
5366 int ret = 0;
5367 char eabuf[ETHER_ADDR_STR_LEN];
5368 pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid;
5369
5370 WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name));
5371
5372 RETURN_IF_EXTRA_NULL(extra);
5373
5374 iwpmksa = (struct iw_pmksa *)extra;
5375 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
5376
5377 if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
5378 WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
5379 bzero((char *)&pmkid_list, sizeof(pmkid_list));
5380 }
5381
5382 else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
5383 {
5384 pmkid_list_t pmkid, *pmkidptr;
5385 uint j;
5386 pmkidptr = &pmkid;
5387
5388 bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID,
5389 ETHER_ADDR_LEN);
5390 bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
5391
5392 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
5393 bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
5394 eabuf)));
5395 for (j = 0; j < WPA2_PMKID_LEN; j++)
5396 WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
5397 WL_WSEC(("\n"));
5398 }
5399
5400 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5401 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID,
5402 ETHER_ADDR_LEN))
5403 break;
5404
5405 if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) {
5406 bzero(&pmkid_array[i], sizeof(pmkid_t));
5407 for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
5408 bcopy(&pmkid_array[i+1].BSSID,
5409 &pmkid_array[i].BSSID,
5410 ETHER_ADDR_LEN);
5411 bcopy(&pmkid_array[i+1].PMKID,
5412 &pmkid_array[i].PMKID,
5413 WPA2_PMKID_LEN);
5414 }
5415 pmkid_list.pmkids.npmkid--;
5416 }
5417 else
5418 ret = -EINVAL;
5419 }
5420
5421 else if (iwpmksa->cmd == IW_PMKSA_ADD) {
5422 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5423 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID,
5424 ETHER_ADDR_LEN))
5425 break;
5426 if (i < MAXPMKID) {
5427 bcopy(&iwpmksa->bssid.sa_data[0],
5428 &pmkid_array[i].BSSID,
5429 ETHER_ADDR_LEN);
5430 bcopy(&iwpmksa->pmkid[0], &pmkid_array[i].PMKID,
5431 WPA2_PMKID_LEN);
5432 if (i == pmkid_list.pmkids.npmkid)
5433 pmkid_list.pmkids.npmkid++;
5434 }
5435 else
5436 ret = -EINVAL;
5437
5438 {
5439 uint j;
5440 uint k;
5441 k = pmkid_list.pmkids.npmkid;
5442 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
5443 bcm_ether_ntoa(&pmkid_array[k].BSSID,
5444 eabuf)));
5445 for (j = 0; j < WPA2_PMKID_LEN; j++)
5446 WL_WSEC(("%02x ", pmkid_array[k].PMKID[j]));
5447 WL_WSEC(("\n"));
5448 }
5449 }
5450 WL_WSEC(("PRINTING pmkid LIST - No of elements %d", pmkid_list.pmkids.npmkid));
5451 for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
5452 uint j;
5453 WL_WSEC(("\nPMKID[%d]: %s = ", i,
5454 bcm_ether_ntoa(&pmkid_array[i].BSSID,
5455 eabuf)));
5456 for (j = 0; j < WPA2_PMKID_LEN; j++)
5457 WL_WSEC(("%02x ", pmkid_array[i].PMKID[j]));
5458 }
5459 WL_WSEC(("\n"));
5460
5461 if (!ret)
5462 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
5463 sizeof(pmkid_list));
5464 return ret;
5465}
5466#endif
5467
5468static int
5469wl_iw_get_encodeext(
5470 struct net_device *dev,
5471 struct iw_request_info *info,
5472 struct iw_param *vwrq,
5473 char *extra
5474)
5475{
5476 WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
5477 return 0;
5478}
5479
5480
5481static uint32
5482wl_iw_create_wpaauth_wsec(struct net_device *dev)
5483{
5484 wl_iw_t *iw = NETDEV_PRIV(dev);
5485 uint32 wsec;
5486
5487
5488 if (iw->pcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
5489 wsec = WEP_ENABLED;
5490 else if (iw->pcipher & IW_AUTH_CIPHER_TKIP)
5491 wsec = TKIP_ENABLED;
5492 else if (iw->pcipher & IW_AUTH_CIPHER_CCMP)
5493 wsec = AES_ENABLED;
5494 else
5495 wsec = 0;
5496
5497
5498 if (iw->gcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
5499 wsec |= WEP_ENABLED;
5500 else if (iw->gcipher & IW_AUTH_CIPHER_TKIP)
5501 wsec |= TKIP_ENABLED;
5502 else if (iw->gcipher & IW_AUTH_CIPHER_CCMP)
5503 wsec |= AES_ENABLED;
5504
5505
5506 if (wsec == 0 && iw->privacy_invoked)
5507 wsec = WEP_ENABLED;
5508
5509 WL_INFORM(("%s: returning wsec of %d\n", __FUNCTION__, wsec));
5510
5511 return wsec;
5512}
5513
5514static int
5515wl_iw_set_wpaauth(
5516 struct net_device *dev,
5517 struct iw_request_info *info,
5518 struct iw_param *vwrq,
5519 char *extra
5520)
5521{
5522 int error = 0;
5523 int paramid;
5524 int paramval;
5525 int val = 0;
5526 wl_iw_t *iw = NETDEV_PRIV(dev);
5527
5528 paramid = vwrq->flags & IW_AUTH_INDEX;
5529 paramval = vwrq->value;
5530
5531 WL_TRACE(("%s: SIOCSIWAUTH, %s(%d), paramval = 0x%0x\n",
5532 dev->name,
5533 paramid == IW_AUTH_WPA_VERSION ? "IW_AUTH_WPA_VERSION" :
5534 paramid == IW_AUTH_CIPHER_PAIRWISE ? "IW_AUTH_CIPHER_PAIRWISE" :
5535 paramid == IW_AUTH_CIPHER_GROUP ? "IW_AUTH_CIPHER_GROUP" :
5536 paramid == IW_AUTH_KEY_MGMT ? "IW_AUTH_KEY_MGMT" :
5537 paramid == IW_AUTH_TKIP_COUNTERMEASURES ? "IW_AUTH_TKIP_COUNTERMEASURES" :
5538 paramid == IW_AUTH_DROP_UNENCRYPTED ? "IW_AUTH_DROP_UNENCRYPTED" :
5539 paramid == IW_AUTH_80211_AUTH_ALG ? "IW_AUTH_80211_AUTH_ALG" :
5540 paramid == IW_AUTH_WPA_ENABLED ? "IW_AUTH_WPA_ENABLED" :
5541 paramid == IW_AUTH_RX_UNENCRYPTED_EAPOL ? "IW_AUTH_RX_UNENCRYPTED_EAPOL" :
5542 paramid == IW_AUTH_ROAMING_CONTROL ? "IW_AUTH_ROAMING_CONTROL" :
5543 paramid == IW_AUTH_PRIVACY_INVOKED ? "IW_AUTH_PRIVACY_INVOKED" :
5544 "UNKNOWN",
5545 paramid, paramval));
5546
5547#if defined(SOFTAP)
5548 if (ap_cfg_running) {
5549 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
5550 return 0;
5551 }
5552#endif
5553
5554 switch (paramid) {
5555 case IW_AUTH_WPA_VERSION:
5556
5557 if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
5558 val = WPA_AUTH_DISABLED;
5559 else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
5560 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
5561 else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
5562 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
5563 WL_ERROR(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
5564 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
5565 return error;
5566 break;
5567
5568 case IW_AUTH_CIPHER_PAIRWISE:
5569 iw->pcipher = paramval;
5570 val = wl_iw_create_wpaauth_wsec(dev);
5571 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5572 return error;
5573 break;
5574
5575 case IW_AUTH_CIPHER_GROUP:
5576 iw->gcipher = paramval;
5577 val = wl_iw_create_wpaauth_wsec(dev);
5578 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5579 return error;
5580 break;
5581
5582 case IW_AUTH_KEY_MGMT:
5583 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5584 return error;
5585
5586 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
5587 if (paramval & IW_AUTH_KEY_MGMT_PSK)
5588 val = WPA_AUTH_PSK;
5589 else
5590 val = WPA_AUTH_UNSPECIFIED;
5591 if (paramval & 0x04)
5592 val |= WPA2_AUTH_FT;
5593 }
5594 else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
5595 if (paramval & IW_AUTH_KEY_MGMT_PSK)
5596 val = WPA2_AUTH_PSK;
5597 else
5598 val = WPA2_AUTH_UNSPECIFIED;
5599 if (paramval & 0x04)
5600 val |= WPA2_AUTH_FT;
5601 }
5602
5603 else if (paramval & IW_AUTH_KEY_MGMT_PSK) {
5604 if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
5605 val = WPA_AUTH_PSK;
5606 else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
5607 val = WPA2_AUTH_PSK;
5608 else
5609 val = WPA_AUTH_DISABLED;
5610 } else if (paramval & IW_AUTH_KEY_MGMT_802_1X) {
5611 if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
5612 val = WPA_AUTH_UNSPECIFIED;
5613 else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
5614 val = WPA2_AUTH_UNSPECIFIED;
5615 else
5616 val = WPA_AUTH_DISABLED;
5617 }
5618 else
5619 val = WPA_AUTH_DISABLED;
5620
5621 WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
5622 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
5623 return error;
5624 break;
5625
5626 case IW_AUTH_TKIP_COUNTERMEASURES:
5627 dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
5628 break;
5629
5630 case IW_AUTH_80211_AUTH_ALG:
5631
5632 WL_INFORM(("Setting the D11auth %d\n", paramval));
5633 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
5634 val = 0;
5635 else if (paramval == IW_AUTH_ALG_SHARED_KEY)
5636 val = 1;
5637 else if (paramval == (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
5638 val = 2;
5639 else
5640 error = 1;
5641 if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
5642 return error;
5643 break;
5644
5645 case IW_AUTH_WPA_ENABLED:
5646 if (paramval == 0) {
5647 iw->privacy_invoked = 0;
5648 iw->pcipher = 0;
5649 iw->gcipher = 0;
5650 val = wl_iw_create_wpaauth_wsec(dev);
5651 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5652 return error;
5653 WL_INFORM(("%s: %d: setting wpa_auth to %d, wsec to %d\n",
5654 __FUNCTION__, __LINE__, paramval, val));
5655 dev_wlc_intvar_set(dev, "wpa_auth", paramval);
5656 return error;
5657 }
5658
5659
5660 break;
5661
5662 case IW_AUTH_DROP_UNENCRYPTED:
5663 if ((error = dev_wlc_intvar_set(dev, "wsec_restrict", paramval)))
5664 return error;
5665 break;
5666
5667 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5668 dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
5669 break;
5670
5671#if WIRELESS_EXT > 17
5672 case IW_AUTH_ROAMING_CONTROL:
5673 WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5674
5675 break;
5676
5677 case IW_AUTH_PRIVACY_INVOKED:
5678 iw->privacy_invoked = paramval;
5679 val = wl_iw_create_wpaauth_wsec(dev);
5680 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5681 return error;
5682 break;
5683
5684#endif
5685 default:
5686 break;
5687 }
5688 return 0;
5689}
5690#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
5691
5692static int
5693wl_iw_get_wpaauth(
5694 struct net_device *dev,
5695 struct iw_request_info *info,
5696 struct iw_param *vwrq,
5697 char *extra
5698)
5699{
5700 int error;
5701 int paramid;
5702 int paramval = 0;
5703 int val;
5704 wl_iw_t *iw = NETDEV_PRIV(dev);
5705
5706 WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
5707
5708 paramid = vwrq->flags & IW_AUTH_INDEX;
5709
5710 switch (paramid) {
5711 case IW_AUTH_WPA_VERSION:
5712 paramval = iw->wpaversion;
5713 break;
5714
5715 case IW_AUTH_CIPHER_PAIRWISE:
5716 paramval = iw->pcipher;
5717 break;
5718
5719 case IW_AUTH_CIPHER_GROUP:
5720 paramval = iw->gcipher;
5721 break;
5722
5723 case IW_AUTH_KEY_MGMT:
5724
5725 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5726 return error;
5727 if (VAL_PSK(val))
5728 paramval = IW_AUTH_KEY_MGMT_PSK;
5729 else
5730 paramval = IW_AUTH_KEY_MGMT_802_1X;
5731
5732 break;
5733
5734 case IW_AUTH_TKIP_COUNTERMEASURES:
5735 dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)&paramval, 1);
5736 break;
5737
5738 case IW_AUTH_DROP_UNENCRYPTED:
5739 dev_wlc_intvar_get(dev, "wsec_restrict", &paramval);
5740 break;
5741
5742 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5743 dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
5744 break;
5745
5746 case IW_AUTH_80211_AUTH_ALG:
5747
5748 if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
5749 return error;
5750 if (!val)
5751 paramval = IW_AUTH_ALG_OPEN_SYSTEM;
5752 else
5753 paramval = IW_AUTH_ALG_SHARED_KEY;
5754 break;
5755 case IW_AUTH_WPA_ENABLED:
5756 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5757 return error;
5758 if (val)
5759 paramval = TRUE;
5760 else
5761 paramval = FALSE;
5762 break;
5763#if WIRELESS_EXT > 17
5764 case IW_AUTH_ROAMING_CONTROL:
5765 WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5766
5767 break;
5768 case IW_AUTH_PRIVACY_INVOKED:
5769 paramval = iw->privacy_invoked;
5770 break;
5771
5772#endif
5773 }
5774 vwrq->value = paramval;
5775 return 0;
5776}
5777#endif
5778
5779
5780#ifdef SOFTAP
5781
5782static int ap_macmode = MACLIST_MODE_DISABLED;
5783static struct mflist ap_black_list;
5784
5785static int
5786wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key)
5787{
5788 char hex[] = "XX";
5789 unsigned char *data = key->data;
5790
5791 switch (strlen(keystr)) {
5792 case 5:
5793 case 13:
5794 case 16:
5795 key->len = strlen(keystr);
5796 memcpy(data, keystr, key->len + 1);
5797 break;
5798 case 12:
5799 case 28:
5800 case 34:
5801 case 66:
5802
5803 if (!strnicmp(keystr, "0x", 2))
5804 keystr += 2;
5805 else
5806 return -1;
5807
5808 case 10:
5809 case 26:
5810 case 32:
5811 case 64:
5812 key->len = strlen(keystr) / 2;
5813 while (*keystr) {
5814 strncpy(hex, keystr, 2);
5815 *data++ = (char) bcm_strtoul(hex, NULL, 16);
5816 keystr += 2;
5817 }
5818 break;
5819 default:
5820 return -1;
5821 }
5822
5823 switch (key->len) {
5824 case 5:
5825 key->algo = CRYPTO_ALGO_WEP1;
5826 break;
5827 case 13:
5828 key->algo = CRYPTO_ALGO_WEP128;
5829 break;
5830 case 16:
5831
5832 key->algo = CRYPTO_ALGO_AES_CCM;
5833 break;
5834 case 32:
5835 key->algo = CRYPTO_ALGO_TKIP;
5836 break;
5837 default:
5838 return -1;
5839 }
5840
5841
5842 key->flags |= WL_PRIMARY_KEY;
5843
5844 return 0;
5845}
5846
5847#ifdef EXT_WPA_CRYPTO
5848#define SHA1HashSize 20
5849extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5850 int iterations, u8 *buf, size_t buflen);
5851
5852#else
5853
5854#define SHA1HashSize 20
5855static int
5856pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5857 int iterations, u8 *buf, size_t buflen)
5858{
5859 WL_ERROR(("WARNING: %s is not implemented !!!\n", __FUNCTION__));
5860 return -1;
5861}
5862
5863#endif
5864
5865
5866static int
5867dev_iw_write_cfg1_bss_var(struct net_device *dev, int val)
5868{
5869 struct {
5870 int cfg;
5871 int val;
5872 } bss_setbuf;
5873
5874 int bss_set_res;
5875 char smbuf[WLC_IOCTL_SMLEN];
5876 memset(smbuf, 0, sizeof(smbuf));
5877
5878 bss_setbuf.cfg = 1;
5879 bss_setbuf.val = val;
5880
5881 bss_set_res = dev_iw_iovar_setbuf(dev, "bss",
5882 &bss_setbuf, sizeof(bss_setbuf), smbuf, sizeof(smbuf));
5883 WL_TRACE(("%s: bss_set_result:%d set with %d\n", __FUNCTION__, bss_set_res, val));
5884
5885 return bss_set_res;
5886}
5887
5888
5889
5890#ifndef AP_ONLY
5891static int
5892wl_bssiovar_mkbuf(
5893 const char *iovar,
5894 int bssidx,
5895 void *param,
5896 int paramlen,
5897 void *bufptr,
5898 int buflen,
5899 int *perr)
5900{
5901 const char *prefix = "bsscfg:";
5902 int8* p;
5903 uint prefixlen;
5904 uint namelen;
5905 uint iolen;
5906
5907 prefixlen = strlen(prefix);
5908 namelen = strlen(iovar) + 1;
5909 iolen = prefixlen + namelen + sizeof(int) + paramlen;
5910
5911
5912 if (buflen < 0 || iolen > (uint)buflen) {
5913 *perr = BCME_BUFTOOSHORT;
5914 return 0;
5915 }
5916
5917 p = (int8*)bufptr;
5918
5919
5920 memcpy(p, prefix, prefixlen);
5921 p += prefixlen;
5922
5923
5924 memcpy(p, iovar, namelen);
5925 p += namelen;
5926
5927
5928 bssidx = htod32(bssidx);
5929 memcpy(p, &bssidx, sizeof(int32));
5930 p += sizeof(int32);
5931
5932
5933 if (paramlen)
5934 memcpy(p, param, paramlen);
5935
5936 *perr = 0;
5937 return iolen;
5938}
5939#endif
5940
5941
5942
5943
5944#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
5945
5946
5947#if defined(CSCAN)
5948
5949
5950
5951static int
5952wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan)
5953{
5954 int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
5955 int err = 0;
5956 char *p;
5957 int i;
5958 iscan_info_t *iscan = g_iscan;
5959
5960 WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan));
5961
5962 if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) {
5963 WL_ERROR(("%s error exit\n", __FUNCTION__));
5964 err = -1;
5965 goto exit;
5966 }
5967
5968#ifdef PNO_SUPPORT
5969
5970 if (dhd_dev_get_pno_status(dev)) {
5971 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
5972 }
5973#endif
5974
5975 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
5976
5977
5978 if (nssid > 0) {
5979 i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
5980 i = ROUNDUP(i, sizeof(uint32));
5981 if (i + nssid * sizeof(wlc_ssid_t) > params_size) {
5982 printf("additional ssids exceed params_size\n");
5983 err = -1;
5984 goto exit;
5985 }
5986
5987 p = ((char*)&iscan->iscan_ex_params_p->params) + i;
5988 memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t));
5989 p += nssid * sizeof(wlc_ssid_t);
5990 } else {
5991 p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16);
5992 }
5993
5994
5995 iscan->iscan_ex_params_p->params.channel_num =
5996 htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) |
5997 (nchan & WL_SCAN_PARAMS_COUNT_MASK));
5998
5999 nssid = (uint)
6000 ((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) &
6001 WL_SCAN_PARAMS_COUNT_MASK);
6002
6003
6004 params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t));
6005 iscan->iscan_ex_param_size = params_size;
6006
6007 iscan->list_cur = iscan->list_hdr;
6008 iscan->iscan_state = ISCAN_STATE_SCANING;
6009 wl_iw_set_event_mask(dev);
6010 mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms));
6011
6012 iscan->timer_on = 1;
6013
6014#ifdef SCAN_DUMP
6015 {
6016 int i;
6017 WL_SCAN(("\n### List of SSIDs to scan ###\n"));
6018 for (i = 0; i < nssid; i++) {
6019 if (!ssids_local[i].SSID_len)
6020 WL_SCAN(("%d: Broadcast scan\n", i));
6021 else
6022 WL_SCAN(("%d: scan for %s size =%d\n", i,
6023 ssids_local[i].SSID, ssids_local[i].SSID_len));
6024 }
6025 WL_SCAN(("### List of channels to scan ###\n"));
6026 for (i = 0; i < nchan; i++)
6027 {
6028 WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i]));
6029 }
6030 WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes));
6031 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
6032 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
6033 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
6034 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
6035 WL_SCAN(("\n###################\n"));
6036 }
6037#endif
6038
6039 if (params_size > WLC_IOCTL_MEDLEN) {
6040 WL_ERROR(("Set ISCAN for %s due to params_size=%d \n",
6041 __FUNCTION__, params_size));
6042 err = -1;
6043 }
6044
6045 if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p,
6046 iscan->iscan_ex_param_size,
6047 iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
6048 WL_TRACE(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
6049 err = -1;
6050 }
6051
6052exit:
6053 return err;
6054}
6055
6056
6057static int
6058iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info,
6059 union iwreq_data *wrqu, char *ext)
6060{
6061 int res;
6062 char *extra = NULL;
6063 iscan_info_t *iscan = g_iscan;
6064 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
6065 int nssid = 0;
6066 int nchan = 0;
6067 char *str_ptr;
6068
6069 WL_TRACE(("%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
6070 __FUNCTION__, info->cmd, info->flags,
6071 wrqu->data.pointer, wrqu->data.length));
6072
6073 if (g_onoff == G_WLAN_SET_OFF) {
6074 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
6075 return -ENODEV;
6076 }
6077
6078 if (wrqu->data.length == 0) {
6079 WL_ERROR(("IWPRIV argument len = 0\n"));
6080 return -EINVAL;
6081 }
6082
6083 if (!iscan->iscan_ex_params_p) {
6084 return -EFAULT;
6085 }
6086
6087 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
6088 return -ENOMEM;
6089
6090 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
6091 res = -EFAULT;
6092 goto exit_proc;
6093 }
6094
6095 extra[wrqu->data.length] = 0;
6096 WL_ERROR(("Got str param in iw_point:\n %s\n", extra));
6097
6098 str_ptr = extra;
6099
6100
6101 if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) {
6102 WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__));
6103 res = -EINVAL;
6104 goto exit_proc;
6105 }
6106
6107 str_ptr += strlen(GET_SSID);
6108 nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid,
6109 WL_SCAN_PARAMS_SSID_MAX);
6110 if (nssid == -1) {
6111 WL_ERROR(("%s wrong ssid list", __FUNCTION__));
6112 res = -EINVAL;
6113 goto exit_proc;
6114 }
6115
6116 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
6117 ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN);
6118
6119
6120 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
6121 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
6122 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
6123 iscan->iscan_ex_params_p->scan_duration = htod16(0);
6124
6125
6126 if ((nchan = wl_iw_parse_channel_list(&str_ptr,
6127 &iscan->iscan_ex_params_p->params.channel_list[0],
6128 WL_NUMCHANNELS)) == -1) {
6129 WL_ERROR(("%s missing channel list\n", __FUNCTION__));
6130 res = -EINVAL;
6131 goto exit_proc;
6132 }
6133
6134
6135 get_parameter_from_string(&str_ptr,
6136 GET_NPROBE, PTYPE_INTDEC,
6137 &iscan->iscan_ex_params_p->params.nprobes, 2);
6138
6139 get_parameter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC,
6140 &iscan->iscan_ex_params_p->params.active_time, 4);
6141
6142 get_parameter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC,
6143 &iscan->iscan_ex_params_p->params.passive_time, 4);
6144
6145 get_parameter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC,
6146 &iscan->iscan_ex_params_p->params.home_time, 4);
6147
6148 get_parameter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC,
6149 &iscan->iscan_ex_params_p->params.scan_type, 1);
6150
6151
6152 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
6153
6154exit_proc:
6155 kfree(extra);
6156
6157 return res;
6158}
6159
6160
6161static int
6162wl_iw_set_cscan(
6163 struct net_device *dev,
6164 struct iw_request_info *info,
6165 union iwreq_data *wrqu,
6166 char *extra
6167)
6168{
6169 int res = -1;
6170 iscan_info_t *iscan = g_iscan;
6171 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
6172 int nssid = 0;
6173 int nchan = 0;
6174 cscan_tlv_t *cscan_tlv_temp;
6175 char type;
6176 char *str_ptr;
6177 int tlv_size_left;
6178#ifdef TLV_DEBUG
6179 int i;
6180 char tlv_in_example[] = {
6181 'C', 'S', 'C', 'A', 'N', ' ',
6182 0x53, 0x01, 0x00, 0x00,
6183 'S',
6184 0x00,
6185 'S',
6186 0x04,
6187 'B', 'R', 'C', 'M',
6188 'C',
6189 0x06,
6190 'P',
6191 0x94,
6192 0x11,
6193 'T',
6194 0x01
6195 };
6196#endif
6197
6198 WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
6199 __FUNCTION__, info->cmd, info->flags,
6200 wrqu->data.pointer, wrqu->data.length));
6201
6202 net_os_wake_lock(dev);
6203
6204 if (g_onoff == G_WLAN_SET_OFF) {
6205 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
6206 return -1;
6207 }
6208
6209 if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
6210 WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
6211 wrqu->data.length, (int)(strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))));
6212 return -1;
6213 }
6214
6215#ifdef TLV_DEBUG
6216 memcpy(extra, tlv_in_example, sizeof(tlv_in_example));
6217 wrqu->data.length = sizeof(tlv_in_example);
6218 for (i = 0; i < wrqu->data.length; i++)
6219 printf("%02X ", extra[i]);
6220 printf("\n");
6221#endif
6222
6223 str_ptr = extra;
6224 str_ptr += strlen(CSCAN_COMMAND);
6225 tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND);
6226
6227 cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
6228 memset(ssids_local, 0, sizeof(ssids_local));
6229
6230 if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) &&
6231 (cscan_tlv_temp->version == CSCAN_TLV_VERSION) &&
6232 (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
6233 {
6234 str_ptr += sizeof(cscan_tlv_t);
6235 tlv_size_left -= sizeof(cscan_tlv_t);
6236
6237
6238 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
6239 WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
6240 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
6241 goto exit_proc;
6242 }
6243 else {
6244
6245 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
6246
6247
6248 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
6249 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
6250 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
6251 iscan->iscan_ex_params_p->scan_duration = htod16(0);
6252
6253
6254 while (tlv_size_left > 0)
6255 {
6256 type = str_ptr[0];
6257 switch (type) {
6258 case CSCAN_TLV_TYPE_CHANNEL_IE:
6259
6260 if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr,
6261 &iscan->iscan_ex_params_p->params.channel_list[0],
6262 WL_NUMCHANNELS, &tlv_size_left)) == -1) {
6263 WL_ERROR(("%s missing channel list\n",
6264 __FUNCTION__));
6265 goto exit_proc;
6266 }
6267 break;
6268 case CSCAN_TLV_TYPE_NPROBE_IE:
6269 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6270 &iscan->iscan_ex_params_p->params.nprobes,
6271 sizeof(iscan->iscan_ex_params_p->params.nprobes),
6272 type, sizeof(char), &tlv_size_left)) == -1) {
6273 WL_ERROR(("%s return %d\n",
6274 __FUNCTION__, res));
6275 goto exit_proc;
6276 }
6277 break;
6278 case CSCAN_TLV_TYPE_ACTIVE_IE:
6279 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6280 &iscan->iscan_ex_params_p->params.active_time,
6281 sizeof(iscan->iscan_ex_params_p->params.active_time),
6282 type, sizeof(short), &tlv_size_left)) == -1) {
6283 WL_ERROR(("%s return %d\n",
6284 __FUNCTION__, res));
6285 goto exit_proc;
6286 }
6287 break;
6288 case CSCAN_TLV_TYPE_PASSIVE_IE:
6289 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6290 &iscan->iscan_ex_params_p->params.passive_time,
6291 sizeof(iscan->iscan_ex_params_p->params.passive_time),
6292 type, sizeof(short), &tlv_size_left)) == -1) {
6293 WL_ERROR(("%s return %d\n",
6294 __FUNCTION__, res));
6295 goto exit_proc;
6296 }
6297 break;
6298 case CSCAN_TLV_TYPE_HOME_IE:
6299 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6300 &iscan->iscan_ex_params_p->params.home_time,
6301 sizeof(iscan->iscan_ex_params_p->params.home_time),
6302 type, sizeof(short), &tlv_size_left)) == -1) {
6303 WL_ERROR(("%s return %d\n",
6304 __FUNCTION__, res));
6305 goto exit_proc;
6306 }
6307 break;
6308 case CSCAN_TLV_TYPE_STYPE_IE:
6309 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6310 &iscan->iscan_ex_params_p->params.scan_type,
6311 sizeof(iscan->iscan_ex_params_p->params.scan_type),
6312 type, sizeof(char), &tlv_size_left)) == -1) {
6313 WL_ERROR(("%s return %d\n",
6314 __FUNCTION__, res));
6315 goto exit_proc;
6316 }
6317 break;
6318
6319 default :
6320 WL_ERROR(("%s get unkwown type %X\n",
6321 __FUNCTION__, type));
6322 goto exit_proc;
6323 break;
6324 }
6325 }
6326 }
6327 }
6328 else {
6329 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
6330 goto exit_proc;
6331 }
6332
6333#if defined(CONFIG_FIRST_SCAN)
6334 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
6335 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
6336
6337 WL_ERROR(("%s Clean up First scan flag which is %d\n",
6338 __FUNCTION__, g_first_broadcast_scan));
6339 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
6340 }
6341 else {
6342 WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n",
6343 __FUNCTION__, g_first_counter_scans));
6344 return -EBUSY;
6345 }
6346 }
6347#endif
6348
6349
6350 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
6351
6352exit_proc:
6353 net_os_wake_unlock(dev);
6354 return res;
6355}
6356
6357#endif
6358
6359#ifdef CONFIG_WPS2
6360static int
6361wl_iw_del_wps_probe_req_ie(
6362 struct net_device *dev,
6363 struct iw_request_info *info,
6364 union iwreq_data *wrqu,
6365 char *extra
6366)
6367{
6368 int ret;
6369 vndr_ie_setbuf_t *ie_delbuf;
6370
6371 if (g_wps_probe_req_ie) {
6372 ie_delbuf = (vndr_ie_setbuf_t *)(g_wps_probe_req_ie + strlen("vndr_ie "));
6373 strncpy(ie_delbuf->cmd, "del", 3);
6374 ie_delbuf->cmd[3] = '\0';
6375
6376 ret = dev_wlc_ioctl(dev, WLC_SET_VAR, g_wps_probe_req_ie, g_wps_probe_req_ie_len);
6377 if (ret) {
6378 WL_ERROR(("ioctl failed %d \n", ret));
6379 }
6380
6381 kfree(g_wps_probe_req_ie);
6382 g_wps_probe_req_ie = NULL;
6383 g_wps_probe_req_ie_len = 0;
6384 }
6385
6386 return 0;
6387}
6388
6389static int
6390wl_iw_add_wps_probe_req_ie(
6391 struct net_device *dev,
6392 struct iw_request_info *info,
6393 union iwreq_data *wrqu,
6394 char *extra
6395)
6396{
6397 char *str_ptr = NULL;
6398 char *bufptr = NULL;
6399 uint buflen, datalen, iecount, pktflag, iolen, total_len;
6400 int ret = 0;
6401 vndr_ie_setbuf_t *ie_setbuf = NULL;
6402
6403 if (!g_wps_probe_req_ie) {
6404 ret = -1;
6405 str_ptr = extra;
6406 str_ptr += WPS_PROBE_REQ_IE_CMD_LENGTH;
6407 datalen = wrqu->data.length - WPS_PROBE_REQ_IE_CMD_LENGTH;
6408
6409
6410
6411 buflen = sizeof(vndr_ie_setbuf_t) + datalen - sizeof(vndr_ie_t);
6412 ie_setbuf = (vndr_ie_setbuf_t *)kmalloc(buflen, GFP_KERNEL);
6413 if (!ie_setbuf) {
6414 WL_ERROR(("memory alloc failure ie_setbuf\n"));
6415 return ret;
6416 }
6417
6418 memset(ie_setbuf, 0x00, buflen);
6419
6420
6421 strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
6422 ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
6423
6424
6425 iecount = htod32(1);
6426 memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
6427
6428
6429 pktflag = 0x10;
6430 memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
6431 &pktflag, sizeof(uint32));
6432
6433 memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data,
6434 str_ptr, datalen);
6435
6436 total_len = strlen("vndr_ie ") + buflen;
6437 bufptr = (char *)kmalloc(total_len, GFP_KERNEL);
6438 if (!bufptr) {
6439 WL_ERROR(("memory alloc failure bufptr\n"));
6440 goto fail;
6441 }
6442
6443 iolen = bcm_mkiovar("vndr_ie", (char *)ie_setbuf, buflen, bufptr, total_len);
6444 if (iolen == 0) {
6445 WL_ERROR(("Buffer length is illegal\n"));
6446 goto fail2;
6447 }
6448
6449 ret = dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
6450 if (ret) {
6451 WL_ERROR(("ioctl failed\n"));
6452 goto fail2;
6453 }
6454
6455 g_wps_probe_req_ie = (char *)kmalloc(iolen, GFP_KERNEL);
6456 if (!g_wps_probe_req_ie) {
6457 WL_ERROR(("memory alloc failure g_wps_probe_req_ie\n"));
6458 goto fail2;
6459 }
6460
6461 memcpy(g_wps_probe_req_ie, bufptr, iolen);
6462 g_wps_probe_req_ie_len = iolen;
6463 }
6464
6465fail2:
6466 if (bufptr) {
6467 kfree(bufptr);
6468 bufptr = NULL;
6469 }
6470fail:
6471 if (ie_setbuf) {
6472 kfree(ie_setbuf);
6473 ie_setbuf = NULL;
6474 }
6475 return ret;
6476}
6477#endif
6478
6479
6480#ifdef SOFTAP
6481#ifndef AP_ONLY
6482
6483
6484static int
6485thr_wait_for_2nd_eth_dev(void *data)
6486{
6487 wl_iw_t *iw;
6488 int ret = 0;
6489 unsigned long flags = 0;
6490
6491 tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
6492 struct net_device *dev = (struct net_device *)tsk_ctl->parent;
6493 iw = *(wl_iw_t **)netdev_priv(dev);
6494
6495 DAEMONIZE("wl0_eth_wthread");
6496
6497
6498 WL_SOFTAP(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid));
6499
6500#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
6501 if (!iw) {
6502 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6503 tsk_ctl->thr_pid = -1;
6504 complete(&tsk_ctl->completed);
6505 return -1;
6506 }
6507 DHD_OS_WAKE_LOCK(iw->pub);
6508 complete(&tsk_ctl->completed);
6509 if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(1000)) != 0) {
6510#else
6511 if (down_interruptible(&tsk_ctl->sema) != 0) {
6512#endif
6513 WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__));
6514 ret = -1;
6515 goto fail;
6516 }
6517
6518 SMP_RD_BARRIER_DEPENDS();
6519 if (tsk_ctl->terminated) {
6520 ret = -1;
6521 goto fail;
6522 }
6523
6524 flags = dhd_os_spin_lock(iw->pub);
6525 if (!ap_net_dev) {
6526 WL_ERROR((" ap_net_dev is null !!!"));
6527 ret = -1;
6528 dhd_os_spin_unlock(iw->pub, flags);
6529 goto fail;
6530 }
6531
6532 WL_SOFTAP(("\n>%s: Thread:'softap ethdev IF:%s is detected!'\n\n",
6533 __FUNCTION__, ap_net_dev->name));
6534
6535 ap_cfg_running = TRUE;
6536
6537 dhd_os_spin_unlock(iw->pub, flags);
6538 bcm_mdelay(500);
6539
6540
6541 wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK");
6542
6543fail:
6544
6545 DHD_OS_WAKE_UNLOCK(iw->pub);
6546
6547 WL_SOFTAP(("\n>%s, thread completed\n", __FUNCTION__));
6548
6549 complete_and_exit(&tsk_ctl->completed, 0);
6550 return ret;
6551}
6552#endif
6553#ifndef AP_ONLY
6554static int last_auto_channel = 6;
6555#endif
6556
6557static int
6558get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap)
6559{
6560 int chosen = 0;
6561 wl_uint32_list_t request;
6562 int retry = 0;
6563 int updown = 0;
6564 int ret = 0;
6565 wlc_ssid_t null_ssid;
6566 int res = 0;
6567#ifndef AP_ONLY
6568 int iolen = 0;
6569 int mkvar_err = 0;
6570 int bsscfg_index = 1;
6571 char buf[WLC_IOCTL_SMLEN];
6572#endif
6573 WL_SOFTAP(("Enter %s\n", __FUNCTION__));
6574
6575#ifndef AP_ONLY
6576 if (ap_cfg_running) {
6577 ap->channel = last_auto_channel;
6578 return res;
6579 }
6580#endif
6581
6582 memset(&null_ssid, 0, sizeof(wlc_ssid_t));
6583 res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown));
6584
6585#ifdef AP_ONLY
6586 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid));
6587#else
6588
6589 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid),
6590 null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
6591 ASSERT(iolen);
6592 res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen);
6593
6594#endif
6595
6596 request.count = htod32(0);
6597 ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request));
6598 if (ret < 0) {
6599 WL_ERROR(("can't start auto channel scan\n"));
6600 goto fail;
6601 }
6602
6603 get_channel_retry:
6604 bcm_mdelay(350);
6605
6606 ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6607 if (ret < 0 || dtoh32(chosen) == 0) {
6608 if (retry++ < 15) {
6609 goto get_channel_retry;
6610 } else {
6611 if (ret < 0) {
6612 WL_ERROR(("can't get auto channel sel, err = %d, "
6613 "chosen = 0x%04X\n", ret, (uint16)chosen));
6614 goto fail;
6615 } else {
6616 ap->channel = (uint16)last_auto_channel;
6617 WL_ERROR(("auto channel sel timed out. we get channel %d\n",
6618 ap->channel));
6619 }
6620 }
6621 }
6622
6623 if (chosen) {
6624 ap->channel = (uint16)chosen & 0x00FF;
6625 WL_SOFTAP(("%s: Got auto channel = %d, attempt:%d\n",
6626 __FUNCTION__, ap->channel, retry));
6627 }
6628
6629 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) {
6630 WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res));
6631 goto fail;
6632 }
6633
6634#ifndef AP_ONLY
6635 if (!res || !ret)
6636 last_auto_channel = ap->channel;
6637#endif
6638
6639fail :
6640 if (ret < 0) {
6641 WL_TRACE(("%s: return value %d\n", __FUNCTION__, ret));
6642 return ret;
6643 }
6644 return res;
6645}
6646
6647
6648static int
6649set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
6650{
6651 int updown = 0;
6652 int channel = 0;
6653
6654 wlc_ssid_t ap_ssid;
6655 int max_assoc = 8;
6656
6657 int res = 0;
6658 int apsta_var = 0;
6659#ifndef AP_ONLY
6660 int mpc = 0;
6661 int iolen = 0;
6662 int mkvar_err = 0;
6663 int bsscfg_index = 1;
6664 char buf[WLC_IOCTL_SMLEN];
6665#endif
6666
6667 if (!dev) {
6668 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6669 return -1;
6670 }
6671
6672 net_os_wake_lock(dev);
6673 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
6674
6675 WL_SOFTAP(("wl_iw: set ap profile:\n"));
6676 WL_SOFTAP((" ssid = '%s'\n", ap->ssid));
6677 WL_SOFTAP((" security = '%s'\n", ap->sec));
6678 if (ap->key[0] != '\0')
6679 WL_SOFTAP((" key = '%s'\n", ap->key));
6680 WL_SOFTAP((" channel = %d\n", ap->channel));
6681 WL_SOFTAP((" max scb = %d\n", ap->max_scb));
6682
6683#ifdef AP_ONLY
6684 if (ap_cfg_running) {
6685 wl_iw_softap_deassoc_stations(dev, NULL);
6686 ap_cfg_running = FALSE;
6687 }
6688#endif
6689
6690
6691 if (ap_cfg_running == FALSE) {
6692
6693#ifndef AP_ONLY
6694
6695
6696 sema_init(&ap_eth_ctl.sema, 0);
6697
6698 mpc = 0;
6699 if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) {
6700 WL_ERROR(("%s fail to set mpc\n", __FUNCTION__));
6701 goto fail;
6702 }
6703#endif
6704
6705 updown = 0;
6706 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)))) {
6707 WL_ERROR(("%s fail to set updown\n", __FUNCTION__));
6708 goto fail;
6709 }
6710
6711#ifdef AP_ONLY
6712
6713 apsta_var = 0;
6714 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
6715 WL_ERROR(("%s fail to set apsta_var 0\n", __FUNCTION__));
6716 goto fail;
6717 }
6718 apsta_var = 1;
6719 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
6720 WL_ERROR(("%s fail to set apsta_var 1\n", __FUNCTION__));
6721 goto fail;
6722 }
6723 res = dev_wlc_ioctl(dev, WLC_GET_AP, &apsta_var, sizeof(apsta_var));
6724#else
6725
6726 apsta_var = 1;
6727 iolen = wl_bssiovar_mkbuf("apsta",
6728 bsscfg_index, &apsta_var, sizeof(apsta_var)+4,
6729 buf, sizeof(buf), &mkvar_err);
6730 ASSERT(iolen);
6731 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) {
6732 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
6733 goto fail;
6734 }
6735 WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res));
6736
6737
6738 mpc = 0;
6739 if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) {
6740 WL_ERROR(("%s fail to set mpc\n", __FUNCTION__));
6741 goto fail;
6742 }
6743
6744
6745#endif
6746
6747 updown = 1;
6748 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) {
6749 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
6750 goto fail;
6751 }
6752
6753 } else {
6754
6755 if (!ap_net_dev) {
6756 WL_ERROR(("%s: ap_net_dev is null\n", __FUNCTION__));
6757 goto fail;
6758 }
6759
6760 res = wl_iw_softap_deassoc_stations(ap_net_dev, NULL);
6761
6762
6763 if ((res = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
6764 WL_ERROR(("%s fail to set bss down\n", __FUNCTION__));
6765 goto fail;
6766 }
6767 }
6768
6769
6770 if (strlen(ap->country_code)) {
6771 WL_ERROR(("%s: Igonored: Country MUST be specified"
6772 "COUNTRY command with \n", __FUNCTION__));
6773 } else {
6774 WL_SOFTAP(("%s: Country code is not specified,"
6775 " will use Radio's default\n",
6776 __FUNCTION__));
6777
6778 }
6779 iolen = wl_bssiovar_mkbuf("closednet",
6780 bsscfg_index, &ap->closednet, sizeof(ap->closednet)+4,
6781 buf, sizeof(buf), &mkvar_err);
6782 ASSERT(iolen);
6783 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) {
6784 WL_ERROR(("%s failed to set 'closednet'for apsta \n", __FUNCTION__));
6785 goto fail;
6786 }
6787
6788
6789 if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) {
6790 ap->channel = 1;
6791 WL_ERROR(("%s auto channel failed, use channel=%d\n",
6792 __FUNCTION__, ap->channel));
6793 }
6794
6795 channel = ap->channel;
6796 if ((res = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)))) {
6797 WL_ERROR(("%s fail to set channel\n", __FUNCTION__));
6798 }
6799
6800
6801 if (ap_cfg_running == FALSE) {
6802 updown = 0;
6803 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)))) {
6804 WL_ERROR(("%s fail to set up\n", __FUNCTION__));
6805 goto fail;
6806 }
6807 }
6808
6809 max_assoc = ap->max_scb;
6810 if ((res = dev_wlc_intvar_set(dev, "maxassoc", max_assoc))) {
6811 WL_ERROR(("%s fail to set maxassoc\n", __FUNCTION__));
6812 goto fail;
6813 }
6814
6815 ap_ssid.SSID_len = strlen(ap->ssid);
6816 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
6817
6818
6819#ifdef AP_ONLY
6820 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
6821 WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n",
6822 res, __FUNCTION__));
6823 goto fail;
6824 }
6825 wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START");
6826 ap_cfg_running = TRUE;
6827#else
6828
6829 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid),
6830 ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
6831 ASSERT(iolen);
6832 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) != 0) {
6833 WL_ERROR(("ERROR:%d in:%s, Security & BSS reconfiguration is skipped\n",
6834 res, __FUNCTION__));
6835 goto fail;
6836 }
6837 if (ap_cfg_running == FALSE) {
6838
6839 PROC_START(thr_wait_for_2nd_eth_dev, dev, &ap_eth_ctl, 0);
6840 } else {
6841 ap_eth_ctl.thr_pid = -1;
6842
6843 if (ap_net_dev == NULL) {
6844 WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__));
6845 goto fail;
6846 }
6847
6848 WL_ERROR(("%s: %s Configure security & restart AP bss \n",
6849 __FUNCTION__, ap_net_dev->name));
6850
6851
6852 if ((res = wl_iw_set_ap_security(ap_net_dev, &my_ap)) < 0) {
6853 WL_ERROR(("%s fail to set security : %d\n", __FUNCTION__, res));
6854 goto fail;
6855 }
6856
6857
6858 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) {
6859 WL_ERROR(("%s fail to set bss up\n", __FUNCTION__));
6860 goto fail;
6861 }
6862 }
6863#endif
6864fail:
6865 WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res));
6866
6867 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
6868 net_os_wake_unlock(dev);
6869
6870 return res;
6871}
6872#endif
6873
6874
6875
6876static int
6877wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap)
6878{
6879 int wsec = 0;
6880 int wpa_auth = 0;
6881 int res = 0;
6882 int i;
6883 char *ptr;
6884#ifdef AP_ONLY
6885 int mpc = 0;
6886 wlc_ssid_t ap_ssid;
6887#endif
6888 wl_wsec_key_t key;
6889
6890 WL_SOFTAP(("\nsetting SOFTAP security mode:\n"));
6891 WL_SOFTAP(("wl_iw: set ap profile:\n"));
6892 WL_SOFTAP((" ssid = '%s'\n", ap->ssid));
6893 WL_SOFTAP((" security = '%s'\n", ap->sec));
6894 if (ap->key[0] != '\0')
6895 WL_SOFTAP((" key = '%s'\n", ap->key));
6896 WL_SOFTAP((" channel = %d\n", ap->channel));
6897 WL_SOFTAP((" max scb = %d\n", ap->max_scb));
6898
6899
6900 if (strnicmp(ap->sec, "open", strlen("open")) == 0) {
6901
6902
6903 wsec = 0;
6904 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6905 wpa_auth = WPA_AUTH_DISABLED;
6906 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6907
6908 WL_SOFTAP(("=====================\n"));
6909 WL_SOFTAP((" wsec & wpa_auth set 'OPEN', result:&d %d\n", res));
6910 WL_SOFTAP(("=====================\n"));
6911
6912 } else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
6913
6914
6915 memset(&key, 0, sizeof(key));
6916
6917 wsec = WEP_ENABLED;
6918 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6919
6920 key.index = 0;
6921 if (wl_iw_parse_wep(ap->key, &key)) {
6922 WL_SOFTAP(("wep key parse err!\n"));
6923 return -1;
6924 }
6925
6926 key.index = htod32(key.index);
6927 key.len = htod32(key.len);
6928 key.algo = htod32(key.algo);
6929 key.flags = htod32(key.flags);
6930
6931 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
6932
6933 wpa_auth = WPA_AUTH_DISABLED;
6934 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6935
6936 WL_SOFTAP(("=====================\n"));
6937 WL_SOFTAP((" wsec & auth set 'WEP', result:&d %d\n", res));
6938 WL_SOFTAP(("=====================\n"));
6939
6940 } else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) {
6941
6942
6943
6944 wsec_pmk_t psk;
6945 size_t key_len;
6946
6947 wsec = AES_ENABLED;
6948 dev_wlc_intvar_set(dev, "wsec", wsec);
6949
6950 key_len = strlen(ap->key);
6951 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
6952 WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
6953 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
6954 return -1;
6955 }
6956
6957
6958 if (key_len < WSEC_MAX_PSK_LEN) {
6959 unsigned char output[2*SHA1HashSize];
6960 char key_str_buf[WSEC_MAX_PSK_LEN+1];
6961
6962
6963 memset(output, 0, sizeof(output));
6964 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
6965
6966 ptr = key_str_buf;
6967 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
6968
6969 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4],
6970 (uint)output[i*4+1], (uint)output[i*4+2],
6971 (uint)output[i*4+3]);
6972 ptr += 8;
6973 }
6974 WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf));
6975
6976 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
6977 memcpy(psk.key, key_str_buf, psk.key_len);
6978 } else {
6979 psk.key_len = htod16((ushort) key_len);
6980 memcpy(psk.key, ap->key, key_len);
6981 }
6982 psk.flags = htod16(WSEC_PASSPHRASE);
6983 dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
6984
6985 wpa_auth = WPA2_AUTH_PSK;
6986 dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6987
6988 } else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) {
6989
6990
6991 wsec_pmk_t psk;
6992 size_t key_len;
6993
6994 wsec = TKIP_ENABLED;
6995 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6996
6997 key_len = strlen(ap->key);
6998 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
6999 WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
7000 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
7001 return -1;
7002 }
7003
7004
7005 if (key_len < WSEC_MAX_PSK_LEN) {
7006 unsigned char output[2*SHA1HashSize];
7007 char key_str_buf[WSEC_MAX_PSK_LEN+1];
7008 bzero(output, 2*SHA1HashSize);
7009
7010 WL_SOFTAP(("%s: do passhash...\n", __FUNCTION__));
7011
7012 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
7013
7014 ptr = key_str_buf;
7015 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
7016 WL_SOFTAP(("[%02d]: %08x\n", i, *((unsigned int*)&output[i*4])));
7017
7018 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4],
7019 (uint)output[i*4+1], (uint)output[i*4+2],
7020 (uint)output[i*4+3]);
7021 ptr += 8;
7022 }
7023 printk("%s: passphase = %s\n", __FUNCTION__, key_str_buf);
7024
7025 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
7026 memcpy(psk.key, key_str_buf, psk.key_len);
7027 } else {
7028 psk.key_len = htod16((ushort) key_len);
7029 memcpy(psk.key, ap->key, key_len);
7030 }
7031
7032 psk.flags = htod16(WSEC_PASSPHRASE);
7033 res |= dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
7034
7035 wpa_auth = WPA_AUTH_PSK;
7036 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
7037
7038 WL_SOFTAP((" wsec & auth set 'wpa-psk' (TKIP), result:&d %d\n", res));
7039 }
7040
7041#ifdef AP_ONLY
7042 ap_ssid.SSID_len = strlen(ap->ssid);
7043 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
7044 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid));
7045 mpc = 0;
7046 res |= dev_wlc_intvar_set(dev, "mpc", mpc);
7047 if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
7048 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
7049 }
7050#endif
7051 return res;
7052}
7053
7054
7055
7056static int
7057get_parameter_from_string(
7058 char **str_ptr, const char *token,
7059 int param_type, void *dst, int param_max_len)
7060{
7061 char int_str[7] = "0";
7062 int parm_str_len;
7063 char *param_str_begin;
7064 char *param_str_end;
7065 char *orig_str = *str_ptr;
7066
7067 if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) {
7068
7069 strsep(str_ptr, "=,");
7070 param_str_begin = *str_ptr;
7071 strsep(str_ptr, "=,");
7072
7073 if (*str_ptr == NULL) {
7074
7075 parm_str_len = strlen(param_str_begin);
7076 } else {
7077 param_str_end = *str_ptr-1;
7078 parm_str_len = param_str_end - param_str_begin;
7079 }
7080
7081 WL_TRACE((" 'token:%s', len:%d, ", token, parm_str_len));
7082
7083 if (parm_str_len > param_max_len) {
7084 WL_ERROR((" WARNING: extracted param len:%d is > MAX:%d\n",
7085 parm_str_len, param_max_len));
7086
7087 parm_str_len = param_max_len;
7088 }
7089
7090 switch (param_type) {
7091
7092 case PTYPE_INTDEC: {
7093
7094 int *pdst_int = dst;
7095 char *eptr;
7096
7097 if (parm_str_len > sizeof(int_str))
7098 parm_str_len = sizeof(int_str);
7099
7100 memcpy(int_str, param_str_begin, parm_str_len);
7101
7102 *pdst_int = simple_strtoul(int_str, &eptr, 10);
7103
7104 WL_TRACE((" written as integer:%d\n", *pdst_int));
7105 }
7106 break;
7107 case PTYPE_STR_HEX: {
7108 u8 *buf = dst;
7109
7110 param_max_len = param_max_len >> 1;
7111 hstr_2_buf(param_str_begin, buf, param_max_len);
7112 dhd_print_buf(buf, param_max_len, 0);
7113 }
7114 break;
7115 default:
7116
7117 memcpy(dst, param_str_begin, parm_str_len);
7118 *((char *)dst + parm_str_len) = 0;
7119 WL_ERROR((" written as a string:%s\n", (char *)dst));
7120 break;
7121
7122 }
7123
7124 return 0;
7125 } else {
7126 WL_ERROR(("\n %s: ERROR: can't find token:%s in str:%s \n",
7127 __FUNCTION__, token, orig_str));
7128
7129 return -1;
7130 }
7131}
7132
7133static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac)
7134{
7135 int i;
7136 int res = 0;
7137 char mac_buf[128] = {0};
7138 char z_mac[6] = {0, 0, 0, 0, 0, 0};
7139 char *sta_mac;
7140 struct maclist *assoc_maclist = (struct maclist *) mac_buf;
7141 bool deauth_all = FALSE;
7142
7143
7144 if (mac == NULL) {
7145 deauth_all = TRUE;
7146 sta_mac = z_mac;
7147 } else {
7148 sta_mac = mac;
7149 }
7150
7151 memset(assoc_maclist, 0, sizeof(mac_buf));
7152 assoc_maclist->count = 8;
7153
7154 res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128);
7155 if (res != 0) {
7156 WL_SOFTAP(("%s: Error:%d Couldn't get ASSOC List\n", __FUNCTION__, res));
7157 return res;
7158 }
7159
7160 if (assoc_maclist->count)
7161 for (i = 0; i < assoc_maclist->count; i++) {
7162 scb_val_t scbval;
7163 scbval.val = htod32(1);
7164
7165 bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN);
7166
7167 if (deauth_all || (memcmp(&scbval.ea, sta_mac, ETHER_ADDR_LEN) == 0)) {
7168
7169 WL_SOFTAP(("%s, deauth STA:%d \n", __FUNCTION__, i));
7170 res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
7171 &scbval, sizeof(scb_val_t));
7172 }
7173 } else WL_SOFTAP(("%s: No Stations \n", __FUNCTION__));
7174
7175 if (res != 0) {
7176 WL_ERROR(("%s: Error:%d\n", __FUNCTION__, res));
7177 } else if (assoc_maclist->count) {
7178
7179 bcm_mdelay(200);
7180 }
7181 return res;
7182}
7183
7184
7185
7186static int
7187iwpriv_softap_stop(struct net_device *dev,
7188 struct iw_request_info *info,
7189 union iwreq_data *wrqu,
7190 char *ext)
7191{
7192 int res = 0;
7193
7194 WL_SOFTAP(("got iwpriv AP_BSS_STOP \n"));
7195
7196 if ((!dev) && (!ap_net_dev)) {
7197 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
7198 return res;
7199 }
7200
7201 net_os_wake_lock(dev);
7202 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
7203
7204 if ((ap_cfg_running == TRUE)) {
7205#ifdef AP_ONLY
7206 wl_iw_softap_deassoc_stations(dev, NULL);
7207#else
7208 wl_iw_softap_deassoc_stations(ap_net_dev, NULL);
7209 if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0)
7210 WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res));
7211#endif
7212
7213
7214 bcm_mdelay(100);
7215
7216 wrqu->data.length = 0;
7217 ap_cfg_running = FALSE;
7218 } else
7219 WL_ERROR(("%s: was called when SoftAP is OFF : move on\n", __FUNCTION__));
7220
7221 WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res));
7222 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
7223 net_os_wake_unlock(dev);
7224
7225 return res;
7226}
7227
7228
7229
7230static int
7231iwpriv_fw_reload(struct net_device *dev,
7232 struct iw_request_info *info,
7233 union iwreq_data *wrqu,
7234 char *ext)
7235{
7236 int ret = -1;
7237 char extra[256];
7238 char *fwstr = fw_path ;
7239
7240 WL_SOFTAP(("current firmware_path[]=%s\n", fwstr));
7241
7242 WL_TRACE((">Got FW_RELOAD cmd:"
7243 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d, "
7244 "fw_path:%p, len:%d \n",
7245 info->cmd, info->flags,
7246 wrqu->data.pointer, wrqu->data.length, fwstr, strlen(fwstr)));
7247
7248 if ((wrqu->data.length > 4) && (wrqu->data.length < sizeof(extra))) {
7249 char *str_ptr;
7250
7251 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
7252 ret = -EFAULT;
7253 goto exit_proc;
7254 }
7255
7256
7257 extra[wrqu->data.length] = 8;
7258 str_ptr = extra;
7259
7260 if (get_parameter_from_string(&str_ptr,
7261 "FW_PATH=", PTYPE_STRING, fwstr, 255) != 0) {
7262 WL_ERROR(("Error: extracting FW_PATH='' string\n"));
7263 goto exit_proc;
7264 }
7265
7266 if (strstr(fwstr, "apsta") != NULL) {
7267 WL_SOFTAP(("GOT APSTA FIRMWARE\n"));
7268 ap_fw_loaded = TRUE;
7269 } else {
7270 WL_SOFTAP(("GOT STA FIRMWARE\n"));
7271 ap_fw_loaded = FALSE;
7272 }
7273
7274 WL_SOFTAP(("SET firmware_path[]=%s , str_p:%p\n", fwstr, fwstr));
7275 ret = 0;
7276 } else {
7277 WL_ERROR(("Error: ivalid param len:%d\n", wrqu->data.length));
7278 }
7279
7280exit_proc:
7281 return ret;
7282}
7283
7284#ifdef SOFTAP
7285
7286static int
7287iwpriv_wpasupp_loop_tst(struct net_device *dev,
7288 struct iw_request_info *info,
7289 union iwreq_data *wrqu,
7290 char *ext)
7291{
7292 int res = 0;
7293 char *params = NULL;
7294
7295 WL_TRACE((">Got IWPRIV wp_supp loopback cmd test:"
7296 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
7297 info->cmd, info->flags,
7298 wrqu->data.pointer, wrqu->data.length));
7299
7300 if (wrqu->data.length != 0) {
7301
7302 if (!(params = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
7303 return -ENOMEM;
7304
7305
7306 if (copy_from_user(params, wrqu->data.pointer, wrqu->data.length)) {
7307 kfree(params);
7308 return -EFAULT;
7309 }
7310
7311 params[wrqu->data.length] = 0;
7312 WL_SOFTAP(("\n>> copied from user:\n %s\n", params));
7313 } else {
7314 WL_ERROR(("ERROR param length is 0\n"));
7315 return -EFAULT;
7316 }
7317
7318
7319 res = wl_iw_send_priv_event(dev, params);
7320 kfree(params);
7321
7322 return res;
7323}
7324#endif
7325
7326
7327static int
7328iwpriv_en_ap_bss(
7329 struct net_device *dev,
7330 struct iw_request_info *info,
7331 void *wrqu,
7332 char *extra)
7333{
7334 int res = 0;
7335
7336 if (!dev) {
7337 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
7338 return -1;
7339 }
7340
7341 net_os_wake_lock(dev);
7342 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
7343
7344 WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name));
7345
7346
7347#ifndef AP_ONLY
7348 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
7349 WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res));
7350 }
7351 else {
7352
7353 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0)
7354 WL_ERROR(("%s fail to set bss up err=%d\n", __FUNCTION__, res));
7355 else
7356
7357 bcm_mdelay(100);
7358 }
7359
7360#endif
7361 WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res));
7362
7363 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
7364 net_os_wake_unlock(dev);
7365
7366 return res;
7367}
7368
7369static int
7370get_assoc_sta_list(struct net_device *dev, char *buf, int len)
7371{
7372
7373 WL_TRACE(("%s: dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n",
7374 __FUNCTION__, dev, WLC_GET_ASSOCLIST, buf, len));
7375
7376 return dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len);
7377
7378}
7379
7380
7381void check_error(int res, const char *msg, const char *func, int line)
7382{
7383 if (res != 0)
7384 WL_ERROR(("%s, %d function:%s, line:%d\n", msg, res, func, line));
7385}
7386
7387static int
7388set_ap_mac_list(struct net_device *dev, void *buf)
7389{
7390 struct mac_list_set *mac_list_set = (struct mac_list_set *)buf;
7391 struct maclist *maclist = (struct maclist *)&mac_list_set->mac_list;
7392 int length;
7393 int i;
7394 int mac_mode = mac_list_set->mode;
7395 int ioc_res = 0;
7396 ap_macmode = mac_list_set->mode;
7397
7398
7399 bzero(&ap_black_list, sizeof(struct mflist));
7400
7401 if (mac_mode == MACLIST_MODE_DISABLED) {
7402
7403 ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
7404 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7405 WL_SOFTAP(("%s: MAC filtering disabled\n", __FUNCTION__));
7406 } else {
7407
7408 scb_val_t scbval;
7409 char mac_buf[256] = {0};
7410 struct maclist *assoc_maclist = (struct maclist *) mac_buf;
7411
7412
7413 bcopy(maclist, &ap_black_list, sizeof(ap_black_list));
7414
7415
7416 ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
7417 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7418
7419
7420 length = sizeof(maclist->count) + maclist->count*ETHER_ADDR_LEN;
7421 dev_wlc_ioctl(dev, WLC_SET_MACLIST, maclist, length);
7422
7423 WL_SOFTAP(("%s: applied MAC List, mode:%d, length %d:\n",
7424 __FUNCTION__, mac_mode, length));
7425
7426 for (i = 0; i < maclist->count; i++)
7427 WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n",
7428 i, maclist->ea[i].octet[0], maclist->ea[i].octet[1],
7429 maclist->ea[i].octet[2],
7430 maclist->ea[i].octet[3], maclist->ea[i].octet[4],
7431 maclist->ea[i].octet[5]));
7432
7433
7434 assoc_maclist->count = 8;
7435 ioc_res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256);
7436 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7437 WL_SOFTAP((" Cur assoc clients:%d\n", assoc_maclist->count));
7438
7439
7440 if (assoc_maclist->count)
7441 for (i = 0; i < assoc_maclist->count; i++) {
7442 int j;
7443 bool assoc_mac_matched = FALSE;
7444
7445 WL_SOFTAP(("\n Cheking assoc STA: "));
7446 dhd_print_buf(&assoc_maclist->ea[i], 6, 7);
7447 WL_SOFTAP(("with the b/w list:"));
7448
7449 for (j = 0; j < maclist->count; j++)
7450 if (!bcmp(&assoc_maclist->ea[i], &maclist->ea[j],
7451 ETHER_ADDR_LEN)) {
7452
7453 assoc_mac_matched = TRUE;
7454 break;
7455 }
7456
7457
7458 if (((mac_mode == MACLIST_MODE_ALLOW) && !assoc_mac_matched) ||
7459 ((mac_mode == MACLIST_MODE_DENY) && assoc_mac_matched)) {
7460
7461 WL_SOFTAP(("b-match or w-mismatch,"
7462 " do deauth/disassoc \n"));
7463 scbval.val = htod32(1);
7464 bcopy(&assoc_maclist->ea[i], &scbval.ea,
7465 ETHER_ADDR_LEN);
7466 ioc_res = dev_wlc_ioctl(dev,
7467 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
7468 &scbval, sizeof(scb_val_t));
7469 check_error(ioc_res,
7470 "ioctl ERROR:",
7471 __FUNCTION__, __LINE__);
7472
7473 } else {
7474 WL_SOFTAP((" no b/w list hits, let it be\n"));
7475 }
7476 } else {
7477 WL_SOFTAP(("No ASSOC CLIENTS\n"));
7478 }
7479
7480 }
7481
7482 WL_SOFTAP(("%s iocres:%d\n", __FUNCTION__, ioc_res));
7483 return ioc_res;
7484}
7485#endif
7486
7487
7488
7489#ifdef SOFTAP
7490#define PARAM_OFFSET PROFILE_OFFSET
7491
7492static int
7493wl_iw_process_private_ascii_cmd(
7494 struct net_device *dev,
7495 struct iw_request_info *info,
7496 union iwreq_data *dwrq,
7497 char *cmd_str)
7498{
7499 int ret = 0;
7500 char *sub_cmd = cmd_str + PROFILE_OFFSET + strlen("ASCII_CMD=");
7501
7502 WL_SOFTAP(("\n %s: ASCII_CMD: offs_0:%s, offset_32:\n'%s'\n",
7503 __FUNCTION__, cmd_str, cmd_str + PROFILE_OFFSET));
7504
7505 if (strnicmp(sub_cmd, "AP_CFG", strlen("AP_CFG")) == 0) {
7506
7507 WL_SOFTAP((" AP_CFG \n"));
7508
7509
7510 if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) {
7511 WL_ERROR(("ERROR: SoftAP CFG prams !\n"));
7512 ret = -1;
7513 } else {
7514 ret = set_ap_cfg(dev, &my_ap);
7515 }
7516
7517 } else if (strnicmp(sub_cmd, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
7518
7519 WL_SOFTAP(("\n SOFTAP - ENABLE BSS \n"));
7520
7521
7522 WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name));
7523
7524#ifndef AP_ONLY
7525 if (ap_net_dev == NULL) {
7526 printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n");
7527 } else {
7528
7529 if ((ret = iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str)) < 0)
7530 WL_ERROR(("%s line %d fail to set bss up\n",
7531 __FUNCTION__, __LINE__));
7532 }
7533#else
7534 if ((ret = iwpriv_en_ap_bss(dev, info, dwrq, cmd_str)) < 0)
7535 WL_ERROR(("%s line %d fail to set bss up\n",
7536 __FUNCTION__, __LINE__));
7537#endif
7538 } else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) {
7539
7540
7541
7542 } else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
7543
7544 WL_SOFTAP((" \n temp DOWN SOFTAP\n"));
7545#ifndef AP_ONLY
7546 if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
7547 WL_ERROR(("%s line %d fail to set bss down\n",
7548 __FUNCTION__, __LINE__));
7549 }
7550#endif
7551 }
7552
7553 return ret;
7554
7555}
7556#endif
7557
7558
7559static int
7560wl_iw_set_priv(
7561 struct net_device *dev,
7562 struct iw_request_info *info,
7563 struct iw_point *dwrq,
7564 char *ext
7565)
7566{
7567 int ret = 0;
7568 char * extra;
7569
7570 if (!(extra = kmalloc(dwrq->length, GFP_KERNEL)))
7571 return -ENOMEM;
7572
7573 if (copy_from_user(extra, dwrq->pointer, dwrq->length)) {
7574 kfree(extra);
7575 return -EFAULT;
7576 }
7577
7578 WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d\n",
7579 dev->name, extra, info->cmd, info->flags, dwrq->length));
7580
7581
7582
7583 net_os_wake_lock(dev);
7584
7585 if (dwrq->length && extra) {
7586 if (strnicmp(extra, "START", strlen("START")) == 0) {
7587 wl_iw_control_wl_on(dev, info);
7588 WL_TRACE(("%s, Received regular START command\n", __FUNCTION__));
7589 }
7590
7591 if (g_onoff == G_WLAN_SET_OFF) {
7592 WL_TRACE(("%s, missing START, Fail\n", __FUNCTION__));
7593 kfree(extra);
7594 net_os_wake_unlock(dev);
7595 return -EFAULT;
7596 }
7597
7598 if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
7599#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
7600 WL_TRACE(("%s: active scan setting suppressed\n", dev->name));
7601#else
7602 ret = wl_iw_set_active_scan(dev, info, (union iwreq_data *)dwrq, extra);
7603#endif
7604 }
7605 else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0)
7606#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
7607 WL_TRACE(("%s: passive scan setting suppressed\n", dev->name));
7608#else
7609 ret = wl_iw_set_passive_scan(dev, info, (union iwreq_data *)dwrq, extra);
7610#endif
7611 else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0)
7612 ret = wl_iw_get_rssi(dev, info, (union iwreq_data *)dwrq, extra);
7613 else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0)
7614 ret = wl_iw_get_link_speed(dev, info, (union iwreq_data *)dwrq, extra);
7615 else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0)
7616 ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra);
7617 else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0)
7618 ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra);
7619 else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
7620 ret = wl_iw_control_wl_off(dev, info);
7621 else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0)
7622 ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra);
7623 else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0)
7624 ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra);
7625 else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0)
7626 ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
7627 else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
7628 ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
7629 else if (strnicmp(extra, SETSUSPENDOPT_CMD, strlen(SETSUSPENDOPT_CMD)) == 0)
7630 ret = wl_iw_set_suspend_opt(dev, info, (union iwreq_data *)dwrq, extra);
7631 else if (strnicmp(extra, SETSUSPENDMODE_CMD, strlen(SETSUSPENDMODE_CMD)) == 0)
7632 ret = wl_iw_set_suspend_mode(dev, info, (union iwreq_data *)dwrq, extra);
7633 else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0)
7634 ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra);
7635#if defined(PNO_SUPPORT)
7636 else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0)
7637 ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
7638 else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
7639 ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
7640 else if (strnicmp(extra, PNOSETADD_SET_CMD, strlen(PNOSETADD_SET_CMD)) == 0)
7641 ret = wl_iw_set_pno_setadd(dev, info, (union iwreq_data *)dwrq, extra);
7642 else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
7643 ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
7644#endif
7645#if defined(CSCAN)
7646
7647 else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
7648 ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
7649#endif
7650#ifdef CONFIG_WPS2
7651 else if (strnicmp(extra, WPS_ADD_PROBE_REQ_IE_CMD,
7652 strlen(WPS_ADD_PROBE_REQ_IE_CMD)) == 0)
7653 ret = wl_iw_add_wps_probe_req_ie(dev, info,
7654 (union iwreq_data *)dwrq, extra);
7655 else if (strnicmp(extra, WPS_DEL_PROBE_REQ_IE_CMD,
7656 strlen(WPS_DEL_PROBE_REQ_IE_CMD)) == 0)
7657 ret = wl_iw_del_wps_probe_req_ie(dev, info,
7658 (union iwreq_data *)dwrq, extra);
7659#endif
7660 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
7661 ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
7662 else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
7663 ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
7664 else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0)
7665 ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
7666#ifdef SOFTAP
7667 else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) {
7668 wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra);
7669 }
7670 else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) {
7671 WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n"));
7672 set_ap_mac_list(dev, (extra + PROFILE_OFFSET));
7673 }
7674#endif
7675 else {
7676 WL_ERROR(("Unknown PRIVATE command %s - ignored\n", extra));
7677 snprintf(extra, MAX_WX_STRING, "OK");
7678 dwrq->length = strlen("OK") + 1;
7679 }
7680 }
7681
7682 net_os_wake_unlock(dev);
7683
7684 if (extra) {
7685 if (copy_to_user(dwrq->pointer, extra, dwrq->length)) {
7686 kfree(extra);
7687 return -EFAULT;
7688 }
7689
7690 kfree(extra);
7691 }
7692
7693 return ret;
7694}
7695
7696static const iw_handler wl_iw_handler[] =
7697{
7698 (iw_handler) wl_iw_config_commit,
7699 (iw_handler) wl_iw_get_name,
7700 (iw_handler) NULL,
7701 (iw_handler) NULL,
7702 (iw_handler) wl_iw_set_freq,
7703 (iw_handler) wl_iw_get_freq,
7704 (iw_handler) wl_iw_set_mode,
7705 (iw_handler) wl_iw_get_mode,
7706 (iw_handler) NULL,
7707 (iw_handler) NULL,
7708 (iw_handler) NULL,
7709 (iw_handler) wl_iw_get_range,
7710 (iw_handler) wl_iw_set_priv,
7711 (iw_handler) NULL,
7712 (iw_handler) NULL,
7713 (iw_handler) NULL,
7714 (iw_handler) wl_iw_set_spy,
7715 (iw_handler) wl_iw_get_spy,
7716 (iw_handler) NULL,
7717 (iw_handler) NULL,
7718 (iw_handler) wl_iw_set_wap,
7719 (iw_handler) wl_iw_get_wap,
7720#if WIRELESS_EXT > 17
7721 (iw_handler) wl_iw_mlme,
7722#else
7723 (iw_handler) NULL,
7724#endif
7725#if defined(WL_IW_USE_ISCAN)
7726 (iw_handler) wl_iw_iscan_get_aplist,
7727#else
7728 (iw_handler) wl_iw_get_aplist,
7729#endif
7730#if WIRELESS_EXT > 13
7731#if defined(WL_IW_USE_ISCAN)
7732 (iw_handler) wl_iw_iscan_set_scan,
7733 (iw_handler) wl_iw_iscan_get_scan,
7734#else
7735 (iw_handler) wl_iw_set_scan,
7736 (iw_handler) wl_iw_get_scan,
7737#endif
7738#else
7739 (iw_handler) NULL,
7740 (iw_handler) NULL,
7741#endif
7742 (iw_handler) wl_iw_set_essid,
7743 (iw_handler) wl_iw_get_essid,
7744 (iw_handler) wl_iw_set_nick,
7745 (iw_handler) wl_iw_get_nick,
7746 (iw_handler) NULL,
7747 (iw_handler) NULL,
7748 (iw_handler) wl_iw_set_rate,
7749 (iw_handler) wl_iw_get_rate,
7750 (iw_handler) wl_iw_set_rts,
7751 (iw_handler) wl_iw_get_rts,
7752 (iw_handler) wl_iw_set_frag,
7753 (iw_handler) wl_iw_get_frag,
7754 (iw_handler) wl_iw_set_txpow,
7755 (iw_handler) wl_iw_get_txpow,
7756#if WIRELESS_EXT > 10
7757 (iw_handler) wl_iw_set_retry,
7758 (iw_handler) wl_iw_get_retry,
7759#endif
7760 (iw_handler) wl_iw_set_encode,
7761 (iw_handler) wl_iw_get_encode,
7762 (iw_handler) wl_iw_set_power,
7763 (iw_handler) wl_iw_get_power,
7764#if WIRELESS_EXT > 17
7765 (iw_handler) NULL,
7766 (iw_handler) NULL,
7767 (iw_handler) wl_iw_set_wpaie,
7768 (iw_handler) wl_iw_get_wpaie,
7769 (iw_handler) wl_iw_set_wpaauth,
7770 (iw_handler) wl_iw_get_wpaauth,
7771 (iw_handler) wl_iw_set_encodeext,
7772 (iw_handler) wl_iw_get_encodeext,
7773 (iw_handler) wl_iw_set_pmksa,
7774#endif
7775};
7776
7777#if WIRELESS_EXT > 12
7778static const iw_handler wl_iw_priv_handler[] = {
7779 NULL,
7780 (iw_handler)wl_iw_set_active_scan,
7781 NULL,
7782 (iw_handler)wl_iw_get_rssi,
7783 NULL,
7784 (iw_handler)wl_iw_set_passive_scan,
7785 NULL,
7786 (iw_handler)wl_iw_get_link_speed,
7787 NULL,
7788 (iw_handler)wl_iw_get_macaddr,
7789 NULL,
7790 (iw_handler)wl_iw_control_wl_off,
7791 NULL,
7792 (iw_handler)wl_iw_control_wl_on,
7793#ifdef SOFTAP
7794
7795
7796 NULL,
7797 (iw_handler)iwpriv_set_ap_config,
7798
7799
7800
7801 NULL,
7802 (iw_handler)iwpriv_get_assoc_list,
7803
7804
7805 NULL,
7806 (iw_handler)iwpriv_set_mac_filters,
7807
7808
7809 NULL,
7810 (iw_handler)iwpriv_en_ap_bss,
7811
7812
7813 NULL,
7814 (iw_handler)iwpriv_wpasupp_loop_tst,
7815
7816 NULL,
7817 (iw_handler)iwpriv_softap_stop,
7818
7819 NULL,
7820 (iw_handler)iwpriv_fw_reload,
7821 NULL,
7822 (iw_handler)iwpriv_set_ap_sta_disassoc,
7823#endif
7824#if defined(CSCAN)
7825
7826 NULL,
7827 (iw_handler)iwpriv_set_cscan
7828#endif
7829};
7830
7831static const struct iw_priv_args wl_iw_priv_args[] =
7832{
7833 {
7834 WL_IW_SET_ACTIVE_SCAN,
7835 0,
7836 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7837 "SCAN-ACTIVE"
7838 },
7839 {
7840 WL_IW_GET_RSSI,
7841 0,
7842 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7843 "RSSI"
7844 },
7845 {
7846 WL_IW_SET_PASSIVE_SCAN,
7847 0,
7848 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7849 "SCAN-PASSIVE"
7850 },
7851 {
7852 WL_IW_GET_LINK_SPEED,
7853 0,
7854 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7855 "LINKSPEED"
7856 },
7857 {
7858 WL_IW_GET_CURR_MACADDR,
7859 0,
7860 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7861 "Macaddr"
7862 },
7863 {
7864 WL_IW_SET_STOP,
7865 0,
7866 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7867 "STOP"
7868 },
7869 {
7870 WL_IW_SET_START,
7871 0,
7872 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7873 "START"
7874 },
7875
7876#ifdef SOFTAP
7877
7878
7879 {
7880 WL_SET_AP_CFG,
7881 IW_PRIV_TYPE_CHAR | 256,
7882 0,
7883 "AP_SET_CFG"
7884 },
7885
7886 {
7887 WL_AP_STA_LIST,
7888 IW_PRIV_TYPE_CHAR | 0,
7889 IW_PRIV_TYPE_CHAR | 1024,
7890 "AP_GET_STA_LIST"
7891 },
7892
7893 {
7894 WL_AP_MAC_FLTR,
7895 IW_PRIV_TYPE_CHAR | 256,
7896 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7897 "AP_SET_MAC_FLTR"
7898 },
7899
7900 {
7901 WL_AP_BSS_START,
7902 0,
7903 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7904 "AP_BSS_START"
7905 },
7906
7907 {
7908 AP_LPB_CMD,
7909 IW_PRIV_TYPE_CHAR | 256,
7910 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7911 "AP_LPB_CMD"
7912 },
7913
7914 {
7915 WL_AP_STOP,
7916 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7917 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7918 "AP_BSS_STOP"
7919 },
7920 {
7921 WL_FW_RELOAD,
7922 IW_PRIV_TYPE_CHAR | 256,
7923 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7924 "WL_FW_RELOAD"
7925 },
7926#endif
7927#if defined(CSCAN)
7928 {
7929 WL_COMBO_SCAN,
7930 IW_PRIV_TYPE_CHAR | 1024,
7931 0,
7932 "CSCAN"
7933 },
7934#endif
7935 };
7936
7937const struct iw_handler_def wl_iw_handler_def =
7938{
7939 .num_standard = ARRAYSIZE(wl_iw_handler),
7940 .standard = (iw_handler *) wl_iw_handler,
7941 .num_private = ARRAYSIZE(wl_iw_priv_handler),
7942 .num_private_args = ARRAY_SIZE(wl_iw_priv_args),
7943 .private = (iw_handler *)wl_iw_priv_handler,
7944 .private_args = (void *) wl_iw_priv_args,
7945
7946#if WIRELESS_EXT >= 19
7947 get_wireless_stats: dhd_get_wireless_stats,
7948#endif
7949 };
7950#endif
7951
7952
7953
7954int
7955wl_iw_ioctl(
7956 struct net_device *dev,
7957 struct ifreq *rq,
7958 int cmd
7959)
7960{
7961 struct iwreq *wrq = (struct iwreq *) rq;
7962 struct iw_request_info info;
7963 iw_handler handler;
7964 char *extra = NULL;
7965 size_t token_size = 1;
7966 int max_tokens = 0, ret = 0;
7967
7968 net_os_wake_lock(dev);
7969
7970 WL_TRACE(("\n%s, cmd:%x called via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd));
7971 if (cmd < SIOCIWFIRST ||
7972 IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) ||
7973 !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) {
7974 WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd));
7975 net_os_wake_unlock(dev);
7976 return -EOPNOTSUPP;
7977 }
7978
7979 switch (cmd) {
7980
7981 case SIOCSIWESSID:
7982 case SIOCGIWESSID:
7983 case SIOCSIWNICKN:
7984 case SIOCGIWNICKN:
7985 max_tokens = IW_ESSID_MAX_SIZE + 1;
7986 break;
7987
7988 case SIOCSIWENCODE:
7989 case SIOCGIWENCODE:
7990#if WIRELESS_EXT > 17
7991 case SIOCSIWENCODEEXT:
7992 case SIOCGIWENCODEEXT:
7993#endif
7994 max_tokens = wrq->u.data.length;
7995 break;
7996
7997 case SIOCGIWRANGE:
7998
7999 max_tokens = sizeof(struct iw_range) + 500;
8000 break;
8001
8002 case SIOCGIWAPLIST:
8003 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
8004 max_tokens = IW_MAX_AP;
8005 break;
8006
8007#if WIRELESS_EXT > 13
8008 case SIOCGIWSCAN:
8009#if defined(WL_IW_USE_ISCAN)
8010 if (g_iscan)
8011 max_tokens = wrq->u.data.length;
8012 else
8013#endif
8014 max_tokens = IW_SCAN_MAX_DATA;
8015 break;
8016#endif
8017
8018 case SIOCSIWSPY:
8019 token_size = sizeof(struct sockaddr);
8020 max_tokens = IW_MAX_SPY;
8021 break;
8022
8023 case SIOCGIWSPY:
8024 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
8025 max_tokens = IW_MAX_SPY;
8026 break;
8027
8028#if WIRELESS_EXT > 17
8029 case SIOCSIWPMKSA:
8030 case SIOCSIWGENIE:
8031#endif
8032 case SIOCSIWPRIV:
8033 max_tokens = wrq->u.data.length;
8034 break;
8035 }
8036
8037 if (max_tokens && wrq->u.data.pointer) {
8038 if (wrq->u.data.length > max_tokens) {
8039 WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n",
8040 __FUNCTION__, cmd, wrq->u.data.length, max_tokens));
8041 ret = -E2BIG;
8042 goto wl_iw_ioctl_done;
8043 }
8044 if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) {
8045 ret = -ENOMEM;
8046 goto wl_iw_ioctl_done;
8047 }
8048
8049 if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) {
8050 kfree(extra);
8051 ret = -EFAULT;
8052 goto wl_iw_ioctl_done;
8053 }
8054 }
8055
8056 info.cmd = cmd;
8057 info.flags = 0;
8058
8059 ret = handler(dev, &info, &wrq->u, extra);
8060
8061 if (extra) {
8062 if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) {
8063 kfree(extra);
8064 ret = -EFAULT;
8065 goto wl_iw_ioctl_done;
8066 }
8067
8068 kfree(extra);
8069 }
8070
8071wl_iw_ioctl_done:
8072
8073 net_os_wake_unlock(dev);
8074
8075 return ret;
8076}
8077
8078
8079static bool
8080wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason,
8081 char* stringBuf, uint buflen)
8082{
8083 typedef struct conn_fail_event_map_t {
8084 uint32 inEvent;
8085 uint32 inStatus;
8086 uint32 inReason;
8087 const char* outName;
8088 const char* outCause;
8089 } conn_fail_event_map_t;
8090
8091
8092#define WL_IW_DONT_CARE 9999
8093 const conn_fail_event_map_t event_map [] = {
8094
8095
8096 {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE,
8097 "Conn", "Success"},
8098 {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
8099 "Conn", "NoNetworks"},
8100 {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
8101 "Conn", "ConfigMismatch"},
8102 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH,
8103 "Conn", "EncrypMismatch"},
8104 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH,
8105 "Conn", "RsnMismatch"},
8106 {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
8107 "Conn", "AuthTimeout"},
8108 {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
8109 "Conn", "AuthFail"},
8110 {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE,
8111 "Conn", "AuthNoAck"},
8112 {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
8113 "Conn", "ReassocFail"},
8114 {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
8115 "Conn", "ReassocTimeout"},
8116 {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE,
8117 "Conn", "ReassocAbort"},
8118 {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE,
8119 "Sup", "ConnSuccess"},
8120 {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8121 "Sup", "WpaHandshakeFail"},
8122 {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8123 "Conn", "Deauth"},
8124 {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8125 "Conn", "DisassocInd"},
8126 {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8127 "Conn", "Disassoc"}
8128 };
8129
8130 const char* name = "";
8131 const char* cause = NULL;
8132 int i;
8133
8134
8135 for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) {
8136 const conn_fail_event_map_t* row = &event_map[i];
8137 if (row->inEvent == event_type &&
8138 (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
8139 (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
8140 name = row->outName;
8141 cause = row->outCause;
8142 break;
8143 }
8144 }
8145
8146
8147 if (cause) {
8148 memset(stringBuf, 0, buflen);
8149 snprintf(stringBuf, buflen, "%s %s %02d %02d",
8150 name, cause, status, reason);
8151 WL_INFORM(("Connection status: %s\n", stringBuf));
8152 return TRUE;
8153 } else {
8154 return FALSE;
8155 }
8156}
8157
8158#if WIRELESS_EXT > 14
8159
8160static bool
8161wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen)
8162{
8163 uint32 event = ntoh32(e->event_type);
8164 uint32 status = ntoh32(e->status);
8165 uint32 reason = ntoh32(e->reason);
8166
8167 if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
8168 return TRUE;
8169 }
8170 else
8171 return FALSE;
8172}
8173#endif
8174
8175#ifndef IW_CUSTOM_MAX
8176#define IW_CUSTOM_MAX 256
8177#endif
8178
8179void
8180wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
8181{
8182#if WIRELESS_EXT > 13
8183 union iwreq_data wrqu;
8184 char extra[IW_CUSTOM_MAX + 1];
8185 int cmd = 0;
8186 uint32 event_type = ntoh32(e->event_type);
8187 uint16 flags = ntoh16(e->flags);
8188 uint32 datalen = ntoh32(e->datalen);
8189 uint32 status = ntoh32(e->status);
8190 uint32 toto;
8191 memset(&wrqu, 0, sizeof(wrqu));
8192 memset(extra, 0, sizeof(extra));
8193
8194 if (!dev) {
8195 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
8196 return;
8197 }
8198
8199 net_os_wake_lock(dev);
8200
8201 WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type));
8202
8203
8204 switch (event_type) {
8205#if defined(SOFTAP)
8206 case WLC_E_PRUNE:
8207 if (ap_cfg_running) {
8208 char *macaddr = (char *)&e->addr;
8209 WL_SOFTAP(("PRUNE received, %02X:%02X:%02X:%02X:%02X:%02X!\n",
8210 macaddr[0], macaddr[1], macaddr[2], macaddr[3],
8211 macaddr[4], macaddr[5]));
8212
8213
8214 if (ap_macmode)
8215 {
8216 int i;
8217 for (i = 0; i < ap_black_list.count; i++) {
8218 if (!bcmp(macaddr, &ap_black_list.ea[i],
8219 sizeof(struct ether_addr))) {
8220 WL_SOFTAP(("mac in black list, ignore it\n"));
8221 break;
8222 }
8223 }
8224
8225 if (i == ap_black_list.count) {
8226
8227 char mac_buf[32] = {0};
8228 sprintf(mac_buf, "STA_BLOCK %02X:%02X:%02X:%02X:%02X:%02X",
8229 macaddr[0], macaddr[1], macaddr[2],
8230 macaddr[3], macaddr[4], macaddr[5]);
8231 wl_iw_send_priv_event(priv_dev, mac_buf);
8232 }
8233 }
8234 }
8235 break;
8236#endif
8237 case WLC_E_TXFAIL:
8238 cmd = IWEVTXDROP;
8239 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8240 wrqu.addr.sa_family = ARPHRD_ETHER;
8241 break;
8242#if WIRELESS_EXT > 14
8243 case WLC_E_JOIN:
8244 case WLC_E_ASSOC_IND:
8245 case WLC_E_REASSOC_IND:
8246#if defined(SOFTAP)
8247 WL_SOFTAP(("STA connect received %d\n", event_type));
8248 if (ap_cfg_running) {
8249 wl_iw_send_priv_event(priv_dev, "STA_JOIN");
8250 goto wl_iw_event_end;
8251 }
8252#endif
8253 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8254 wrqu.addr.sa_family = ARPHRD_ETHER;
8255 cmd = IWEVREGISTERED;
8256 break;
8257 case WLC_E_ROAM:
8258 if (status == WLC_E_STATUS_SUCCESS) {
8259 WL_ASSOC((" WLC_E_ROAM : success \n"));
8260 goto wl_iw_event_end;
8261 }
8262 break;
8263
8264 case WLC_E_DEAUTH_IND:
8265 case WLC_E_DISASSOC_IND:
8266#if defined(SOFTAP)
8267 WL_SOFTAP(("STA disconnect received %d\n", event_type));
8268 if (ap_cfg_running) {
8269 wl_iw_send_priv_event(priv_dev, "STA_LEAVE");
8270 goto wl_iw_event_end;
8271 }
8272#endif
8273 cmd = SIOCGIWAP;
8274 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
8275 wrqu.addr.sa_family = ARPHRD_ETHER;
8276 bzero(&extra, ETHER_ADDR_LEN);
8277 break;
8278 case WLC_E_LINK:
8279 case WLC_E_NDIS_LINK:
8280 cmd = SIOCGIWAP;
8281 if (!(flags & WLC_EVENT_MSG_LINK)) {
8282
8283
8284#ifdef SOFTAP
8285#ifdef AP_ONLY
8286 if (ap_cfg_running) {
8287#else
8288 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
8289#endif
8290
8291 WL_SOFTAP(("AP DOWN %d\n", event_type));
8292 wl_iw_send_priv_event(priv_dev, "AP_DOWN");
8293 } else {
8294 WL_TRACE(("STA_Link Down\n"));
8295 g_ss_cache_ctrl.m_link_down = 1;
8296 }
8297#else
8298 g_ss_cache_ctrl.m_link_down = 1;
8299#endif
8300 WL_TRACE(("Link Down\n"));
8301
8302 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
8303 bzero(&extra, ETHER_ADDR_LEN);
8304 }
8305 else {
8306
8307 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8308 g_ss_cache_ctrl.m_link_down = 0;
8309
8310 memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN);
8311#ifdef SOFTAP
8312
8313#ifdef AP_ONLY
8314 if (ap_cfg_running) {
8315#else
8316 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
8317#endif
8318
8319 WL_SOFTAP(("AP UP %d\n", event_type));
8320 wl_iw_send_priv_event(priv_dev, "AP_UP");
8321 } else {
8322 WL_TRACE(("STA_LINK_UP\n"));
8323 }
8324#else
8325#endif
8326 WL_TRACE(("Link UP\n"));
8327
8328 }
8329 wrqu.addr.sa_family = ARPHRD_ETHER;
8330 break;
8331 case WLC_E_ACTION_FRAME:
8332 cmd = IWEVCUSTOM;
8333 if (datalen + 1 <= sizeof(extra)) {
8334 wrqu.data.length = datalen + 1;
8335 extra[0] = WLC_E_ACTION_FRAME;
8336 memcpy(&extra[1], data, datalen);
8337 WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length));
8338 }
8339 break;
8340
8341 case WLC_E_ACTION_FRAME_COMPLETE:
8342 cmd = IWEVCUSTOM;
8343 memcpy(&toto, data, 4);
8344 if (sizeof(status) + 1 <= sizeof(extra)) {
8345 wrqu.data.length = sizeof(status) + 1;
8346 extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
8347 memcpy(&extra[1], &status, sizeof(status));
8348 printf("wl_iw_event status %d PacketId %d \n", status, toto);
8349 printf("WLC_E_ACTION_FRAME_COMPLETE len %d \n", wrqu.data.length);
8350 }
8351 break;
8352#endif
8353#if WIRELESS_EXT > 17
8354 case WLC_E_MIC_ERROR: {
8355 struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra;
8356 cmd = IWEVMICHAELMICFAILURE;
8357 wrqu.data.length = sizeof(struct iw_michaelmicfailure);
8358 if (flags & WLC_EVENT_MSG_GROUP)
8359 micerrevt->flags |= IW_MICFAILURE_GROUP;
8360 else
8361 micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
8362 memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8363 micerrevt->src_addr.sa_family = ARPHRD_ETHER;
8364
8365 break;
8366 }
8367
8368 case WLC_E_ASSOC_REQ_IE:
8369 cmd = IWEVASSOCREQIE;
8370 wrqu.data.length = datalen;
8371 if (datalen < sizeof(extra))
8372 memcpy(extra, data, datalen);
8373 break;
8374
8375 case WLC_E_ASSOC_RESP_IE:
8376 cmd = IWEVASSOCRESPIE;
8377 wrqu.data.length = datalen;
8378 if (datalen < sizeof(extra))
8379 memcpy(extra, data, datalen);
8380 break;
8381
8382 case WLC_E_PMKID_CACHE: {
8383 if (data)
8384 {
8385 struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra;
8386 pmkid_cand_list_t *pmkcandlist;
8387 pmkid_cand_t *pmkidcand;
8388 int count;
8389
8390 cmd = IWEVPMKIDCAND;
8391 pmkcandlist = data;
8392 count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand);
8393 ASSERT(count >= 0);
8394 wrqu.data.length = sizeof(struct iw_pmkid_cand);
8395 pmkidcand = pmkcandlist->pmkid_cand;
8396 while (count) {
8397 bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand));
8398 if (pmkidcand->preauth)
8399 iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH;
8400 bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data,
8401 ETHER_ADDR_LEN);
8402 wireless_send_event(dev, cmd, &wrqu, extra);
8403 pmkidcand++;
8404 count--;
8405 }
8406 }
8407 goto wl_iw_event_end;
8408 }
8409#endif
8410
8411 case WLC_E_SCAN_COMPLETE:
8412#if defined(WL_IW_USE_ISCAN)
8413 if (!g_iscan) {
8414 WL_ERROR(("Event WLC_E_SCAN_COMPLETE on g_iscan NULL!"));
8415 goto wl_iw_event_end;
8416 }
8417
8418 if ((g_iscan) && (g_iscan->tsk_ctl.thr_pid >= 0) &&
8419 (g_iscan->iscan_state != ISCAN_STATE_IDLE))
8420 {
8421 up(&g_iscan->tsk_ctl.sema);
8422 } else {
8423 cmd = SIOCGIWSCAN;
8424 wrqu.data.length = strlen(extra);
8425 WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan %d\n",
8426 g_iscan->iscan_state));
8427 }
8428#else
8429 cmd = SIOCGIWSCAN;
8430 wrqu.data.length = strlen(extra);
8431 WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
8432#endif
8433 break;
8434
8435
8436 case WLC_E_PFN_NET_FOUND:
8437 {
8438 wl_pfn_net_info_t *netinfo;
8439 netinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) -
8440 sizeof(wl_pfn_net_info_t));
8441 WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n",
8442 __FUNCTION__, PNO_EVENT_UP, netinfo->pfnsubnet.SSID,
8443 netinfo->pfnsubnet.SSID_len));
8444 cmd = IWEVCUSTOM;
8445 memset(&wrqu, 0, sizeof(wrqu));
8446 strcpy(extra, PNO_EVENT_UP);
8447 wrqu.data.length = strlen(extra);
8448 }
8449 break;
8450
8451 default:
8452
8453 WL_TRACE(("Unknown Event %d: ignoring\n", event_type));
8454 break;
8455 }
8456 if (cmd) {
8457 if (cmd == SIOCGIWSCAN)
8458 wireless_send_event(dev, cmd, &wrqu, NULL);
8459 else
8460 wireless_send_event(dev, cmd, &wrqu, extra);
8461 }
8462
8463#if WIRELESS_EXT > 14
8464
8465 memset(extra, 0, sizeof(extra));
8466 if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
8467 cmd = IWEVCUSTOM;
8468 wrqu.data.length = strlen(extra);
8469 wireless_send_event(dev, cmd, &wrqu, extra);
8470 }
8471#endif
8472
8473 goto wl_iw_event_end;
8474wl_iw_event_end:
8475
8476 net_os_wake_unlock(dev);
8477#endif
8478}
8479
8480int
8481wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
8482{
8483 int res = 0;
8484 wl_cnt_t cnt;
8485 int phy_noise;
8486 int rssi;
8487 scb_val_t scb_val;
8488
8489 phy_noise = 0;
8490 if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise))))
8491 goto done;
8492
8493 phy_noise = dtoh32(phy_noise);
8494 WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise));
8495
8496 bzero(&scb_val, sizeof(scb_val_t));
8497 if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t))))
8498 goto done;
8499
8500 rssi = dtoh32(scb_val.val);
8501 WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi));
8502 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
8503 wstats->qual.qual = 0;
8504 else if (rssi <= WL_IW_RSSI_VERY_LOW)
8505 wstats->qual.qual = 1;
8506 else if (rssi <= WL_IW_RSSI_LOW)
8507 wstats->qual.qual = 2;
8508 else if (rssi <= WL_IW_RSSI_GOOD)
8509 wstats->qual.qual = 3;
8510 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
8511 wstats->qual.qual = 4;
8512 else
8513 wstats->qual.qual = 5;
8514
8515
8516 wstats->qual.level = 0x100 + rssi;
8517 wstats->qual.noise = 0x100 + phy_noise;
8518#if WIRELESS_EXT > 18
8519 wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
8520#else
8521 wstats->qual.updated |= 7;
8522#endif
8523
8524#if WIRELESS_EXT > 11
8525 WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n", (int)sizeof(wl_cnt_t)));
8526
8527 memset(&cnt, 0, sizeof(wl_cnt_t));
8528 res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
8529 if (res)
8530 {
8531 WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n", res));
8532 goto done;
8533 }
8534
8535 cnt.version = dtoh16(cnt.version);
8536 if (cnt.version != WL_CNT_T_VERSION) {
8537 WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n",
8538 WL_CNT_T_VERSION, cnt.version));
8539 goto done;
8540 }
8541
8542 wstats->discard.nwid = 0;
8543 wstats->discard.code = dtoh32(cnt.rxundec);
8544 wstats->discard.fragment = dtoh32(cnt.rxfragerr);
8545 wstats->discard.retries = dtoh32(cnt.txfail);
8546 wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant);
8547 wstats->miss.beacon = 0;
8548
8549 WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
8550 dtoh32(cnt.txframe), dtoh32(cnt.txbyte)));
8551 WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)));
8552 WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)));
8553 WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)));
8554 WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)));
8555 WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)));
8556 WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)));
8557 WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)));
8558
8559#endif
8560
8561done:
8562 return res;
8563}
8564#if defined(COEX_DHCP)
8565static void
8566wl_iw_bt_flag_set(
8567 struct net_device *dev,
8568 bool set)
8569{
8570#if defined(BT_DHCP_USE_FLAGS)
8571 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
8572 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
8573#endif
8574
8575#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8576 rtnl_lock();
8577#endif
8578
8579
8580#if defined(BT_DHCP_eSCO_FIX)
8581
8582 set_btc_esco_params(dev, set);
8583#endif
8584
8585
8586#if defined(BT_DHCP_USE_FLAGS)
8587 WL_TRACE_COEX(("WI-FI priority boost via bt flags, set:%d\n", set));
8588 if (set == TRUE) {
8589
8590 dev_wlc_bufvar_set(dev, "btc_flags",
8591 (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on));
8592 }
8593 else {
8594
8595 dev_wlc_bufvar_set(dev, "btc_flags",
8596 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
8597 }
8598#endif
8599
8600#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8601 rtnl_unlock();
8602#endif
8603}
8604
8605static void
8606wl_iw_bt_timerfunc(ulong data)
8607{
8608 bt_info_t *bt_local = (bt_info_t *)data;
8609 bt_local->timer_on = 0;
8610 WL_TRACE(("%s\n", __FUNCTION__));
8611
8612 up(&bt_local->tsk_ctl.sema);
8613}
8614
8615static int
8616_bt_dhcp_sysioc_thread(void *data)
8617{
8618 tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
8619
8620 DAEMONIZE("dhcp_sysioc");
8621
8622 complete(&tsk_ctl->completed);
8623
8624 while (down_interruptible(&tsk_ctl->sema) == 0) {
8625
8626 SMP_RD_BARRIER_DEPENDS();
8627 if (tsk_ctl->terminated) {
8628 break;
8629 }
8630
8631 if (g_bt->timer_on) {
8632 g_bt->timer_on = 0;
8633 del_timer_sync(&g_bt->timer);
8634 }
8635
8636 switch (g_bt->bt_state) {
8637 case BT_DHCP_START:
8638
8639 WL_TRACE_COEX(("%s bt_dhcp stm: started \n", __FUNCTION__));
8640 g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW;
8641 mod_timer(&g_bt->timer,
8642 jiffies + msecs_to_jiffies(BT_DHCP_OPPORTUNITY_WINDOW_TIME));
8643 g_bt->timer_on = 1;
8644 break;
8645
8646 case BT_DHCP_OPPORTUNITY_WINDOW:
8647 if (g_bt->dhcp_done) {
8648 WL_TRACE_COEX(("%s DHCP Done before T1 expiration\n",
8649 __FUNCTION__));
8650 goto btc_coex_idle;
8651 }
8652
8653
8654 WL_TRACE_COEX(("%s DHCP T1:%d expired\n",
8655 __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIME));
8656
8657 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE);
8658 g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
8659 mod_timer(&g_bt->timer, jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME));
8660 g_bt->timer_on = 1;
8661 break;
8662
8663 case BT_DHCP_FLAG_FORCE_TIMEOUT:
8664 if (g_bt->dhcp_done) {
8665 WL_TRACE_COEX(("%s DHCP Done before T2 expiration\n",
8666 __FUNCTION__));
8667 } else {
8668
8669 WL_TRACE_COEX(("%s DHCP wait interval T2:%d msec expired\n",
8670 __FUNCTION__, BT_DHCP_FLAG_FORCE_TIME));
8671 }
8672
8673
8674 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
8675 btc_coex_idle:
8676 g_bt->bt_state = BT_DHCP_IDLE;
8677 g_bt->timer_on = 0;
8678 break;
8679
8680 default:
8681 WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__,
8682 g_bt->bt_state));
8683 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
8684 g_bt->bt_state = BT_DHCP_IDLE;
8685 g_bt->timer_on = 0;
8686 break;
8687 }
8688
8689 net_os_wake_unlock(g_bt->dev);
8690 }
8691
8692 if (g_bt->timer_on) {
8693 g_bt->timer_on = 0;
8694 del_timer_sync(&g_bt->timer);
8695 }
8696 complete_and_exit(&tsk_ctl->completed, 0);
8697}
8698
8699static void
8700wl_iw_bt_release(void)
8701{
8702 bt_info_t *bt_local = g_bt;
8703
8704 if (!bt_local) {
8705 return;
8706 }
8707
8708 if (bt_local->tsk_ctl.thr_pid >= 0) {
8709 PROC_STOP(&bt_local->tsk_ctl);
8710 }
8711 kfree(bt_local);
8712 g_bt = NULL;
8713}
8714
8715static int
8716wl_iw_bt_init(struct net_device *dev)
8717{
8718 bt_info_t *bt_dhcp = NULL;
8719
8720 bt_dhcp = kmalloc(sizeof(bt_info_t), GFP_KERNEL);
8721 if (!bt_dhcp)
8722 return -ENOMEM;
8723
8724 memset(bt_dhcp, 0, sizeof(bt_info_t));
8725
8726 g_bt = bt_dhcp;
8727 bt_dhcp->dev = dev;
8728 bt_dhcp->bt_state = BT_DHCP_IDLE;
8729
8730
8731 bt_dhcp->timer_ms = 10;
8732 init_timer(&bt_dhcp->timer);
8733 bt_dhcp->timer.data = (ulong)bt_dhcp;
8734 bt_dhcp->timer.function = wl_iw_bt_timerfunc;
8735 bt_dhcp->ts_dhcp_start = 0;
8736 bt_dhcp->ts_dhcp_ok = 0;
8737
8738 PROC_START(_bt_dhcp_sysioc_thread, bt_dhcp, &bt_dhcp->tsk_ctl, 0);
8739 if (bt_dhcp->tsk_ctl.thr_pid < 0) {
8740 WL_ERROR(("Failed in %s\n", __FUNCTION__));
8741 return -ENOMEM;
8742 }
8743
8744 return 0;
8745}
8746#endif
8747
8748int
8749wl_iw_attach(struct net_device *dev, void * dhdp)
8750{
8751#if defined(WL_IW_USE_ISCAN)
8752 int params_size = 0;
8753#endif
8754 wl_iw_t *iw;
8755#if defined(WL_IW_USE_ISCAN)
8756 iscan_info_t *iscan = NULL;
8757#endif
8758
8759 DHD_OS_MUTEX_INIT(&wl_cache_lock);
8760 DHD_OS_MUTEX_INIT(&wl_softap_lock);
8761
8762#if defined(WL_IW_USE_ISCAN)
8763 if (!dev)
8764 return 0;
8765
8766
8767 memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
8768
8769
8770#ifdef CSCAN
8771 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
8772 (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
8773#else
8774 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
8775#endif
8776 iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
8777 if (!iscan)
8778 return -ENOMEM;
8779 memset(iscan, 0, sizeof(iscan_info_t));
8780
8781
8782 iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
8783 if (!iscan->iscan_ex_params_p) {
8784 kfree(iscan);
8785 return -ENOMEM;
8786 }
8787 iscan->iscan_ex_param_size = params_size;
8788
8789
8790 g_iscan = iscan;
8791 iscan->dev = dev;
8792 iscan->iscan_state = ISCAN_STATE_IDLE;
8793
8794#if defined(CONFIG_FIRST_SCAN)
8795 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
8796 g_first_counter_scans = 0;
8797 g_iscan->scan_flag = 0;
8798#endif
8799
8800#ifdef CONFIG_WPS2
8801 g_wps_probe_req_ie = NULL;
8802 g_wps_probe_req_ie_len = 0;
8803#endif
8804
8805 iscan->timer_ms = 8000;
8806 init_timer(&iscan->timer);
8807 iscan->timer.data = (ulong)iscan;
8808 iscan->timer.function = wl_iw_timerfunc;
8809
8810 PROC_START(_iscan_sysioc_thread, iscan, &iscan->tsk_ctl, 0);
8811 if (iscan->tsk_ctl.thr_pid < 0)
8812 return -ENOMEM;
8813#endif
8814
8815 iw = *(wl_iw_t **)netdev_priv(dev);
8816 iw->pub = (dhd_pub_t *)dhdp;
8817#ifdef SOFTAP
8818 priv_dev = dev;
8819#endif
8820 g_scan = NULL;
8821
8822
8823 g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
8824 if (!g_scan)
8825 return -ENOMEM;
8826
8827 memset(g_scan, 0, G_SCAN_RESULTS);
8828 g_scan_specified_ssid = 0;
8829
8830#if !defined(CSCAN)
8831
8832 wl_iw_init_ss_cache_ctrl();
8833#endif
8834#ifdef COEX_DHCP
8835
8836 wl_iw_bt_init(dev);
8837#endif
8838
8839
8840 return 0;
8841}
8842
8843void
8844wl_iw_detach(void)
8845{
8846#if defined(WL_IW_USE_ISCAN)
8847 iscan_buf_t *buf;
8848 iscan_info_t *iscan = g_iscan;
8849
8850 if (!iscan)
8851 return;
8852 if (iscan->tsk_ctl.thr_pid >= 0) {
8853 PROC_STOP(&iscan->tsk_ctl);
8854 }
8855 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
8856 while (iscan->list_hdr) {
8857 buf = iscan->list_hdr->next;
8858 kfree(iscan->list_hdr);
8859 iscan->list_hdr = buf;
8860 }
8861 kfree(iscan->iscan_ex_params_p);
8862 kfree(iscan);
8863 g_iscan = NULL;
8864 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
8865#endif
8866
8867 if (g_scan)
8868 kfree(g_scan);
8869
8870 g_scan = NULL;
8871#ifdef CONFIG_WPS2
8872
8873 if (g_wps_probe_req_ie) {
8874 kfree(g_wps_probe_req_ie);
8875 g_wps_probe_req_ie = NULL;
8876 g_wps_probe_req_ie_len = 0;
8877 }
8878#endif
8879#if !defined(CSCAN)
8880 wl_iw_release_ss_cache_ctrl();
8881#endif
8882#ifdef COEX_DHCP
8883 wl_iw_bt_release();
8884#endif
8885
8886#ifdef SOFTAP
8887 if (ap_cfg_running) {
8888 WL_TRACE(("\n%s AP is going down\n", __FUNCTION__));
8889
8890 wl_iw_send_priv_event(priv_dev, "AP_DOWN");
8891 }
8892#endif
8893
8894}