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