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