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