OSDN Git Service

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