net: wireless: bcmdhd: Update to 5.90.125.69
[linux-2.6.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 Exp $
25  */
26
27 #include <wlioctl.h>
28
29 #include <typedefs.h>
30 #include <linuxver.h>
31 #include <osl.h>
32
33 #include <bcmutils.h>
34 #include <bcmendian.h>
35 #include <proto/ethernet.h>
36
37 #include <linux/if_arp.h>
38 #include <asm/uaccess.h>
39
40 #include <dngl_stats.h>
41 #include <dhd.h>
42 #include <dhdioctl.h>
43
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 #ifdef CONFIG_WIRELESS_EXT
166
167 extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
168 extern int dhd_wait_pend8021x(struct net_device *dev);
169 #endif 
170
171 #if WIRELESS_EXT < 19
172 #define IW_IOCTL_IDX(cmd)       ((cmd) - SIOCIWFIRST)
173 #define IW_EVENT_IDX(cmd)       ((cmd) - IWEVFIRST)
174 #endif 
175
176 static void *g_scan = NULL;
177 static volatile uint g_scan_specified_ssid;     
178 static wlc_ssid_t g_specific_ssid;              
179
180 static wlc_ssid_t g_ssid;
181
182 bool btcoex_is_sco_active(struct net_device *dev);  
183 static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl;   
184 #if defined(CONFIG_FIRST_SCAN)
185 static volatile uint g_first_broadcast_scan;    
186 static volatile uint g_first_counter_scans;
187 #define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3
188 #endif 
189
190 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
191 #define DAEMONIZE(a) daemonize(a); \
192         allow_signal(SIGKILL); \
193         allow_signal(SIGTERM);
194 #else 
195 #define RAISE_RX_SOFTIRQ() \
196         cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
197 #define DAEMONIZE(a) daemonize(); \
198         do { if (a) \
199                 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
200         } while (0);
201 #endif 
202
203 #if defined(WL_IW_USE_ISCAN)
204 #if  !defined(CSCAN)
205 static void wl_iw_free_ss_cache(void);
206 static int   wl_iw_run_ss_cache_timer(int kick_off);
207 #endif 
208 #if defined(CONFIG_FIRST_SCAN)
209 int  wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
210 #endif 
211 static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len);
212 #define ISCAN_STATE_IDLE   0
213 #define ISCAN_STATE_SCANING 1
214
215
216 #define WLC_IW_ISCAN_MAXLEN   2048
217 typedef struct iscan_buf {
218         struct iscan_buf * next;
219         char   iscan_buf[WLC_IW_ISCAN_MAXLEN];
220 } iscan_buf_t;
221
222 typedef struct iscan_info {
223         struct net_device *dev;
224         struct timer_list timer;
225         uint32 timer_ms;
226         uint32 timer_on;
227         int    iscan_state;
228         iscan_buf_t * list_hdr;
229         iscan_buf_t * list_cur;
230
231         
232         tsk_ctl_t tsk_ctl;
233
234         uint32 scan_flag;       
235 #if defined CSCAN
236         char ioctlbuf[WLC_IOCTL_MEDLEN];
237 #else
238         char ioctlbuf[WLC_IOCTL_SMLEN];
239 #endif 
240         
241         wl_iscan_params_t *iscan_ex_params_p;
242         int iscan_ex_param_size;
243 } iscan_info_t;
244
245
246
247 #define  COEX_DHCP 1    
248 #ifdef COEX_DHCP
249
250 #define BT_DHCP_eSCO_FIX 
251 #define BT_DHCP_USE_FLAGS  
252 #define BT_DHCP_OPPORTUNITY_WINDOW_TIME  2500 
253 #define BT_DHCP_FLAG_FORCE_TIME 5500 
254
255
256
257 static int wl_iw_set_btcoex_dhcp(
258         struct net_device *dev,
259         struct iw_request_info *info,
260         union iwreq_data *wrqu,
261         char *extra
262 );
263
264 static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
265 static void wl_iw_bt_release(void);
266
267 typedef enum bt_coex_status {
268         BT_DHCP_IDLE = 0,
269         BT_DHCP_START,
270         BT_DHCP_OPPORTUNITY_WINDOW,
271         BT_DHCP_FLAG_FORCE_TIMEOUT
272 } coex_status_t;
273
274
275 typedef struct bt_info {
276         struct net_device *dev;
277         struct timer_list timer;
278         uint32 timer_ms;
279         uint32 timer_on;
280         uint32 ts_dhcp_start; 
281         uint32 ts_dhcp_ok;    
282         bool    dhcp_done; 
283         int     bt_state;
284
285         
286         tsk_ctl_t tsk_ctl;
287
288 } bt_info_t;
289
290 bt_info_t *g_bt = NULL;
291 static void wl_iw_bt_timerfunc(ulong data);
292 #endif 
293 iscan_info_t *g_iscan = NULL;
294 void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
295 static void wl_iw_timerfunc(ulong data);
296 static void wl_iw_set_event_mask(struct net_device *dev);
297 static int
298 wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action);
299 #endif 
300
301 static int
302 wl_iw_set_scan(
303         struct net_device *dev,
304         struct iw_request_info *info,
305         union iwreq_data *wrqu,
306         char *extra
307 );
308
309 #ifndef CSCAN
310 static int
311 wl_iw_get_scan(
312         struct net_device *dev,
313         struct iw_request_info *info,
314         struct iw_point *dwrq,
315         char *extra
316 );
317
318 static uint
319 wl_iw_get_scan_prep(
320         wl_scan_results_t *list,
321         struct iw_request_info *info,
322         char *extra,
323         short max_size
324 );
325 #endif 
326
327 static void
328 swap_key_from_BE(
329         wl_wsec_key_t *key
330 )
331 {
332         key->index = htod32(key->index);
333         key->len = htod32(key->len);
334         key->algo = htod32(key->algo);
335         key->flags = htod32(key->flags);
336         key->rxiv.hi = htod32(key->rxiv.hi);
337         key->rxiv.lo = htod16(key->rxiv.lo);
338         key->iv_initialized = htod32(key->iv_initialized);
339 }
340
341 static void
342 swap_key_to_BE(
343         wl_wsec_key_t *key
344 )
345 {
346         key->index = dtoh32(key->index);
347         key->len = dtoh32(key->len);
348         key->algo = dtoh32(key->algo);
349         key->flags = dtoh32(key->flags);
350         key->rxiv.hi = dtoh32(key->rxiv.hi);
351         key->rxiv.lo = dtoh16(key->rxiv.lo);
352         key->iv_initialized = dtoh32(key->iv_initialized);
353 }
354
355 static int
356 dev_wlc_ioctl(
357         struct net_device *dev,
358         int cmd,
359         void *arg,
360         int len
361 )
362 {
363         struct ifreq ifr;
364         wl_ioctl_t ioc;
365         mm_segment_t fs;
366         int ret = -EINVAL;
367
368         if (!dev) {
369                 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
370                 return ret;
371         }
372
373         net_os_wake_lock(dev);
374
375         WL_INFORM(("%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n",
376                 __FUNCTION__, current->pid, cmd, arg, len));
377
378         if (g_onoff == G_WLAN_SET_ON) {
379                 memset(&ioc, 0, sizeof(ioc));
380                 ioc.cmd = cmd;
381                 ioc.buf = arg;
382                 ioc.len = len;
383
384                 strcpy(ifr.ifr_name, dev->name);
385                 ifr.ifr_data = (caddr_t) &ioc;
386
387                 
388                 ret = dev_open(dev);
389                 if (ret) {
390                         WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret));
391                         net_os_wake_unlock(dev);
392                         return ret;
393                 }
394
395                 fs = get_fs();
396                 set_fs(get_ds());
397 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)
398                 ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
399 #else
400                 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
401 #endif 
402                 set_fs(fs);
403         }
404         else {
405                 WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__));
406         }
407
408         net_os_wake_unlock(dev);
409
410         return ret;
411 }
412
413
414 static int
415 dev_wlc_intvar_get_reg(
416         struct net_device *dev,
417         char *name,
418         uint  reg,
419         int *retval)
420 {
421         union {
422                 char buf[WLC_IOCTL_SMLEN];
423                 int val;
424         } var;
425         int error;
426
427         uint len;
428         len = bcm_mkiovar(name, (char *)(&reg), sizeof(reg), (char *)(&var), sizeof(var.buf));
429         ASSERT(len);
430         error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
431
432         *retval = dtoh32(var.val);
433         return (error);
434 }
435
436
437 static int
438 dev_wlc_intvar_set_reg(
439         struct net_device *dev,
440         char *name,
441         char *addr,
442         char * val)
443 {
444         char reg_addr[8];
445
446         memset(reg_addr, 0, sizeof(reg_addr));
447         memcpy((char *)&reg_addr[0], (char *)addr, 4);
448         memcpy((char *)&reg_addr[4], (char *)val, 4);
449
450         return (dev_wlc_bufvar_set(dev, name,  (char *)&reg_addr[0], sizeof(reg_addr)));
451 }
452
453
454
455
456 static int
457 dev_wlc_intvar_set(
458         struct net_device *dev,
459         char *name,
460         int val)
461 {
462         char buf[WLC_IOCTL_SMLEN];
463         uint len;
464
465         val = htod32(val);
466         len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
467         ASSERT(len);
468
469         return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
470 }
471
472 #if defined(WL_IW_USE_ISCAN)
473 static int
474 dev_iw_iovar_setbuf(
475         struct net_device *dev,
476         char *iovar,
477         void *param,
478         int paramlen,
479         void *bufptr,
480         int buflen)
481 {
482         int iolen;
483
484         iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
485         ASSERT(iolen);
486
487         if (iolen == 0)
488                 return 0;
489
490         return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen));
491 }
492
493 static int
494 dev_iw_iovar_getbuf(
495         struct net_device *dev,
496         char *iovar,
497         void *param,
498         int paramlen,
499         void *bufptr,
500         int buflen)
501 {
502         int iolen;
503
504         iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
505         ASSERT(iolen);
506
507         return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen));
508 }
509 #endif 
510
511
512 #if WIRELESS_EXT > 17
513 static int
514 dev_wlc_bufvar_set(
515         struct net_device *dev,
516         char *name,
517         char *buf, int len)
518 {
519 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
520         char ioctlbuf[MAX_WLIW_IOCTL_LEN];
521 #else
522         static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
523 #endif 
524         uint buflen;
525
526         buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
527         ASSERT(buflen);
528
529         return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen));
530 }
531 #endif 
532
533
534 static int
535 dev_wlc_bufvar_get(
536         struct net_device *dev,
537         char *name,
538         char *buf, int buflen)
539 {
540 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
541         char ioctlbuf[MAX_WLIW_IOCTL_LEN];
542 #else
543         static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
544 #endif 
545         int error;
546         uint len;
547
548         len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
549         ASSERT(len);
550         error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN);
551         if (!error)
552                 bcopy(ioctlbuf, buf, buflen);
553
554         return (error);
555 }
556
557
558
559 static int
560 dev_wlc_intvar_get(
561         struct net_device *dev,
562         char *name,
563         int *retval)
564 {
565         union {
566                 char buf[WLC_IOCTL_SMLEN];
567                 int val;
568         } var;
569         int error;
570
571         uint len;
572         uint data_null;
573
574         len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
575         ASSERT(len);
576         error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
577
578         *retval = dtoh32(var.val);
579
580         return (error);
581 }
582
583
584 #if WIRELESS_EXT > 12
585 static int
586 wl_iw_set_active_scan(
587         struct net_device *dev,
588         struct iw_request_info *info,
589         union iwreq_data *wrqu,
590         char *extra
591 )
592 {
593         int as = 0;
594         int error = 0;
595         char *p = extra;
596
597 #if defined(WL_IW_USE_ISCAN)
598         if (g_iscan->iscan_state == ISCAN_STATE_IDLE)
599 #endif 
600                 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
601 #if defined(WL_IW_USE_ISCAN)
602         else
603                 g_iscan->scan_flag = as;
604 #endif 
605         p += snprintf(p, MAX_WX_STRING, "OK");
606
607         wrqu->data.length = p - extra + 1;
608         return error;
609 }
610
611 static int
612 wl_iw_set_passive_scan(
613         struct net_device *dev,
614         struct iw_request_info *info,
615         union iwreq_data *wrqu,
616         char *extra
617 )
618 {
619         int ps = 1;
620         int error = 0;
621         char *p = extra;
622
623 #if defined(WL_IW_USE_ISCAN)
624         if (g_iscan->iscan_state == ISCAN_STATE_IDLE) {
625 #endif 
626
627                  
628                 if (g_scan_specified_ssid == 0) {
629                         error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &ps, sizeof(ps));
630                 }
631 #if defined(WL_IW_USE_ISCAN)
632         }
633         else
634                 g_iscan->scan_flag = ps;
635 #endif 
636
637         p += snprintf(p, MAX_WX_STRING, "OK");
638
639         wrqu->data.length = p - extra + 1;
640         return error;
641 }
642
643
644 static int
645 wl_iw_set_txpower(
646         struct net_device *dev,
647         struct iw_request_info *info,
648         union iwreq_data *wrqu,
649         char *extra
650 )
651 {
652         int error = 0;
653         char *p = extra;
654         int txpower = -1;
655
656         txpower = bcm_atoi(extra + strlen(TXPOWER_SET_CMD) + 1);
657         if ((txpower >= 0) && (txpower <= 127))
658         {
659                 txpower |= WL_TXPWR_OVERRIDE;
660                 txpower = htod32(txpower);
661
662                 error = dev_wlc_intvar_set(dev, "qtxpower", txpower);
663                 p += snprintf(p, MAX_WX_STRING, "OK");
664                 WL_TRACE(("%s: set TXpower 0x%X is OK\n", __FUNCTION__, txpower));
665         } else {
666                 WL_ERROR(("%s: set tx power failed\n", __FUNCTION__));
667                 p += snprintf(p, MAX_WX_STRING, "FAIL");
668         }
669
670         wrqu->data.length = p - extra + 1;
671         return error;
672 }
673
674 static int
675 wl_iw_get_macaddr(
676         struct net_device *dev,
677         struct iw_request_info *info,
678         union iwreq_data *wrqu,
679         char *extra
680 )
681 {
682         int error;
683         char buf[128];
684         struct ether_addr *id;
685         char *p = extra;
686
687         
688         strcpy(buf, "cur_etheraddr");
689         error = dev_wlc_ioctl(dev, WLC_GET_VAR, buf, sizeof(buf));
690         id = (struct ether_addr *) buf;
691         p += snprintf(p, MAX_WX_STRING, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
692                 id->octet[0], id->octet[1], id->octet[2],
693                 id->octet[3], id->octet[4], id->octet[5]);
694         wrqu->data.length = p - extra + 1;
695
696         return error;
697 }
698
699
700
701 static int
702 wl_iw_set_country(
703         struct net_device *dev,
704         struct iw_request_info *info,
705         union iwreq_data *wrqu,
706         char *extra
707 )
708 {
709         char country_code[WLC_CNTRY_BUF_SZ];
710         int error = 0;
711         char *p = extra;
712         int country_offset;
713         int country_code_size;
714         wl_country_t cspec = {{0}, 0, {0}};
715         char smbuf[WLC_IOCTL_SMLEN];
716         scb_val_t scbval;
717
718         cspec.rev = -1;
719         memset(country_code, 0, sizeof(country_code));
720         memset(smbuf, 0, sizeof(smbuf));
721
722         
723         country_offset = strcspn(extra, " ");
724         country_code_size = strlen(extra) - country_offset;
725
726         
727         if (country_offset != 0) {
728                 strncpy(country_code, extra + country_offset +1,
729                         MIN(country_code_size, sizeof(country_code)));
730
731                 
732                 bzero(&scbval, sizeof(scb_val_t));
733                 if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) {
734                         WL_ERROR(("%s: set country failed due to Disassoc error\n", __FUNCTION__));
735                         goto exit_failed;
736                 }
737
738                 memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
739                 memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
740
741                 get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
742
743                 
744                 if ((error = dev_iw_iovar_setbuf(dev, "country", &cspec,
745                         sizeof(cspec), smbuf, sizeof(smbuf))) >= 0) {
746                         p += snprintf(p, MAX_WX_STRING, "OK");
747                         WL_ERROR(("%s: set country for %s as %s rev %d is OK\n",
748                                 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
749                         dhd_bus_country_set(dev, &cspec);
750                         goto exit;
751                 }
752         }
753
754         WL_ERROR(("%s: set country for %s as %s rev %d failed\n",
755                 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
756
757 exit_failed:
758         p += snprintf(p, MAX_WX_STRING, "FAIL");
759
760 exit:
761         wrqu->data.length = p - extra + 1;
762         return error;
763 }
764
765 static int
766 wl_iw_set_power_mode(
767         struct net_device *dev,
768         struct iw_request_info *info,
769         union iwreq_data *wrqu,
770         char *extra
771 )
772 {
773         int error = 0;
774         char *p = extra;
775         static int  pm = PM_FAST;
776         int  pm_local = PM_OFF;
777         char powermode_val = 0;
778
779         WL_TRACE_COEX(("%s: DHCP session cmd:%s\n", __FUNCTION__, extra));
780
781         strncpy((char *)&powermode_val, extra + strlen("POWERMODE") +1, 1);
782
783         if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
784
785                 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
786
787                 dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
788                 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
789
790                 
791                 net_os_set_packet_filter(dev, 0);
792
793 #ifdef COEX_DHCP
794                 g_bt->ts_dhcp_start = JF2MS;
795                 g_bt->dhcp_done = FALSE;
796                 WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n",
797                         __FUNCTION__, pm, pm_local));
798
799 #endif 
800         } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
801                 
802
803                 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
804
805                 
806                 net_os_set_packet_filter(dev, 1);
807
808 #ifdef COEX_DHCP
809                 g_bt->dhcp_done = TRUE;
810                 g_bt->ts_dhcp_ok = JF2MS;
811                 WL_TRACE_COEX(("%s: DHCP done for:%d ms, restored pm:%d\n",
812                         __FUNCTION__, (g_bt->ts_dhcp_ok - g_bt->ts_dhcp_start), pm));
813 #endif 
814
815         } else {
816                 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
817                         __FUNCTION__));
818         }
819
820         p += snprintf(p, MAX_WX_STRING, "OK");
821
822         wrqu->data.length = p - extra + 1;
823
824         return error;
825 }
826
827
828 bool btcoex_is_sco_active(struct net_device *dev)
829 {
830         int ioc_res = 0;
831         bool res = FALSE;
832         int sco_id_cnt = 0;
833         int param27;
834         int i;
835
836         for (i = 0; i < 12; i++) {
837
838                 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
839
840                 WL_TRACE_COEX(("%s, sample[%d], btc params: 27:%x\n",
841                         __FUNCTION__, i, param27));
842
843                 if (ioc_res < 0) {
844                         WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__));
845                         break;
846                 }
847
848                 if ((param27 & 0x6) == 2) { 
849                         sco_id_cnt++;
850                 }
851
852                 if (sco_id_cnt > 2) {
853                         WL_TRACE_COEX(("%s, sco/esco detected, pkt id_cnt:%d  samples:%d\n",
854                                 __FUNCTION__, sco_id_cnt, i));
855                         res = TRUE;
856                         break;
857                 }
858
859                 msleep(5);
860         }
861
862         return res;
863 }
864
865 #if defined(BT_DHCP_eSCO_FIX)
866
867 static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
868 {
869         static bool saved_status = FALSE;
870
871         char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
872         char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
873         char buf_reg64va_dhcp_on[8] = { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
874         char buf_reg65va_dhcp_on[8] = { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
875         char buf_reg71va_dhcp_on[8] = { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
876
877         uint32 regaddr;
878         static uint32 saved_reg50;
879         static uint32 saved_reg51;
880         static uint32 saved_reg64;
881         static uint32 saved_reg65;
882         static uint32 saved_reg71;
883
884         if (trump_sco) { 
885
886                 
887                 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
888
889
890                 if  ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50,  &saved_reg50)) &&
891                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 51,  &saved_reg51)) &&
892                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 64,  &saved_reg64)) &&
893                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 65,  &saved_reg65)) &&
894                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 71,  &saved_reg71))) {
895
896                         saved_status = TRUE;
897                         WL_TRACE_COEX(("%s saved bt_params[50,51,64,65,71]:"
898                                 " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
899                                 __FUNCTION__, saved_reg50, saved_reg51,
900                                 saved_reg64, saved_reg65, saved_reg71));
901
902                 } else {
903                         WL_ERROR((":%s: save btc_params failed\n",
904                                 __FUNCTION__));
905                         saved_status = FALSE;
906                         return -1;
907                 }
908
909                 WL_TRACE_COEX(("override with [50,51,64,65,71]:"
910                         " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
911                         *(u32 *)(buf_reg50va_dhcp_on+4),
912                         *(u32 *)(buf_reg51va_dhcp_on+4),
913                         *(u32 *)(buf_reg64va_dhcp_on+4),
914                         *(u32 *)(buf_reg65va_dhcp_on+4),
915                         *(u32 *)(buf_reg71va_dhcp_on+4)));
916
917                 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg50va_dhcp_on[0], 8);
918                 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg51va_dhcp_on[0], 8);
919                 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg64va_dhcp_on[0], 8);
920                 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8);
921                 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8);
922
923                 saved_status = TRUE;
924
925         } else if (saved_status) {
926                 
927                 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
928
929                 regaddr = 50;
930                 dev_wlc_intvar_set_reg(dev, "btc_params",
931                         (char *)&regaddr, (char *)&saved_reg50);
932                 regaddr = 51;
933                 dev_wlc_intvar_set_reg(dev, "btc_params",
934                         (char *)&regaddr, (char *)&saved_reg51);
935                 regaddr = 64;
936                 dev_wlc_intvar_set_reg(dev, "btc_params",
937                         (char *)&regaddr, (char *)&saved_reg64);
938                 regaddr = 65;
939                 dev_wlc_intvar_set_reg(dev, "btc_params",
940                         (char *)&regaddr, (char *)&saved_reg65);
941                 regaddr = 71;
942                 dev_wlc_intvar_set_reg(dev, "btc_params",
943                         (char *)&regaddr, (char *)&saved_reg71);
944
945                 WL_TRACE_COEX(("restore bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
946                         saved_reg50, saved_reg51, saved_reg64,
947                         saved_reg65, saved_reg71));
948
949                 saved_status = FALSE;
950         } else {
951                 WL_ERROR((":%s att to restore not saved BTCOEX params\n",
952                         __FUNCTION__));
953                 return -1;
954         }
955         return 0;
956 }
957 #endif 
958
959
960 static int
961 wl_iw_get_power_mode(
962         struct net_device *dev,
963         struct iw_request_info *info,
964         union iwreq_data *wrqu,
965         char *extra
966 )
967 {
968         int error = 0;
969         int pm_local;
970         char *p = extra;
971
972         error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local));
973         if (!error) {
974                 WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local));
975                 if (pm_local == PM_OFF)
976                         pm_local = 1; 
977                 else
978                         pm_local = 0; 
979                 p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local);
980         }
981         else {
982                 WL_TRACE(("%s: Error = %d\n", __func__, error));
983                 p += snprintf(p, MAX_WX_STRING, "FAIL");
984         }
985         wrqu->data.length = p - extra + 1;
986         return error;
987 }
988
989 static int
990 wl_iw_set_btcoex_dhcp(
991         struct net_device *dev,
992         struct iw_request_info *info,
993         union iwreq_data *wrqu,
994         char *extra
995 )
996 {
997         int error = 0;
998         char *p = extra;
999         char powermode_val = 0;
1000         char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
1001         char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
1002         char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
1003
1004         uint32 regaddr;
1005         static uint32 saved_reg66;
1006         static uint32 saved_reg41;
1007         static uint32 saved_reg68;
1008         static bool saved_status = FALSE;
1009
1010 #ifdef COEX_DHCP
1011         char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
1012 #endif 
1013
1014         
1015         strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") +1, 1);
1016
1017         if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
1018
1019                 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
1020
1021                 
1022                 if ((saved_status == FALSE) &&
1023                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
1024                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
1025                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
1026                                 saved_status = TRUE;
1027                                 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
1028                                         saved_reg66, saved_reg41, saved_reg68));
1029
1030                                 
1031
1032                                 
1033 #ifdef COEX_DHCP
1034                                 
1035                                 if (btcoex_is_sco_active(dev)) {
1036                                         
1037                                         dev_wlc_bufvar_set(dev, "btc_params",
1038                                                 (char *)&buf_reg66va_dhcp_on[0],
1039                                                 sizeof(buf_reg66va_dhcp_on));
1040                                         
1041                                         dev_wlc_bufvar_set(dev, "btc_params",
1042                                                 (char *)&buf_reg41va_dhcp_on[0],
1043                                                 sizeof(buf_reg41va_dhcp_on));
1044                                         
1045                                         dev_wlc_bufvar_set(dev, "btc_params",
1046                                                 (char *)&buf_reg68va_dhcp_on[0],
1047                                                 sizeof(buf_reg68va_dhcp_on));
1048                                         saved_status = TRUE;
1049
1050                                         g_bt->bt_state = BT_DHCP_START;
1051                                         g_bt->timer_on = 1;
1052                                         mod_timer(&g_bt->timer, g_bt->timer.expires);
1053                                         WL_TRACE_COEX(("%s enable BT DHCP Timer\n",
1054                                         __FUNCTION__));
1055                                 }
1056 #endif 
1057                 }
1058                 else if (saved_status == TRUE) {
1059                         WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
1060                 }
1061         }
1062         else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
1063
1064
1065                 
1066
1067 #ifdef COEX_DHCP
1068                 
1069                 WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
1070                 if (g_bt->timer_on) {
1071                         g_bt->timer_on = 0;
1072                         del_timer_sync(&g_bt->timer);
1073
1074                         if (g_bt->bt_state != BT_DHCP_IDLE) {
1075                         
1076                                 WL_TRACE_COEX(("%s bt->bt_state:%d\n",
1077                                         __FUNCTION__, g_bt->bt_state));
1078                                 
1079                                 up(&g_bt->tsk_ctl.sema);
1080                         }
1081                 }
1082
1083                 
1084                 if (saved_status == TRUE)
1085                         dev_wlc_bufvar_set(dev, "btc_flags",
1086                                 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
1087 #endif 
1088
1089                 
1090                 if (saved_status == TRUE) {
1091                         regaddr = 66;
1092                         dev_wlc_intvar_set_reg(dev, "btc_params",
1093                                 (char *)&regaddr, (char *)&saved_reg66);
1094                         regaddr = 41;
1095                         dev_wlc_intvar_set_reg(dev, "btc_params",
1096                                 (char *)&regaddr, (char *)&saved_reg41);
1097                         regaddr = 68;
1098                         dev_wlc_intvar_set_reg(dev, "btc_params",
1099                                 (char *)&regaddr, (char *)&saved_reg68);
1100
1101                         WL_TRACE_COEX(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
1102                                 saved_reg66, saved_reg41, saved_reg68));
1103                 }
1104                 saved_status = FALSE;
1105
1106         }
1107         else {
1108                 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
1109                         __FUNCTION__));
1110         }
1111
1112         p += snprintf(p, MAX_WX_STRING, "OK");
1113
1114         wrqu->data.length = p - extra + 1;
1115
1116         return error;
1117 }
1118
1119 static int
1120 wl_iw_set_suspend(
1121 struct net_device *dev,
1122 struct iw_request_info *info,
1123 union iwreq_data *wrqu,
1124 char *extra
1125 )
1126 {
1127         int suspend_flag;
1128         int ret_now;
1129         int ret = 0;
1130
1131         suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0';
1132
1133         if (suspend_flag != 0)
1134                 suspend_flag = 1;
1135
1136         ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1137
1138         
1139         if (ret_now != suspend_flag) {
1140                 if (!(ret = net_os_set_suspend(dev, ret_now)))
1141                         WL_ERROR(("%s: Suspend Flag %d -> %d\n",
1142                                   __FUNCTION__, ret_now, suspend_flag));
1143                 else
1144                         WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1145         }
1146
1147         return ret;
1148 }
1149
1150 static int
1151 wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
1152 {
1153         int i, c;
1154         char *p = ssid_buf;
1155
1156         if (ssid_len > 32) ssid_len = 32;
1157
1158         for (i = 0; i < ssid_len; i++) {
1159                 c = (int)ssid[i];
1160                 if (c == '\\') {
1161                         *p++ = '\\';
1162                         *p++ = '\\';
1163                 } else if (isprint((uchar)c)) {
1164                         *p++ = (char)c;
1165                 } else {
1166                         p += sprintf(p, "\\x%02X", c);
1167                 }
1168         }
1169         *p = '\0';
1170
1171         return p - ssid_buf;
1172 }
1173
1174 static int
1175 wl_iw_get_link_speed(
1176         struct net_device *dev,
1177         struct iw_request_info *info,
1178         union iwreq_data *wrqu,
1179         char *extra
1180 )
1181 {
1182         int error = 0;
1183         char *p = extra;
1184         static int link_speed;
1185
1186         
1187         net_os_wake_lock(dev);
1188         if (g_onoff == G_WLAN_SET_ON) {
1189                 error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed));
1190                 link_speed *= 500000;
1191         }
1192
1193         p += snprintf(p, MAX_WX_STRING, "LinkSpeed %d", link_speed/1000000);
1194
1195         wrqu->data.length = p - extra + 1;
1196
1197         net_os_wake_unlock(dev);
1198         return error;
1199 }
1200
1201
1202 static int
1203 wl_iw_get_dtim_skip(
1204         struct net_device *dev,
1205         struct iw_request_info *info,
1206         union iwreq_data *wrqu,
1207         char *extra
1208 )
1209 {
1210         int error = -1;
1211         char *p = extra;
1212         char iovbuf[32];
1213
1214         net_os_wake_lock(dev);
1215         if (g_onoff == G_WLAN_SET_ON) {
1216
1217                         memset(iovbuf, 0, sizeof(iovbuf));
1218                         strcpy(iovbuf, "bcn_li_dtim");
1219
1220                         if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR,
1221                                 &iovbuf, sizeof(iovbuf))) >= 0) {
1222
1223                                 p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]);
1224                                 WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0]));
1225                                 wrqu->data.length = p - extra + 1;
1226                         }
1227                         else
1228                                 WL_ERROR(("%s: get dtim_skip failed code %d\n",
1229                                         __FUNCTION__, error));
1230         }
1231         net_os_wake_unlock(dev);
1232         return error;
1233 }
1234
1235
1236 static int
1237 wl_iw_set_dtim_skip(
1238         struct net_device *dev,
1239         struct iw_request_info *info,
1240         union iwreq_data *wrqu,
1241         char *extra
1242 )
1243 {
1244         int error = -1;
1245         char *p = extra;
1246         int bcn_li_dtim;
1247         char iovbuf[32];
1248
1249         net_os_wake_lock(dev);
1250         if (g_onoff == G_WLAN_SET_ON) {
1251
1252                 bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0');
1253
1254                 if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) {
1255
1256                         memset(iovbuf, 0, sizeof(iovbuf));
1257                         bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1258                                 4, iovbuf, sizeof(iovbuf));
1259
1260                         if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR,
1261                                 &iovbuf, sizeof(iovbuf))) >= 0) {
1262                                 p += snprintf(p, MAX_WX_STRING, "OK");
1263
1264                                 net_os_set_dtim_skip(dev, bcn_li_dtim);
1265
1266                                 WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__,
1267                                         bcn_li_dtim));
1268                                 goto exit;
1269                         }
1270                         else  WL_ERROR(("%s: set dtim_skip %d failed code %d\n",
1271                                 __FUNCTION__, bcn_li_dtim, error));
1272                 }
1273                 else  WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n",
1274                         __FUNCTION__, bcn_li_dtim));
1275         }
1276
1277         p += snprintf(p, MAX_WX_STRING, "FAIL");
1278
1279 exit:
1280         wrqu->data.length = p - extra + 1;
1281         net_os_wake_unlock(dev);
1282         return error;
1283 }
1284
1285
1286 static int
1287 wl_iw_get_band(
1288         struct net_device *dev,
1289         struct iw_request_info *info,
1290         union iwreq_data *wrqu,
1291         char *extra
1292 )
1293 {
1294         int error = -1;
1295         char *p = extra;
1296         static int band;
1297
1298         net_os_wake_lock(dev);
1299
1300         if (g_onoff == G_WLAN_SET_ON) {
1301                 error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band));
1302
1303                 p += snprintf(p, MAX_WX_STRING, "Band %d", band);
1304
1305                 wrqu->data.length = p - extra + 1;
1306         }
1307
1308         net_os_wake_unlock(dev);
1309         return error;
1310 }
1311
1312
1313 static int
1314 wl_iw_set_band(
1315         struct net_device *dev,
1316         struct iw_request_info *info,
1317         union iwreq_data *wrqu,
1318         char *extra
1319 )
1320 {
1321         int error = -1;
1322         char *p = extra;
1323         uint band;
1324
1325         net_os_wake_lock(dev);
1326
1327         if (g_onoff == G_WLAN_SET_ON) {
1328
1329                 band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0');
1330
1331                 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
1332                         
1333                         if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND,
1334                                 &band, sizeof(band))) >= 0) {
1335                                 p += snprintf(p, MAX_WX_STRING, "OK");
1336                                 WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band));
1337                                 goto exit;
1338                         } else {
1339                                 WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__,
1340                                           band, error));
1341                         }
1342                 } else {
1343                         WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band));
1344                 }
1345         }
1346
1347         p += snprintf(p, MAX_WX_STRING, "FAIL");
1348
1349 exit:
1350         wrqu->data.length = p - extra + 1;
1351         net_os_wake_unlock(dev);
1352         return error;
1353 }
1354
1355 #ifdef PNO_SUPPORT
1356
1357 static int
1358 wl_iw_set_pno_reset(
1359         struct net_device *dev,
1360         struct iw_request_info *info,
1361         union iwreq_data *wrqu,
1362         char *extra
1363 )
1364 {
1365         int error = -1;
1366         char *p = extra;
1367
1368         net_os_wake_lock(dev);
1369         if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1370
1371                 if ((error = dhd_dev_pno_reset(dev)) >= 0) {
1372                                 p += snprintf(p, MAX_WX_STRING, "OK");
1373                                 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1374                                 goto exit;
1375                 }
1376                 else  WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1377         }
1378
1379         p += snprintf(p, MAX_WX_STRING, "FAIL");
1380
1381 exit:
1382         wrqu->data.length = p - extra + 1;
1383         net_os_wake_unlock(dev);
1384         return error;
1385 }
1386
1387
1388
1389 static int
1390 wl_iw_set_pno_enable(
1391         struct net_device *dev,
1392         struct iw_request_info *info,
1393         union iwreq_data *wrqu,
1394         char *extra
1395 )
1396 {
1397         int error = -1;
1398         char *p = extra;
1399         int pfn_enabled;
1400
1401         net_os_wake_lock(dev);
1402         pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0');
1403
1404         if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1405
1406                 if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) {
1407                                 p += snprintf(p, MAX_WX_STRING, "OK");
1408                                 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1409                                 goto exit;
1410                 }
1411                 else  WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1412         }
1413
1414         p += snprintf(p, MAX_WX_STRING, "FAIL");
1415
1416 exit:
1417         wrqu->data.length = p - extra + 1;
1418         net_os_wake_unlock(dev);
1419         return error;
1420 }
1421
1422
1423
1424 static int
1425 wl_iw_set_pno_set(
1426         struct net_device *dev,
1427         struct iw_request_info *info,
1428         union iwreq_data *wrqu,
1429         char *extra
1430 )
1431 {
1432         int res = -1;
1433         wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
1434         int nssid = 0;
1435         cmd_tlv_t *cmd_tlv_temp;
1436         char *str_ptr;
1437         int tlv_size_left;
1438         int pno_time;
1439         int pno_repeat;
1440         int pno_freq_expo_max;
1441 #ifdef PNO_SET_DEBUG
1442         int i;
1443         char pno_in_example[] = {
1444                 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
1445                 'S', '1', '2', '0',
1446                 'S',
1447                 0x04,
1448                 'B', 'R', 'C', 'M',
1449                 'S',
1450                 0x04,
1451                 'G', 'O', 'O', 'G',
1452                 'T',
1453                 '1', 'E',
1454                 'R',
1455                 '2',
1456                 'M',
1457                 '2',
1458                 0x00
1459                 };
1460 #endif 
1461
1462         net_os_wake_lock(dev);
1463         WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
1464                 __FUNCTION__, info->cmd, info->flags,
1465                 wrqu->data.pointer, wrqu->data.length));
1466
1467         if (g_onoff == G_WLAN_SET_OFF) {
1468                 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
1469                 goto exit_proc;
1470         }
1471
1472         if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) {
1473                 WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
1474                           wrqu->data.length, (int)(strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))));
1475                 goto exit_proc;
1476         }
1477
1478 #ifdef PNO_SET_DEBUG
1479         if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) {
1480                 res = -ENOMEM;
1481                 goto exit_proc;
1482         }
1483         memcpy(extra, pno_in_example, sizeof(pno_in_example));
1484         wrqu->data.length = sizeof(pno_in_example);
1485         for (i = 0; i < wrqu->data.length; i++)
1486                 printf("%02X ", extra[i]);
1487         printf("\n");
1488 #endif 
1489
1490         str_ptr = extra;
1491 #ifdef PNO_SET_DEBUG
1492         str_ptr +=  strlen("PNOSETUP ");
1493         tlv_size_left = wrqu->data.length - strlen("PNOSETUP ");
1494 #else
1495         str_ptr +=  strlen(PNOSETUP_SET_CMD);
1496         tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
1497 #endif
1498
1499         cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
1500         memset(ssids_local, 0, sizeof(ssids_local));
1501         pno_repeat = pno_freq_expo_max = 0;
1502         
1503         if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
1504                 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
1505                 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION))
1506         {
1507                 str_ptr += sizeof(cmd_tlv_t);
1508                 tlv_size_left  -= sizeof(cmd_tlv_t);
1509
1510                 
1511                 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
1512                         MAX_PFN_LIST_COUNT,
1513                         &tlv_size_left)) <= 0) {
1514                         WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
1515                         goto exit_proc;
1516                 }
1517                 else {
1518                         if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
1519                                 WL_ERROR(("%s scan duration corrupted field size %d\n",
1520                                         __FUNCTION__, tlv_size_left));
1521                                 goto exit_proc;
1522                         }
1523                         str_ptr++;
1524                         pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
1525                         WL_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
1526
1527                         
1528                         if (str_ptr[0] != 0) {
1529                                 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
1530                                         WL_ERROR(("%s pno repeat : corrupted field\n",
1531                                                 __FUNCTION__));
1532                                         goto exit_proc;
1533                                 }
1534                                 str_ptr++;
1535                                 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
1536                                 WL_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
1537                                 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
1538                                         WL_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
1539                                                 __FUNCTION__));
1540                                         goto exit_proc;
1541                                 }
1542                                 str_ptr++;
1543                                 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
1544                                 WL_PNO(("%s: pno_freq_expo_max=%d\n",
1545                                         __FUNCTION__, pno_freq_expo_max));
1546                         }
1547                 }
1548         }
1549         else {
1550                 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
1551                 goto exit_proc;
1552         }
1553
1554         
1555         res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
1556
1557 exit_proc:
1558         net_os_wake_unlock(dev);
1559         return res;
1560 }
1561 #endif 
1562
1563 static int
1564 wl_iw_get_rssi(
1565         struct net_device *dev,
1566         struct iw_request_info *info,
1567         union iwreq_data *wrqu,
1568         char *extra
1569 )
1570 {
1571         static int rssi = 0;
1572         static wlc_ssid_t ssid = {0};
1573         int error = 0;
1574         char *p = extra;
1575         static char ssidbuf[SSID_FMT_BUF_LEN];
1576         scb_val_t scb_val;
1577
1578         net_os_wake_lock(dev);
1579
1580         bzero(&scb_val, sizeof(scb_val_t));
1581
1582         if (g_onoff == G_WLAN_SET_ON) {
1583                 error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
1584                 if (error) {
1585                         WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error));
1586                         net_os_wake_unlock(dev);
1587                         return error;
1588                 }
1589                 rssi = dtoh32(scb_val.val);
1590
1591                 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1592                 if (!error) {
1593                         ssid.SSID_len = dtoh32(ssid.SSID_len);
1594                         wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len));
1595                 }
1596         }
1597
1598         p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi);
1599         wrqu->data.length = p - extra + 1;
1600
1601         net_os_wake_unlock(dev);
1602         return error;
1603 }
1604
1605 int
1606 wl_iw_send_priv_event(
1607         struct net_device *dev,
1608         char *flag
1609 )
1610 {
1611         union iwreq_data wrqu;
1612         char extra[IW_CUSTOM_MAX + 1];
1613         int cmd;
1614
1615         cmd = IWEVCUSTOM;
1616         memset(&wrqu, 0, sizeof(wrqu));
1617         if (strlen(flag) > sizeof(extra))
1618                 return -1;
1619
1620         strcpy(extra, flag);
1621         wrqu.data.length = strlen(extra);
1622         wireless_send_event(dev, cmd, &wrqu, extra);
1623         net_os_wake_lock_timeout_enable(dev);
1624         WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
1625
1626         return 0;
1627 }
1628
1629
1630 int
1631 wl_control_wl_start(struct net_device *dev)
1632 {
1633         wl_iw_t *iw;
1634         int ret = 0;
1635
1636         WL_TRACE(("Enter %s \n", __FUNCTION__));
1637
1638         if (!dev) {
1639                 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1640                 return -1;
1641         }
1642
1643         iw = *(wl_iw_t **)netdev_priv(dev);
1644
1645         if (!iw) {
1646                 WL_ERROR(("%s: wl is null\n", __FUNCTION__));
1647                 return -1;
1648         }
1649
1650         dhd_net_if_lock(dev);
1651
1652         if (g_onoff == G_WLAN_SET_OFF) {
1653                 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
1654
1655 #if defined(BCMLXSDMMC)
1656                 sdioh_start(NULL, 0);
1657 #endif
1658
1659                 ret = dhd_dev_reset(dev, 0);
1660
1661 #if defined(BCMLXSDMMC)
1662                 sdioh_start(NULL, 1);
1663 #endif
1664
1665                 dhd_dev_init_ioctl(dev);
1666
1667                 g_onoff = G_WLAN_SET_ON;
1668         }
1669         WL_TRACE(("Exited %s\n", __FUNCTION__));
1670
1671         dhd_net_if_unlock(dev);
1672         return ret;
1673 }
1674
1675
1676 static int
1677 wl_iw_control_wl_off(
1678         struct net_device *dev,
1679         struct iw_request_info *info
1680 )
1681 {
1682         wl_iw_t *iw;
1683         int ret = 0;
1684
1685         WL_TRACE(("Enter %s\n", __FUNCTION__));
1686
1687         if (!dev) {
1688                 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1689                 return -1;
1690         }
1691
1692         iw = *(wl_iw_t **)netdev_priv(dev);
1693
1694         if (!iw) {
1695                 WL_ERROR(("%s: wl is null\n", __FUNCTION__));
1696                 return -1;
1697         }
1698
1699         dhd_net_if_lock(dev);
1700
1701 #ifdef SOFTAP
1702         ap_cfg_running = FALSE;
1703 #endif 
1704
1705         if (g_onoff == G_WLAN_SET_ON) {
1706                 g_onoff = G_WLAN_SET_OFF;
1707
1708 #if defined(WL_IW_USE_ISCAN)
1709                 g_iscan->iscan_state = ISCAN_STATE_IDLE;
1710 #endif 
1711
1712                 dhd_dev_reset(dev, 1);
1713
1714 #if defined(WL_IW_USE_ISCAN)
1715 #if !defined(CSCAN)
1716                 
1717                 wl_iw_free_ss_cache();
1718                 wl_iw_run_ss_cache_timer(0);
1719                 
1720                 g_ss_cache_ctrl.m_link_down = 1;
1721 #endif 
1722                 memset(g_scan, 0, G_SCAN_RESULTS);
1723                 g_scan_specified_ssid = 0;
1724 #if defined(CONFIG_FIRST_SCAN)
1725                 
1726                 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
1727                 g_first_counter_scans = 0;
1728 #endif 
1729 #endif 
1730
1731 #if defined(BCMLXSDMMC)
1732                 sdioh_stop(NULL);
1733 #endif
1734
1735                 net_os_set_dtim_skip(dev, 0);
1736
1737                 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1738
1739                 wl_iw_send_priv_event(dev, "STOP");
1740         }
1741
1742         dhd_net_if_unlock(dev);
1743
1744         WL_TRACE(("Exited %s\n", __FUNCTION__));
1745
1746         return ret;
1747 }
1748
1749 static int
1750 wl_iw_control_wl_on(
1751         struct net_device *dev,
1752         struct iw_request_info *info
1753 )
1754 {
1755         int ret = 0;
1756
1757         WL_TRACE(("Enter %s \n", __FUNCTION__));
1758
1759         ret = wl_control_wl_start(dev);
1760
1761         wl_iw_send_priv_event(dev, "START");
1762
1763 #ifdef SOFTAP
1764         if (!ap_fw_loaded) {
1765                 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1766         }
1767 #else
1768         wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1769 #endif
1770
1771         WL_TRACE(("Exited %s\n", __FUNCTION__));
1772
1773         return ret;
1774 }
1775
1776 #ifdef SOFTAP
1777 static struct ap_profile my_ap;
1778 static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap); 
1779 static int get_assoc_sta_list(struct net_device *dev, char *buf, int len);
1780 static int set_ap_mac_list(struct net_device *dev, void *buf);
1781
1782 #define PTYPE_STRING 0
1783 #define PTYPE_INTDEC 1   
1784 #define PTYPE_INTHEX 2
1785 #define PTYPE_STR_HEX 3  
1786
1787 static int get_parameter_from_string(
1788         char **str_ptr, const char *token, int param_type, void  *dst, int param_max_len);
1789
1790 static int
1791 hex2num(char c)
1792 {
1793         if (c >= '0' && c <= '9')
1794                 return c - '0';
1795         if (c >= 'a' && c <= 'f')
1796                 return c - 'a' + 10;
1797         if (c >= 'A' && c <= 'F')
1798                 return c - 'A' + 10;
1799         return -1;
1800 }
1801
1802
1803
1804 static int
1805 hstr_2_buf(const char *txt, u8 *buf, int len)
1806 {
1807         int i;
1808
1809         for (i = 0; i < len; i++) {
1810                 int a, b;
1811
1812                 a = hex2num(*txt++);
1813                 if (a < 0)
1814                         return -1;
1815                 b = hex2num(*txt++);
1816                 if (b < 0)
1817                         return -1;
1818                 *buf++ = (a << 4) | b;
1819         }
1820
1821         return 0;
1822 }
1823
1824
1825
1826 static int
1827 init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg)
1828 {
1829         char *str_ptr = param_str;
1830         char sub_cmd[16];
1831         int ret = 0;
1832
1833         memset(sub_cmd, 0, sizeof(sub_cmd));
1834         memset(ap_cfg, 0, sizeof(struct ap_profile));
1835
1836         
1837         if (get_parameter_from_string(&str_ptr, "ASCII_CMD=",
1838                 PTYPE_STRING, sub_cmd, SSID_LEN) != 0) {
1839          return -1;
1840         }
1841         if (strncmp(sub_cmd, "AP_CFG", 6)) {
1842            WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd));
1843                 return -1;
1844         }
1845
1846         
1847         
1848         ret = get_parameter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN);
1849
1850         ret |= get_parameter_from_string(&str_ptr, "SEC=", PTYPE_STRING,  ap_cfg->sec, SEC_LEN);
1851
1852         ret |= get_parameter_from_string(&str_ptr, "KEY=", PTYPE_STRING,  ap_cfg->key, KEY_LEN);
1853
1854         ret |= get_parameter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5);
1855
1856         
1857         get_parameter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5);
1858
1859         
1860         get_parameter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC,  &ap_cfg->max_scb, 5);
1861
1862         
1863         get_parameter_from_string(&str_ptr, "HIDDEN=",
1864                 PTYPE_INTDEC,  &ap_cfg->closednet, 5);
1865
1866         
1867         get_parameter_from_string(&str_ptr, "COUNTRY=",
1868                 PTYPE_STRING,  &ap_cfg->country_code, 3);
1869
1870         return ret;
1871 }
1872 #endif 
1873
1874
1875
1876 #ifdef SOFTAP
1877 static int
1878 iwpriv_set_ap_config(struct net_device *dev,
1879             struct iw_request_info *info,
1880             union iwreq_data *wrqu,
1881             char *ext)
1882 {
1883         int res = 0;
1884         char  *extra = NULL;
1885         struct ap_profile *ap_cfg = &my_ap;
1886
1887         WL_TRACE(("> Got IWPRIV SET_AP IOCTL: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
1888                 info->cmd, info->flags,
1889                 wrqu->data.pointer, wrqu->data.length));
1890
1891         if (!ap_fw_loaded) {
1892                 WL_ERROR(("Can't execute %s(), SOFTAP fw is not Loaded\n",
1893                         __FUNCTION__));
1894                 return -1;
1895         }
1896
1897         if (wrqu->data.length != 0) {
1898
1899                 char *str_ptr;
1900
1901                 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
1902                         return -ENOMEM;
1903
1904                 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
1905                         kfree(extra);
1906                         return -EFAULT;
1907                 }
1908
1909                 extra[wrqu->data.length] = 0;
1910                 WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra));
1911
1912                 memset(ap_cfg, 0, sizeof(struct ap_profile));
1913
1914                 
1915
1916                 str_ptr = extra;
1917
1918                 if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) {
1919                         WL_ERROR(("%s failed to parse %d\n", __FUNCTION__, res));
1920                         kfree(extra);
1921                         return -1;
1922                 }
1923
1924         } else {
1925          
1926           WL_ERROR(("IWPRIV argument len = 0 \n"));
1927           return -1;
1928         }
1929
1930         if ((res = set_ap_cfg(dev, ap_cfg)) < 0)
1931                 WL_ERROR(("%s failed to set_ap_cfg %d\n", __FUNCTION__, res));
1932
1933         kfree(extra);
1934
1935         return res;
1936 }
1937 #endif 
1938
1939
1940
1941 #ifdef SOFTAP
1942 static int iwpriv_get_assoc_list(struct net_device *dev,
1943         struct iw_request_info *info,
1944         union iwreq_data *p_iwrq,
1945         char *extra)
1946 {
1947         int i, ret = 0;
1948         char mac_buf[256];
1949         struct maclist *sta_maclist = (struct maclist *)mac_buf;
1950
1951         char mac_lst[384];
1952         char *p_mac_str;
1953         char *p_mac_str_end;
1954         wl_iw_t *iw;
1955
1956         if ((!dev) || (!extra)) {
1957                 
1958                 return -EINVAL;
1959         }
1960
1961
1962         iw = *(wl_iw_t **)netdev_priv(dev);
1963
1964         net_os_wake_lock(dev);
1965         DHD_OS_MUTEX_LOCK(&wl_softap_lock);
1966
1967         WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d,"
1968                 "iwp.len:%p, iwp.flags:%x  \n", __FUNCTION__, info->cmd, info->flags,
1969                 extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags));
1970
1971
1972         memset(sta_maclist, 0, sizeof(mac_buf));
1973
1974         sta_maclist->count = 8;
1975
1976         WL_SOFTAP(("%s: net device:%s, buf_sz:%d\n",
1977                 __FUNCTION__, dev->name, sizeof(mac_buf)));
1978
1979         if ((ret = get_assoc_sta_list(dev, mac_buf, sizeof(mac_buf))) < 0) {
1980                 WL_ERROR(("%s: sta list ioctl error:%d\n",
1981                         __FUNCTION__, ret));
1982                 goto func_exit;
1983         }
1984
1985         WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__,
1986                 sta_maclist->count));
1987
1988
1989         
1990         memset(mac_lst, 0, sizeof(mac_lst));
1991         p_mac_str = mac_lst;
1992         p_mac_str_end = &mac_lst[sizeof(mac_lst)-1];
1993
1994         for (i = 0; i < 8; i++) { 
1995                 struct ether_addr * id = &sta_maclist->ea[i];
1996                 if (!ETHER_ISNULLADDR(id->octet)) {
1997                         scb_val_t scb_val;
1998                         int rssi = 0;
1999                         bzero(&scb_val, sizeof(scb_val_t));
2000
2001                         
2002                         if ((p_mac_str_end - p_mac_str) <= 36) {
2003                                 WL_ERROR(("%s: mac list buf is < 36 for item[%i] item\n",
2004                                         __FUNCTION__, i));
2005                                 break;
2006                         }
2007
2008                         p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
2009                         "\nMac[%d]=%02X:%02X:%02X:%02X:%02X:%02X,", i,
2010                         id->octet[0], id->octet[1], id->octet[2],
2011                         id->octet[3], id->octet[4], id->octet[5]);
2012
2013                         
2014                         bcopy(id->octet, &scb_val.ea, 6);
2015                         ret = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
2016                         if (ret  < 0) {
2017                                 snprintf(p_mac_str, MAX_WX_STRING, "RSSI:ERR");
2018                                 WL_ERROR(("%s: RSSI ioctl error:%d\n",
2019                                         __FUNCTION__, ret));
2020                                 break;
2021                         }
2022
2023                         rssi = dtoh32(scb_val.val);
2024                         p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
2025                         "RSSI:%d", rssi);
2026                 }
2027         }
2028
2029         p_iwrq->data.length = strlen(mac_lst)+1; 
2030
2031         WL_SOFTAP(("%s: data to user:\n%s\n usr_ptr:%p\n", __FUNCTION__,
2032                 mac_lst, p_iwrq->data.pointer));
2033
2034         if (p_iwrq->data.length) {
2035                 bcopy(mac_lst, extra, p_iwrq->data.length);
2036         }
2037
2038 func_exit:
2039
2040         DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
2041         net_os_wake_unlock(dev);
2042
2043         WL_SOFTAP(("%s: Exited\n", __FUNCTION__));
2044         return ret;
2045 }
2046 #endif 
2047
2048
2049 #ifdef SOFTAP
2050
2051 #define MAC_FILT_MAX 8
2052 static int iwpriv_set_mac_filters(struct net_device *dev,
2053         struct iw_request_info *info,
2054         union iwreq_data *wrqu,
2055         char *ext)
2056 {
2057         int i, ret = -1;
2058         char  * extra = NULL;
2059         int mac_cnt = 0; 
2060         int mac_mode = 0;
2061         struct ether_addr *p_ea;
2062         struct mac_list_set mflist_set; 
2063
2064         WL_SOFTAP((">>> Got IWPRIV SET_MAC_FILTER IOCTL:  info->cmd:%x,"
2065                         "info->flags:%x, u.data:%p, u.len:%d\n",
2066                         info->cmd, info->flags,
2067                         wrqu->data.pointer, wrqu->data.length));
2068
2069         if (wrqu->data.length != 0) {
2070
2071                 char *str_ptr;
2072
2073                 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
2074                         return -ENOMEM;
2075
2076                 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
2077                         kfree(extra);
2078                         return -EFAULT;
2079                 }
2080
2081                 extra[wrqu->data.length] = 0;
2082                 WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra));
2083
2084                 memset(&mflist_set, 0, sizeof(mflist_set));
2085
2086                 
2087                 str_ptr = extra;
2088
2089
2090                 
2091                 if (get_parameter_from_string(&str_ptr, "MAC_MODE=",
2092                         PTYPE_INTDEC, &mac_mode, 4) != 0) {
2093                         WL_ERROR(("ERROR: 'MAC_MODE=' token is missing\n"));
2094                         goto exit_proc;
2095                 }
2096
2097                 p_ea = &mflist_set.mac_list.ea[0];
2098
2099                 if (get_parameter_from_string(&str_ptr, "MAC_CNT=",
2100                         PTYPE_INTDEC, &mac_cnt, 4) != 0) {
2101                         WL_ERROR(("ERROR: 'MAC_CNT=' token param is missing \n"));
2102                         goto exit_proc;
2103                 }
2104
2105                 if (mac_cnt > MAC_FILT_MAX) {
2106                         WL_ERROR(("ERROR: number of MAC filters > MAX\n"));
2107                         goto exit_proc;
2108                 }
2109
2110                 for (i=0; i< mac_cnt; i++)      
2111                 if (get_parameter_from_string(&str_ptr, "MAC=",
2112                         PTYPE_STR_HEX, &p_ea[i], 12) != 0) {
2113                         WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i));
2114                         goto exit_proc;
2115                 }
2116
2117                 WL_SOFTAP(("MAC_MODE=:%d, MAC_CNT=%d, MACs:..\n", mac_mode, mac_cnt));
2118                 for (i = 0; i < mac_cnt; i++) {
2119                    WL_SOFTAP(("mac_filt[%d]:", i));
2120                    dhd_print_buf(&p_ea[i], 6, 0);
2121                 }
2122
2123                 
2124                 mflist_set.mode = mac_mode;
2125                 mflist_set.mac_list.count = mac_cnt;
2126                 set_ap_mac_list(dev, &mflist_set);
2127
2128                 
2129                 wrqu->data.pointer = NULL;
2130                 wrqu->data.length = 0;
2131                 ret = 0;
2132
2133         } else {
2134          
2135           WL_ERROR(("IWPRIV argument len is 0\n"));
2136           return -1;
2137         }
2138
2139         exit_proc:
2140         kfree(extra);
2141         return ret;
2142 }
2143 #endif 
2144
2145
2146 #ifdef SOFTAP
2147
2148 static int iwpriv_set_ap_sta_disassoc(struct net_device *dev,
2149         struct iw_request_info *info,
2150         union iwreq_data *wrqu,
2151         char *ext)
2152 {
2153         int res = 0;
2154         char sta_mac[6] = {0, 0, 0, 0, 0, 0};
2155         char cmd_buf[256];
2156         char *str_ptr = cmd_buf;
2157
2158         WL_SOFTAP((">>%s called\n args: info->cmd:%x,"
2159                 " info->flags:%x, u.data.p:%p, u.data.len:%d\n",
2160                 __FUNCTION__, info->cmd, info->flags,
2161                 wrqu->data.pointer, wrqu->data.length));
2162
2163         if (wrqu->data.length != 0) {
2164
2165                 if (copy_from_user(cmd_buf, wrqu->data.pointer, wrqu->data.length)) {
2166                         return -EFAULT;
2167                 }
2168
2169                 if (get_parameter_from_string(&str_ptr,
2170                         "MAC=", PTYPE_STR_HEX, sta_mac, 12) == 0) {
2171                         res = wl_iw_softap_deassoc_stations(dev, sta_mac);
2172                 } else  {
2173                         WL_ERROR(("ERROR: STA_MAC= token not found\n"));
2174                 }
2175         }
2176
2177         return res;
2178 }
2179 #endif 
2180
2181 #endif 
2182
2183 #if WIRELESS_EXT < 13
2184 struct iw_request_info
2185 {
2186         __u16           cmd;            
2187         __u16           flags;          
2188 };
2189
2190 typedef int (*iw_handler)(struct net_device *dev,
2191                 struct iw_request_info *info,
2192                 void *wrqu,
2193                 char *extra);
2194 #endif 
2195
2196 static int
2197 wl_iw_config_commit(
2198         struct net_device *dev,
2199         struct iw_request_info *info,
2200         void *zwrq,
2201         char *extra
2202 )
2203 {
2204         wlc_ssid_t ssid;
2205         int error;
2206         struct sockaddr bssid;
2207
2208         WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
2209
2210         if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
2211                 return error;
2212
2213         ssid.SSID_len = dtoh32(ssid.SSID_len);
2214
2215         if (!ssid.SSID_len)
2216                 return 0;
2217
2218         bzero(&bssid, sizeof(struct sockaddr));
2219         if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
2220                 WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __FUNCTION__, ssid.SSID));
2221                 return error;
2222         }
2223
2224         return 0;
2225 }
2226
2227 static int
2228 wl_iw_get_name(
2229         struct net_device *dev,
2230         struct iw_request_info *info,
2231         char *cwrq,
2232         char *extra
2233 )
2234 {
2235         WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
2236
2237         strcpy(cwrq, "IEEE 802.11-DS");
2238
2239         return 0;
2240 }
2241
2242 static int
2243 wl_iw_set_freq(
2244         struct net_device *dev,
2245         struct iw_request_info *info,
2246         struct iw_freq *fwrq,
2247         char *extra
2248 )
2249 {
2250         int error, chan;
2251         uint sf = 0;
2252
2253         WL_TRACE(("%s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name));
2254
2255 #if defined(SOFTAP)
2256         if (ap_cfg_running) {
2257                 WL_TRACE(("%s:>> not executed, 'SOFT_AP is active' \n", __FUNCTION__));
2258                 return 0;
2259         }
2260 #endif
2261
2262         
2263         if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
2264                 chan = fwrq->m;
2265         }
2266         
2267         else {
2268                 
2269                 if (fwrq->e >= 6) {
2270                         fwrq->e -= 6;
2271                         while (fwrq->e--)
2272                                 fwrq->m *= 10;
2273                 } else if (fwrq->e < 6) {
2274                         while (fwrq->e++ < 6)
2275                                 fwrq->m /= 10;
2276                 }
2277                 
2278                 if (fwrq->m > 4000 && fwrq->m < 5000)
2279                         sf = WF_CHAN_FACTOR_4_G; 
2280
2281                 chan = wf_mhz2channel(fwrq->m, sf);
2282         }
2283
2284         chan = htod32(chan);
2285
2286         if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
2287                 return error;
2288
2289         g_wl_iw_params.target_channel = chan;
2290
2291         
2292         return -EINPROGRESS;
2293 }
2294
2295 static int
2296 wl_iw_get_freq(
2297         struct net_device *dev,
2298         struct iw_request_info *info,
2299         struct iw_freq *fwrq,
2300         char *extra
2301 )
2302 {
2303         channel_info_t ci;
2304         int error;
2305
2306         WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
2307
2308         if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
2309                 return error;
2310
2311         
2312         fwrq->m = dtoh32(ci.hw_channel);
2313         fwrq->e = dtoh32(0);
2314         return 0;
2315 }
2316
2317 static int
2318 wl_iw_set_mode(
2319         struct net_device *dev,
2320         struct iw_request_info *info,
2321         __u32 *uwrq,
2322         char *extra
2323 )
2324 {
2325         int infra = 0, ap = 0, error = 0;
2326
2327         WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
2328
2329         switch (*uwrq) {
2330         case IW_MODE_MASTER:
2331                 infra = ap = 1;
2332                 break;
2333         case IW_MODE_ADHOC:
2334         case IW_MODE_AUTO:
2335                 break;
2336         case IW_MODE_INFRA:
2337                 infra = 1;
2338                 break;
2339         default:
2340                 return -EINVAL;
2341         }
2342         infra = htod32(infra);
2343         ap = htod32(ap);
2344
2345         if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
2346             (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
2347                 return error;
2348
2349         
2350         return -EINPROGRESS;
2351 }
2352
2353 static int
2354 wl_iw_get_mode(
2355         struct net_device *dev,
2356         struct iw_request_info *info,
2357         __u32 *uwrq,
2358         char *extra
2359 )
2360 {
2361         int error, infra = 0, ap = 0;
2362
2363         WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
2364
2365         if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
2366             (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
2367                 return error;
2368
2369         infra = dtoh32(infra);
2370         ap = dtoh32(ap);
2371         *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
2372
2373         return 0;
2374 }
2375
2376 static int
2377 wl_iw_get_range(
2378         struct net_device *dev,
2379         struct iw_request_info *info,
2380         struct iw_point *dwrq,
2381         char *extra
2382 )
2383 {
2384         struct iw_range *range = (struct iw_range *) extra;
2385         wl_uint32_list_t *list;
2386         wl_rateset_t rateset;
2387         int8 *channels;
2388         int error, i, k;
2389         uint sf, ch;
2390
2391         int phytype;
2392         int bw_cap = 0, sgi_tx = 0, nmode = 0;
2393         channel_info_t ci;
2394         uint8 nrate_list2copy = 0;
2395         uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
2396                 {14, 29, 43, 58, 87, 116, 130, 144},
2397                 {27, 54, 81, 108, 162, 216, 243, 270},
2398                 {30, 60, 90, 120, 180, 240, 270, 300}};
2399
2400         WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
2401
2402         if (!extra)
2403                 return -EINVAL;
2404
2405         channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL);
2406         if (!channels) {
2407                 WL_ERROR(("Could not alloc channels\n"));
2408                 return -ENOMEM;
2409         }
2410         list = (wl_uint32_list_t *)channels;
2411
2412         dwrq->length = sizeof(struct iw_range);
2413         memset(range, 0, sizeof(range));
2414
2415         
2416         range->min_nwid = range->max_nwid = 0;
2417
2418         
2419         list->count = htod32(MAXCHANNEL);
2420         if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) {
2421                 kfree(channels);
2422                 return error;
2423         }
2424         for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
2425                 range->freq[i].i = dtoh32(list->element[i]);
2426
2427                 ch = dtoh32(list->element[i]);
2428                 if (ch <= CH_MAX_2G_CHANNEL)
2429                         sf = WF_CHAN_FACTOR_2_4_G;
2430                 else
2431                         sf = WF_CHAN_FACTOR_5_G;
2432
2433                 range->freq[i].m = wf_channel2mhz(ch, sf);
2434                 range->freq[i].e = 6;
2435         }
2436         range->num_frequency = range->num_channels = i;
2437
2438         
2439         range->max_qual.qual = 5;
2440         
2441         range->max_qual.level = 0x100 - 200;    
2442         
2443         range->max_qual.noise = 0x100 - 200;    
2444         
2445         range->sensitivity = 65535;
2446
2447 #if WIRELESS_EXT > 11
2448         
2449         range->avg_qual.qual = 3;
2450         
2451         range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
2452         
2453         range->avg_qual.noise = 0x100 - 75;     
2454 #endif 
2455
2456         
2457         if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) {
2458                 kfree(channels);
2459                 return error;
2460         }
2461         rateset.count = dtoh32(rateset.count);
2462         range->num_bitrates = rateset.count;
2463         for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
2464                 range->bitrate[i] = (rateset.rates[i]& 0x7f) * 500000; 
2465         dev_wlc_intvar_get(dev, "nmode", &nmode);
2466         dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
2467
2468         if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
2469                 dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
2470                 dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
2471                 dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t));
2472                 ci.hw_channel = dtoh32(ci.hw_channel);
2473
2474                 if (bw_cap == 0 ||
2475                         (bw_cap == 2 && ci.hw_channel <= 14)) {
2476                         if (sgi_tx == 0)
2477                                 nrate_list2copy = 0;
2478                         else
2479                                 nrate_list2copy = 1;
2480                 }
2481                 if (bw_cap == 1 ||
2482                         (bw_cap == 2 && ci.hw_channel >= 36)) {
2483                         if (sgi_tx == 0)
2484                                 nrate_list2copy = 2;
2485                         else
2486                                 nrate_list2copy = 3;
2487                 }
2488                 range->num_bitrates += 8;
2489                 for (k = 0; i < range->num_bitrates; k++, i++) {
2490                         
2491                         range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000;
2492                 }
2493         }
2494
2495         
2496         if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) {
2497                 kfree(channels);
2498                 return error;
2499         }
2500         i = dtoh32(i);
2501         if (i == WLC_PHY_TYPE_A)
2502                 range->throughput = 24000000;   
2503         else
2504                 range->throughput = 1500000;    
2505
2506         
2507         range->min_rts = 0;
2508         range->max_rts = 2347;
2509         range->min_frag = 256;
2510         range->max_frag = 2346;
2511
2512         range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
2513         range->num_encoding_sizes = 4;
2514         range->encoding_size[0] = WEP1_KEY_SIZE;
2515         range->encoding_size[1] = WEP128_KEY_SIZE;
2516 #if WIRELESS_EXT > 17
2517         range->encoding_size[2] = TKIP_KEY_SIZE;
2518 #else
2519         range->encoding_size[2] = 0;
2520 #endif
2521         range->encoding_size[3] = AES_KEY_SIZE;
2522
2523         
2524         range->min_pmp = 0;
2525         range->max_pmp = 0;
2526         range->min_pmt = 0;
2527         range->max_pmt = 0;
2528         range->pmp_flags = 0;
2529         range->pm_capa = 0;
2530
2531         
2532         range->num_txpower = 2;
2533         range->txpower[0] = 1;
2534         range->txpower[1] = 255;
2535         range->txpower_capa = IW_TXPOW_MWATT;
2536
2537 #if WIRELESS_EXT > 10
2538         range->we_version_compiled = WIRELESS_EXT;
2539         range->we_version_source = 19;
2540
2541         
2542         range->retry_capa = IW_RETRY_LIMIT;
2543         range->retry_flags = IW_RETRY_LIMIT;
2544         range->r_time_flags = 0;
2545         
2546         range->min_retry = 1;
2547         range->max_retry = 255;
2548         
2549         range->min_r_time = 0;
2550         range->max_r_time = 0;
2551 #endif 
2552
2553 #if WIRELESS_EXT > 17
2554         range->enc_capa = IW_ENC_CAPA_WPA;
2555         range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
2556         range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
2557         range->enc_capa |= IW_ENC_CAPA_WPA2;
2558
2559         
2560         IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
2561         
2562         IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
2563         IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
2564         IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
2565         IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
2566         IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
2567 #endif 
2568
2569         kfree(channels);
2570
2571         return 0;
2572 }
2573
2574 static int
2575 rssi_to_qual(int rssi)
2576 {
2577         if (rssi <= WL_IW_RSSI_NO_SIGNAL)
2578                 return 0;
2579         else if (rssi <= WL_IW_RSSI_VERY_LOW)
2580                 return 1;
2581         else if (rssi <= WL_IW_RSSI_LOW)
2582                 return 2;
2583         else if (rssi <= WL_IW_RSSI_GOOD)
2584                 return 3;
2585         else if (rssi <= WL_IW_RSSI_VERY_GOOD)
2586                 return 4;
2587         else
2588                 return 5;
2589 }
2590
2591 static int
2592 wl_iw_set_spy(
2593         struct net_device *dev,
2594         struct iw_request_info *info,
2595         struct iw_point *dwrq,
2596         char *extra
2597 )
2598 {
2599         wl_iw_t *iw = NETDEV_PRIV(dev);
2600         struct sockaddr *addr = (struct sockaddr *) extra;
2601         int i;
2602
2603         WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
2604
2605         if (!extra)
2606                 return -EINVAL;
2607
2608         iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
2609         for (i = 0; i < iw->spy_num; i++)
2610                 memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
2611         memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
2612
2613         return 0;
2614 }
2615
2616 static int
2617 wl_iw_get_spy(
2618         struct net_device *dev,
2619         struct iw_request_info *info,
2620         struct iw_point *dwrq,
2621         char *extra
2622 )
2623 {
2624         wl_iw_t *iw = NETDEV_PRIV(dev);
2625         struct sockaddr *addr = (struct sockaddr *) extra;
2626         struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
2627         int i;
2628
2629         WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
2630
2631         if (!extra)
2632                 return -EINVAL;
2633
2634         dwrq->length = iw->spy_num;
2635         for (i = 0; i < iw->spy_num; i++) {
2636                 memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
2637                 addr[i].sa_family = AF_UNIX;
2638                 memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
2639                 iw->spy_qual[i].updated = 0;
2640         }
2641
2642         return 0;
2643 }
2644
2645
2646 static int
2647 wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size)
2648 {
2649         chanspec_t chanspec = 0;
2650
2651         if (ch != 0) {
2652                 
2653                 join_params->params.chanspec_num = 1;
2654                 join_params->params.chanspec_list[0] = ch;
2655
2656                 if (join_params->params.chanspec_list[0])
2657                         chanspec |= WL_CHANSPEC_BAND_2G;
2658                 else
2659                         chanspec |= WL_CHANSPEC_BAND_5G;
2660
2661                 chanspec |= WL_CHANSPEC_BW_20;
2662                 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
2663
2664                 
2665                 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
2666                         join_params->params.chanspec_num * sizeof(chanspec_t);
2667
2668                 
2669                 join_params->params.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
2670                 join_params->params.chanspec_list[0] |= chanspec;
2671                 join_params->params.chanspec_list[0] =
2672                         htodchanspec(join_params->params.chanspec_list[0]);
2673
2674                 join_params->params.chanspec_num = htod32(join_params->params.chanspec_num);
2675
2676                 WL_TRACE(("%s  join_params->params.chanspec_list[0]= %X\n",
2677                         __FUNCTION__, join_params->params.chanspec_list[0]));
2678         }
2679         return 1;
2680 }
2681
2682 static int
2683 wl_iw_set_wap(
2684         struct net_device *dev,
2685         struct iw_request_info *info,
2686         struct sockaddr *awrq,
2687         char *extra
2688 )
2689 {
2690         int error = -EINVAL;
2691         wl_join_params_t join_params;
2692         int join_params_size;
2693
2694         WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
2695
2696         if (awrq->sa_family != ARPHRD_ETHER) {
2697                 WL_ERROR(("Invalid Header...sa_family\n"));
2698                 return -EINVAL;
2699         }
2700
2701         
2702         if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
2703                 scb_val_t scbval;
2704                 
2705                 bzero(&scbval, sizeof(scb_val_t));
2706                 
2707                 (void) dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2708                 return 0;
2709         }
2710
2711
2712         
2713         memset(&join_params, 0, sizeof(join_params));
2714         join_params_size = sizeof(join_params.ssid);
2715
2716         memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
2717         join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
2718         memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN);
2719
2720         
2721         
2722         WL_TRACE(("%s  target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel));
2723         wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
2724
2725         if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
2726                 WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error));
2727                 return error;
2728         }
2729
2730         if (g_ssid.SSID_len) {
2731                 WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__,
2732                         g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data),
2733                         g_wl_iw_params.target_channel));
2734         }
2735
2736         
2737         memset(&g_ssid, 0, sizeof(g_ssid));
2738         return 0;
2739 }
2740
2741 static int
2742 wl_iw_get_wap(
2743         struct net_device *dev,
2744         struct iw_request_info *info,
2745         struct sockaddr *awrq,
2746         char *extra
2747 )
2748 {
2749         WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
2750
2751         awrq->sa_family = ARPHRD_ETHER;
2752         memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
2753
2754         
2755         (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
2756
2757         return 0;
2758 }
2759
2760 #if WIRELESS_EXT > 17
2761 static int
2762 wl_iw_mlme(
2763         struct net_device *dev,
2764         struct iw_request_info *info,
2765         struct sockaddr *awrq,
2766         char *extra
2767 )
2768 {
2769         struct iw_mlme *mlme;
2770         scb_val_t scbval;
2771         int error  = -EINVAL;
2772
2773         WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name));
2774
2775         mlme = (struct iw_mlme *)extra;
2776         if (mlme == NULL) {
2777                 WL_ERROR(("Invalid ioctl data.\n"));
2778                 return error;
2779         }
2780
2781         scbval.val = mlme->reason_code;
2782         bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
2783
2784         if (mlme->cmd == IW_MLME_DISASSOC) {
2785                 scbval.val = htod32(scbval.val);
2786                 error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2787         }
2788         else if (mlme->cmd == IW_MLME_DEAUTH) {
2789                 scbval.val = htod32(scbval.val);
2790                 error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
2791                         sizeof(scb_val_t));
2792         }
2793         else {
2794                 WL_ERROR(("Invalid ioctl data.\n"));
2795                 return error;
2796         }
2797
2798         return error;
2799 }
2800 #endif 
2801
2802 #ifndef WL_IW_USE_ISCAN
2803 static int
2804 wl_iw_get_aplist(
2805         struct net_device *dev,
2806         struct iw_request_info *info,
2807         struct iw_point *dwrq,
2808         char *extra
2809 )
2810 {
2811         wl_scan_results_t *list;
2812         struct sockaddr *addr = (struct sockaddr *) extra;
2813         struct iw_quality qual[IW_MAX_AP];
2814         wl_bss_info_t *bi = NULL;
2815         int error, i;
2816         uint buflen = dwrq->length;
2817
2818         WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2819
2820         if (!extra)
2821                 return -EINVAL;
2822
2823         
2824         list = kmalloc(buflen, GFP_KERNEL);
2825         if (!list)
2826                 return -ENOMEM;
2827         memset(list, 0, buflen);
2828         list->buflen = htod32(buflen);
2829         if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
2830                 WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
2831                 kfree(list);
2832                 return error;
2833         }
2834         list->buflen = dtoh32(list->buflen);
2835         list->version = dtoh32(list->version);
2836         list->count = dtoh32(list->count);
2837         if (list->version != WL_BSS_INFO_VERSION) {
2838                 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
2839                           __FUNCTION__, list->version));
2840                 kfree(list);
2841                 return -EINVAL;
2842         }
2843
2844         for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
2845                 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
2846                 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
2847                         buflen));
2848
2849                 
2850                 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
2851                         continue;
2852
2853                 
2854                 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
2855                 addr[dwrq->length].sa_family = ARPHRD_ETHER;
2856                 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
2857                 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
2858                 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
2859
2860                 
2861 #if WIRELESS_EXT > 18
2862                 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
2863 #else
2864                 qual[dwrq->length].updated = 7;
2865 #endif 
2866
2867                 dwrq->length++;
2868         }
2869
2870         kfree(list);
2871
2872         if (dwrq->length) {
2873                 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
2874                 
2875                 dwrq->flags = 1;
2876         }
2877
2878         return 0;
2879 }
2880 #endif 
2881
2882 #ifdef WL_IW_USE_ISCAN
2883 static int
2884 wl_iw_iscan_get_aplist(
2885         struct net_device *dev,
2886         struct iw_request_info *info,
2887         struct iw_point *dwrq,
2888         char *extra
2889 )
2890 {
2891         wl_scan_results_t *list;
2892         iscan_buf_t * buf;
2893         iscan_info_t *iscan = g_iscan;
2894
2895         struct sockaddr *addr = (struct sockaddr *) extra;
2896         struct iw_quality qual[IW_MAX_AP];
2897         wl_bss_info_t *bi = NULL;
2898         int i;
2899
2900         WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2901
2902         if (!extra)
2903                 return -EINVAL;
2904
2905         if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
2906                 WL_ERROR(("%s error\n", __FUNCTION__));
2907                 return 0;
2908         }
2909
2910         buf = iscan->list_hdr;
2911         
2912         while (buf) {
2913                 list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
2914                 if (list->version != WL_BSS_INFO_VERSION) {
2915                         WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
2916                                 __FUNCTION__, list->version));
2917                         return -EINVAL;
2918                 }
2919
2920                 bi = NULL;
2921                 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
2922                         bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
2923                                   : list->bss_info;
2924                         ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
2925                                 WLC_IW_ISCAN_MAXLEN));
2926
2927                         
2928                         if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
2929                                 continue;
2930
2931                         
2932                         memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
2933                         addr[dwrq->length].sa_family = ARPHRD_ETHER;
2934                         qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
2935                         qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
2936                         qual[dwrq->length].noise = 0x100 + bi->phy_noise;
2937
2938                         
2939 #if WIRELESS_EXT > 18
2940                         qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
2941 #else
2942                         qual[dwrq->length].updated = 7;
2943 #endif 
2944
2945                         dwrq->length++;
2946                 }
2947                 buf = buf->next;
2948         }
2949         if (dwrq->length) {
2950                 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
2951                 
2952                 dwrq->flags = 1;
2953         }
2954
2955         return 0;
2956 }
2957
2958 static int
2959 wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
2960 {
2961         int err = 0;
2962
2963         memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
2964         params->bss_type = DOT11_BSSTYPE_ANY;
2965         params->scan_type = 0;
2966         params->nprobes = -1;
2967         params->active_time = -1;
2968         params->passive_time = -1;
2969         params->home_time = -1;
2970         params->channel_num = 0;
2971
2972 #if defined(CONFIG_FIRST_SCAN)
2973         
2974         if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
2975                 params->passive_time = 30;
2976 #endif 
2977         params->nprobes = htod32(params->nprobes);
2978         params->active_time = htod32(params->active_time);
2979         params->passive_time = htod32(params->passive_time);
2980         params->home_time = htod32(params->home_time);
2981         if (ssid && ssid->SSID_len)
2982                 memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
2983
2984         return err;
2985 }
2986
2987 static int
2988 wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
2989 {
2990         int err = 0;
2991
2992         iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
2993         iscan->iscan_ex_params_p->action = htod16(action);
2994         iscan->iscan_ex_params_p->scan_duration = htod16(0);
2995
2996         WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes));
2997         WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
2998         WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
2999         WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
3000         WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
3001         WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
3002
3003         if ((dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p,
3004                 iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
3005                         WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
3006                         err = -1;
3007         }
3008
3009         return err;
3010 }
3011
3012 static void
3013 wl_iw_timerfunc(ulong data)
3014 {
3015         iscan_info_t *iscan = (iscan_info_t *)data;
3016         if (iscan) {
3017                 iscan->timer_on = 0;
3018                 if (iscan->iscan_state != ISCAN_STATE_IDLE) {
3019                         WL_TRACE(("timer trigger\n"));
3020                         up(&iscan->tsk_ctl.sema);
3021                 }
3022         }
3023 }
3024
3025 static void
3026 wl_iw_set_event_mask(struct net_device *dev)
3027 {
3028         char eventmask[WL_EVENTING_MASK_LEN];
3029         char iovbuf[WL_EVENTING_MASK_LEN + 12]; 
3030
3031         dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
3032         bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
3033         setbit(eventmask, WLC_E_SCAN_COMPLETE);
3034         dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
3035                 iovbuf, sizeof(iovbuf));
3036 }
3037
3038 static uint32
3039 wl_iw_iscan_get(iscan_info_t *iscan)
3040 {
3041         iscan_buf_t * buf;
3042         iscan_buf_t * ptr;
3043         wl_iscan_results_t * list_buf;
3044         wl_iscan_results_t list;
3045         wl_scan_results_t *results;
3046         uint32 status;
3047         int res = 0;
3048
3049         DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3050         if (iscan->list_cur) {
3051                 buf = iscan->list_cur;
3052                 iscan->list_cur = buf->next;
3053         }
3054         else {
3055                 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
3056                 if (!buf) {
3057                         WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n",
3058                                   __FUNCTION__));
3059                         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3060                         return WL_SCAN_RESULTS_NO_MEM;
3061                 }
3062                 buf->next = NULL;
3063                 if (!iscan->list_hdr)
3064                         iscan->list_hdr = buf;
3065                 else {
3066                         ptr = iscan->list_hdr;
3067                         while (ptr->next) {
3068                                 ptr = ptr->next;
3069                         }
3070                         ptr->next = buf;
3071                 }
3072         }
3073         memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
3074         list_buf = (wl_iscan_results_t*)buf->iscan_buf;
3075         results = &list_buf->results;
3076         results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
3077         results->version = 0;
3078         results->count = 0;
3079
3080         memset(&list, 0, sizeof(list));
3081         list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
3082         res = dev_iw_iovar_getbuf(
3083                 iscan->dev,
3084                 "iscanresults",
3085                 &list,
3086                 WL_ISCAN_RESULTS_FIXED_SIZE,
3087                 buf->iscan_buf,
3088                 WLC_IW_ISCAN_MAXLEN);
3089         if (res == 0) {
3090                 results->buflen = dtoh32(results->buflen);
3091                 results->version = dtoh32(results->version);
3092                 results->count = dtoh32(results->count);
3093                 WL_TRACE(("results->count = %d\n", results->count));
3094                 WL_TRACE(("results->buflen = %d\n", results->buflen));
3095                 status = dtoh32(list_buf->status);
3096         } else {
3097                 WL_ERROR(("%s returns error %d\n", __FUNCTION__, res));
3098                 
3099                 status = WL_SCAN_RESULTS_NO_MEM;
3100         }
3101         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3102         return status;
3103 }
3104
3105 static void
3106 wl_iw_force_specific_scan(iscan_info_t *iscan)
3107 {
3108         WL_TRACE(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID));
3109 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3110         rtnl_lock();
3111 #endif
3112
3113         (void) dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid));
3114
3115 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3116         rtnl_unlock();
3117 #endif
3118 }
3119
3120 static void
3121 wl_iw_send_scan_complete(iscan_info_t *iscan)
3122 {
3123         union iwreq_data wrqu;
3124
3125         memset(&wrqu, 0, sizeof(wrqu));
3126
3127         
3128         wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
3129 #if defined(CONFIG_FIRST_SCAN)
3130                 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
3131                         g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY;
3132 #endif 
3133                 WL_TRACE(("Send Event ISCAN complete\n"));
3134 }
3135
3136 static int
3137 _iscan_sysioc_thread(void *data)
3138 {
3139         uint32 status;
3140
3141         tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
3142         iscan_info_t *iscan = (iscan_info_t *) tsk_ctl->parent;
3143
3144
3145         static bool iscan_pass_abort = FALSE;
3146
3147         DAEMONIZE("iscan_sysioc");
3148
3149         status = WL_SCAN_RESULTS_PARTIAL;
3150
3151         
3152         complete(&tsk_ctl->completed);
3153
3154         while (down_interruptible(&tsk_ctl->sema) == 0) {
3155
3156                 SMP_RD_BARRIER_DEPENDS();
3157                 if (tsk_ctl->terminated) {
3158                         break;
3159                 }
3160 #if defined(SOFTAP)
3161                 
3162                 if (ap_cfg_running) {
3163                  WL_TRACE(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__));
3164                  net_os_wake_unlock(iscan->dev);
3165                  continue;
3166                 }
3167 #endif 
3168
3169                 if (iscan->timer_on) {
3170                         
3171                         iscan->timer_on = 0;
3172                         del_timer_sync(&iscan->timer);
3173                 }
3174
3175 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3176                 rtnl_lock();
3177 #endif
3178                 status = wl_iw_iscan_get(iscan);
3179 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3180                 rtnl_unlock();
3181 #endif
3182
3183         if  (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) {
3184                 WL_TRACE(("%s Get results from specific scan status=%d\n", __FUNCTION__, status));
3185                         wl_iw_send_scan_complete(iscan);
3186                         iscan_pass_abort = FALSE;
3187                         status  = -1;
3188                 }
3189
3190                 switch (status) {
3191                         case WL_SCAN_RESULTS_PARTIAL:
3192                                 WL_TRACE(("iscanresults incomplete\n"));
3193 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3194                                 rtnl_lock();
3195 #endif
3196                                 
3197                                 wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
3198 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3199                                 rtnl_unlock();
3200 #endif
3201                                 
3202                                 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3203                                 iscan->timer_on = 1;
3204                                 break;
3205                         case WL_SCAN_RESULTS_SUCCESS:
3206                                 WL_TRACE(("iscanresults complete\n"));
3207                                 iscan->iscan_state = ISCAN_STATE_IDLE;
3208                                 wl_iw_send_scan_complete(iscan);
3209                                 break;
3210                         case WL_SCAN_RESULTS_PENDING:
3211                                 WL_TRACE(("iscanresults pending\n"));
3212                                 
3213                                 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3214                                 iscan->timer_on = 1;
3215                                 break;
3216                         case WL_SCAN_RESULTS_ABORTED:
3217                                 WL_TRACE(("iscanresults aborted\n"));
3218                                 iscan->iscan_state = ISCAN_STATE_IDLE;
3219                                 if (g_scan_specified_ssid == 0)
3220                                         wl_iw_send_scan_complete(iscan);
3221                                 else {
3222                                         iscan_pass_abort = TRUE;
3223                                         wl_iw_force_specific_scan(iscan);
3224                                 }
3225                                 break;
3226                         case WL_SCAN_RESULTS_NO_MEM:
3227                                 WL_TRACE(("iscanresults can't alloc memory: skip\n"));
3228                                 iscan->iscan_state = ISCAN_STATE_IDLE;
3229                                 break;
3230                         default:
3231                                 WL_TRACE(("iscanresults returned unknown status %d\n", status));
3232                                 break;
3233                  }
3234
3235                 net_os_wake_unlock(iscan->dev);
3236         }
3237
3238         if (iscan->timer_on) {
3239                 iscan->timer_on = 0;
3240                 del_timer_sync(&iscan->timer);
3241         }
3242         complete_and_exit(&tsk_ctl->completed, 0);
3243 }
3244 #endif 
3245
3246 #if !defined(CSCAN)
3247
3248 static void
3249 wl_iw_set_ss_cache_timer_flag(void)
3250 {
3251         g_ss_cache_ctrl.m_timer_expired = 1;
3252         WL_TRACE(("%s called\n", __FUNCTION__));
3253 }
3254
3255
3256 static int
3257 wl_iw_init_ss_cache_ctrl(void)
3258 {
3259         WL_TRACE(("%s :\n", __FUNCTION__));
3260         g_ss_cache_ctrl.m_prev_scan_mode = 0;
3261         g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
3262         g_ss_cache_ctrl.m_cache_head = NULL;
3263         g_ss_cache_ctrl.m_link_down = 0;
3264         g_ss_cache_ctrl.m_timer_expired = 0;
3265         memset(g_ss_cache_ctrl.m_active_bssid, 0, ETHER_ADDR_LEN);
3266
3267         g_ss_cache_ctrl.m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
3268         if (!g_ss_cache_ctrl.m_timer) {
3269                 return -ENOMEM;
3270         }
3271         g_ss_cache_ctrl.m_timer->function = (void *)wl_iw_set_ss_cache_timer_flag;
3272         init_timer(g_ss_cache_ctrl.m_timer);
3273
3274         return 0;
3275 }
3276
3277
3278
3279 static void
3280 wl_iw_free_ss_cache(void)
3281 {
3282         wl_iw_ss_cache_t *node, *cur;
3283         wl_iw_ss_cache_t **spec_scan_head;
3284
3285         WL_TRACE(("%s called\n", __FUNCTION__));
3286
3287         DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3288         spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3289         node = *spec_scan_head;
3290
3291         for (;node;) {
3292                 WL_TRACE(("%s : SSID - %s\n", __FUNCTION__, node->bss_info->SSID));
3293                 cur = node;
3294                 node = cur->next;
3295                 kfree(cur);
3296         }
3297         *spec_scan_head = NULL;
3298         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3299 }
3300
3301
3302
3303 static int
3304 wl_iw_run_ss_cache_timer(int kick_off)
3305 {
3306         struct timer_list **timer;
3307
3308         timer = &g_ss_cache_ctrl.m_timer;
3309
3310         if (*timer) {
3311                 if (kick_off) {
3312 #ifdef CONFIG_PRESCANNED
3313                         (*timer)->expires = jiffies + 70000 * HZ / 1000;
3314 #else
3315                         (*timer)->expires = jiffies + 30000 * HZ / 1000;        
3316 #endif
3317                         add_timer(*timer);
3318                         WL_TRACE(("%s : timer starts \n", __FUNCTION__));
3319                 } else {
3320                         del_timer_sync(*timer);
3321                         WL_TRACE(("%s : timer stops \n", __FUNCTION__));
3322                 }
3323         }
3324
3325         return 0;
3326 }
3327
3328
3329 static void
3330 wl_iw_release_ss_cache_ctrl(void)
3331 {
3332         WL_TRACE(("%s :\n", __FUNCTION__));
3333         wl_iw_free_ss_cache();
3334         wl_iw_run_ss_cache_timer(0);
3335         if (g_ss_cache_ctrl.m_timer) {
3336                 kfree(g_ss_cache_ctrl.m_timer);
3337         }
3338 }
3339
3340
3341
3342 static void
3343 wl_iw_reset_ss_cache(void)
3344 {
3345         wl_iw_ss_cache_t *node, *prev, *cur;
3346         wl_iw_ss_cache_t **spec_scan_head;
3347
3348         DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3349         spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3350         node = *spec_scan_head;
3351         prev = node;
3352
3353         for (;node;) {
3354                 WL_TRACE(("%s : node SSID %s \n", __FUNCTION__, node->bss_info->SSID));
3355                 if (!node->dirty) {
3356                         cur = node;
3357                         if (cur == *spec_scan_head) {
3358                                 *spec_scan_head = cur->next;
3359                                 prev = *spec_scan_head;
3360                         }
3361                         else {
3362                                 prev->next = cur->next;
3363                         }
3364                         node = cur->next;
3365
3366                         WL_TRACE(("%s : Del node : SSID %s\n", __FUNCTION__, cur->bss_info->SSID));
3367                         kfree(cur);
3368                         continue;
3369                 }
3370
3371                 node->dirty = 0;
3372                 prev = node;
3373                 node = node->next;
3374         }
3375         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3376 }
3377
3378
3379 static int
3380 wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list)
3381 {
3382
3383         wl_iw_ss_cache_t *node, *prev, *leaf;
3384         wl_iw_ss_cache_t **spec_scan_head;
3385         wl_bss_info_t *bi = NULL;
3386         int i;
3387
3388         
3389         if (!ss_list->count) {
3390                 return 0;
3391         }
3392
3393         DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3394         spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3395
3396         for (i = 0; i < ss_list->count; i++) {
3397
3398                 node = *spec_scan_head;
3399                 prev = node;
3400
3401                 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3402
3403                 WL_TRACE(("%s : find %d with specific SSID %s\n", __FUNCTION__, i, bi->SSID));
3404                 for (;node;) {
3405                         if (!memcmp(&node->bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3406                                 
3407                                 WL_TRACE(("dirty marked : SSID %s\n", bi->SSID));
3408                                 node->dirty = 1;
3409                                 break;
3410                         }
3411                         prev = node;
3412                         node = node->next;
3413                 }
3414
3415                 if (node) {
3416                         continue;
3417                 }
3418
3419                 leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
3420                 if (!leaf) {
3421                         WL_ERROR(("Memory alloc failure %d\n",
3422                                 bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
3423                         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3424                         return -ENOMEM;
3425                 }
3426
3427                 memcpy(leaf->bss_info, bi, bi->length);
3428                 leaf->next = NULL;
3429                 leaf->dirty = 1;
3430                 leaf->count = 1;
3431                 leaf->version = ss_list->version;
3432
3433                 if (!prev) {
3434                         *spec_scan_head = leaf;
3435                 }
3436                 else {
3437                         prev->next = leaf;
3438                 }
3439         }
3440         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3441         return 0;
3442 }
3443
3444
3445 static int
3446 wl_iw_merge_scan_cache(struct iw_request_info *info, char *extra, uint buflen_from_user,
3447 __u16 *merged_len)
3448 {
3449         wl_iw_ss_cache_t *node;
3450         wl_scan_results_t *list_merge;
3451
3452         DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3453         node = g_ss_cache_ctrl.m_cache_head;
3454         for (;node;) {
3455                 list_merge = (wl_scan_results_t *)&node->buflen;
3456                 WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count));
3457                 if (buflen_from_user - *merged_len > 0) {
3458                         *merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info,
3459                                 extra + *merged_len, buflen_from_user - *merged_len);
3460                 }
3461                 else {
3462                         WL_TRACE(("%s: exit with break\n", __FUNCTION__));
3463                         break;
3464                 }
3465                 node = node->next;
3466         }
3467         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3468         return 0;
3469 }
3470
3471
3472 static int
3473 wl_iw_delete_bss_from_ss_cache(void *addr)
3474 {
3475
3476         wl_iw_ss_cache_t *node, *prev;
3477         wl_iw_ss_cache_t **spec_scan_head;
3478
3479         DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3480         spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3481         node = *spec_scan_head;
3482         prev = node;
3483         for (;node;) {
3484                 if (!memcmp(&node->bss_info->BSSID, addr, ETHER_ADDR_LEN)) {
3485                         if (node == *spec_scan_head) {
3486                                 *spec_scan_head = node->next;
3487                         }
3488                         else {
3489                                 prev->next = node->next;
3490                         }
3491
3492                         WL_TRACE(("%s : Del node : %s\n", __FUNCTION__, node->bss_info->SSID));
3493                         kfree(node);
3494                         break;
3495                 }
3496
3497                 prev = node;
3498                 node = node->next;
3499         }
3500
3501         memset(addr, 0, ETHER_ADDR_LEN);
3502         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3503         return 0;
3504 }
3505
3506 #endif  
3507
3508 static int
3509 wl_iw_set_scan(
3510         struct net_device *dev,
3511         struct iw_request_info *info,
3512         union iwreq_data *wrqu,
3513         char *extra
3514 )
3515 {
3516         int error;
3517         WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name));
3518
3519 #ifdef OEM_CHROMIUMOS
3520         g_set_essid_before_scan = FALSE;
3521 #endif
3522
3523 #if defined(CSCAN)
3524                 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3525                 return -EINVAL;
3526 #endif 
3527
3528 #if defined(SOFTAP)
3529         
3530         if (ap_cfg_running) {
3531                 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3532                 return 0;
3533         }
3534 #endif 
3535
3536         
3537         if (g_onoff == G_WLAN_SET_OFF)
3538                 return 0;
3539
3540         
3541         memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
3542 #ifndef WL_IW_USE_ISCAN
3543         
3544         g_scan_specified_ssid = 0;
3545 #endif 
3546
3547 #if WIRELESS_EXT > 17
3548         
3549         if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3550                 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3551                         struct iw_scan_req *req = (struct iw_scan_req *)extra;
3552 #if defined(CONFIG_FIRST_SCAN)
3553                         if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3554                                 
3555                                 WL_TRACE(("%s Ignoring SC %s first BC is not done = %d\n",
3556                                           __FUNCTION__, req->essid,
3557                                           g_first_broadcast_scan));
3558                                 return -EBUSY;
3559                         }
3560 #endif  
3561                         if (g_scan_specified_ssid) {
3562                                 WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n",
3563                                         __FUNCTION__, req->essid));
3564                                 
3565                                 return -EBUSY;
3566                         }
3567                         else {
3568                                 g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID),
3569                                                                req->essid_len);
3570                                 memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len);
3571                                 g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len);
3572                                 g_scan_specified_ssid = 1;
3573                                 WL_TRACE(("### Specific scan ssid=%s len=%d\n",
3574                                           g_specific_ssid.SSID, g_specific_ssid.SSID_len));
3575                         }
3576                 }
3577         }
3578 #endif 
3579         
3580         if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) {
3581                 WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error));
3582                 
3583                 g_scan_specified_ssid = 0;
3584                 return -EBUSY;
3585         }
3586
3587         return 0;
3588 }
3589
3590 #ifdef WL_IW_USE_ISCAN
3591 int
3592 wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
3593 {
3594         wlc_ssid_t ssid;
3595         iscan_info_t *iscan = g_iscan;
3596
3597 #if defined(CONFIG_FIRST_SCAN)
3598         
3599         if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) {
3600                 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED;
3601                 WL_TRACE(("%s: First Brodcast scan was forced\n", __FUNCTION__));
3602         }
3603         else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) {
3604                 WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__));
3605                 return 0;
3606         }
3607 #endif 
3608
3609 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3610         if (flag)
3611                 rtnl_lock();
3612 #endif
3613
3614         dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag));
3615         wl_iw_set_event_mask(dev);
3616
3617         WL_TRACE(("+++: Set Broadcast ISCAN\n"));
3618         
3619         memset(&ssid, 0, sizeof(ssid));
3620
3621         iscan->list_cur = iscan->list_hdr;
3622         iscan->iscan_state = ISCAN_STATE_SCANING;
3623
3624         memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size);
3625         wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
3626         wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
3627
3628 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3629         if (flag)
3630                 rtnl_unlock();
3631 #endif
3632
3633         mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3634
3635         iscan->timer_on = 1;
3636
3637         return 0;
3638 }
3639
3640 static int
3641 wl_iw_iscan_set_scan(
3642         struct net_device *dev,
3643         struct iw_request_info *info,
3644         union iwreq_data *wrqu,
3645         char *extra
3646 )
3647 {
3648         wlc_ssid_t ssid;
3649         iscan_info_t *iscan = g_iscan;
3650         int ret = 0;
3651
3652         WL_TRACE_SCAN(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
3653
3654 #if defined(CSCAN)
3655                 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3656                 return -EINVAL;
3657 #endif 
3658
3659         net_os_wake_lock(dev);
3660
3661         
3662 #if defined(SOFTAP)
3663         if (ap_cfg_running) {
3664                 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3665                 goto set_scan_end;
3666         }
3667 #endif
3668         
3669         if (g_onoff == G_WLAN_SET_OFF) {
3670                 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
3671                 goto set_scan_end;
3672         }
3673
3674 #ifdef PNO_SUPPORT
3675         
3676         if  (dhd_dev_get_pno_status(dev)) {
3677                 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
3678         }
3679 #endif 
3680
3681         
3682         if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
3683                 WL_ERROR(("%s error \n",  __FUNCTION__));
3684                 goto set_scan_end;
3685         }
3686
3687         if (g_scan_specified_ssid) {
3688                 WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n",
3689                           __FUNCTION__));
3690                 ret = EBUSY;
3691                 goto set_scan_end;
3692         }
3693
3694         
3695         memset(&ssid, 0, sizeof(ssid));
3696
3697 #if WIRELESS_EXT > 17
3698         
3699         if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3700                 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3701                         int as = 0;
3702                         struct iw_scan_req *req = (struct iw_scan_req *)extra;
3703                         
3704                         ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
3705                         memcpy(ssid.SSID, req->essid, ssid.SSID_len);
3706                         ssid.SSID_len = htod32(ssid.SSID_len);
3707                         dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
3708                         wl_iw_set_event_mask(dev);
3709                         ret = wl_iw_set_scan(dev, info, wrqu, extra);
3710                         goto set_scan_end;
3711                 }
3712                 else {
3713                         g_scan_specified_ssid = 0;
3714
3715                         if (iscan->iscan_state == ISCAN_STATE_SCANING) {
3716                                 WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__));
3717                                 goto set_scan_end;
3718                         }
3719                 }
3720         }
3721 #endif 
3722
3723 #if defined(CONFIG_FIRST_SCAN) && !defined(CSCAN)
3724         if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3725                 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
3726
3727                         WL_ERROR(("%s Clean up First scan flag which is %d\n",
3728                                   __FUNCTION__, g_first_broadcast_scan));
3729                         g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
3730                 }
3731                 else {
3732                         WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n",
3733                                   __FUNCTION__, g_first_counter_scans));
3734                         ret = -EBUSY;
3735                         goto set_scan_end;
3736                 }
3737         }
3738 #endif
3739
3740         wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
3741
3742 set_scan_end:
3743         net_os_wake_unlock(dev);
3744         return ret;
3745 }
3746 #endif 
3747
3748 #if WIRELESS_EXT > 17
3749 static bool
3750 ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
3751 {
3752
3753
3754         uint8 *ie = *wpaie;
3755
3756         
3757         if ((ie[1] >= 6) &&
3758                 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
3759                 return TRUE;
3760         }
3761
3762         
3763         ie += ie[1] + 2;
3764         
3765         *tlvs_len -= (int)(ie - *tlvs);
3766         
3767         *tlvs = ie;
3768         return FALSE;
3769 }
3770
3771 static bool
3772 ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
3773 {
3774
3775
3776         uint8 *ie = *wpsie;
3777
3778         
3779         if ((ie[1] >= 4) &&
3780                 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
3781                 return TRUE;
3782         }
3783
3784         
3785         ie += ie[1] + 2;
3786         
3787         *tlvs_len -= (int)(ie - *tlvs);
3788         
3789         *tlvs = ie;
3790         return FALSE;
3791 }
3792 #endif 
3793
3794
3795 static int
3796 wl_iw_handle_scanresults_ies(char **event_p, char *end,
3797         struct iw_request_info *info, wl_bss_info_t *bi)
3798 {
3799 #if WIRELESS_EXT > 17
3800         struct iw_event iwe;
3801         char *event;
3802
3803         event = *event_p;
3804         if (bi->ie_length) {
3805                 
3806                 bcm_tlv_t *ie;
3807                 uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3808                 int ptr_len = bi->ie_length;
3809
3810                 if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
3811                         iwe.cmd = IWEVGENIE;
3812                         iwe.u.data.length = ie->len + 2;
3813                         event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3814                 }
3815                 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3816
3817                 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3818                         
3819                         if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3820                                 iwe.cmd = IWEVGENIE;
3821                                 iwe.u.data.length = ie->len + 2;
3822                                 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3823                                 break;
3824                         }
3825                 }
3826
3827                 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3828                 ptr_len = bi->ie_length;
3829                 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3830                         if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3831                                 iwe.cmd = IWEVGENIE;
3832                                 iwe.u.data.length = ie->len + 2;
3833                                 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3834                                 break;
3835                         }
3836                 }
3837
3838         *event_p = event;
3839         }
3840 #endif 
3841
3842         return 0;
3843 }
3844
3845 #ifndef CSCAN
3846 static uint
3847 wl_iw_get_scan_prep(
3848         wl_scan_results_t *list,
3849         struct iw_request_info *info,
3850         char *extra,
3851         short max_size)
3852 {
3853         int  i, j;
3854         struct iw_event  iwe;
3855         wl_bss_info_t *bi = NULL;
3856         char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
3857         int     ret = 0;
3858
3859         if (!list) {
3860                 WL_ERROR(("%s: Null list pointer", __FUNCTION__));
3861                 return ret;
3862         }
3863
3864         
3865
3866         for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
3867                 if (list->version != WL_BSS_INFO_VERSION) {
3868                         WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
3869                                   __FUNCTION__, list->version));
3870                         return ret;
3871                 }
3872
3873                 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
3874
3875                 WL_TRACE(("%s : %s\n", __FUNCTION__, bi->SSID));
3876
3877                 
3878                 iwe.cmd = SIOCGIWAP;
3879                 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
3880                 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
3881                 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
3882                 
3883                 iwe.u.data.length = dtoh32(bi->SSID_len);
3884                 iwe.cmd = SIOCGIWESSID;
3885                 iwe.u.data.flags = 1;
3886                 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
3887
3888                 
3889                 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
3890                         iwe.cmd = SIOCGIWMODE;
3891                         if (dtoh16(bi->capability) & DOT11_CAP_ESS)
3892                                 iwe.u.mode = IW_MODE_INFRA;
3893                         else
3894                                 iwe.u.mode = IW_MODE_ADHOC;
3895                         event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
3896                 }
3897
3898                 
3899                 iwe.cmd = SIOCGIWFREQ;
3900                 iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
3901                         CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
3902                         WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
3903                 iwe.u.freq.e = 6;
3904                 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
3905
3906                 
3907                 iwe.cmd = IWEVQUAL;
3908                 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
3909                 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
3910                 iwe.u.qual.noise = 0x100 + bi->phy_noise;
3911                 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
3912
3913                 
3914                  wl_iw_handle_scanresults_ies(&event, end, info, bi);
3915
3916                 
3917                 iwe.cmd = SIOCGIWENCODE;
3918                 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
3919                         iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
3920                 else
3921                         iwe.u.data.flags = IW_ENCODE_DISABLED;
3922                 iwe.u.data.length = 0;
3923                 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
3924
3925                 
3926                 if (bi->rateset.count) {
3927                         if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) {
3928                                 value = event + IW_EV_LCP_LEN;
3929                                 iwe.cmd = SIOCGIWRATE;
3930                                 
3931                                 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
3932                                 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
3933                                         iwe.u.bitrate.value =
3934                                                 (bi->rateset.rates[j] & 0x7f) * 500000;
3935                                         value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
3936                                                 IW_EV_PARAM_LEN);
3937                                 }
3938                                 event = value;
3939                         }
3940                 }
3941         }
3942
3943         if ((ret = (event - extra)) < 0) {
3944                 WL_ERROR(("==> Wrong size\n"));
3945                 ret = 0;
3946         }
3947
3948         WL_TRACE(("%s: size=%d bytes prepared \n", __FUNCTION__, (unsigned int)(event - extra)));
3949         return (uint)ret;
3950 }
3951
3952 static int
3953 wl_iw_get_scan(
3954         struct net_device *dev,
3955         struct iw_request_info *info,
3956         struct iw_point *dwrq,
3957         char *extra
3958 )
3959 {
3960         channel_info_t ci;
3961         wl_scan_results_t *list_merge;
3962         wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
3963         int error;
3964         uint buflen_from_user = dwrq->length;
3965         uint len =  G_SCAN_RESULTS;
3966         __u16 len_ret = 0;
3967 #if  !defined(CSCAN)
3968         __u16 merged_len = 0;
3969 #endif
3970 #if defined(WL_IW_USE_ISCAN)
3971         iscan_info_t *iscan = g_iscan;
3972         iscan_buf_t * p_buf;
3973 #if  !defined(CSCAN)
3974         uint32 counter = 0;
3975 #endif 
3976 #endif 
3977
3978         WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
3979
3980         if (!extra) {
3981                 WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name));
3982                 return -EINVAL;
3983         }
3984
3985         
3986         if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
3987                 return error;
3988         ci.scan_channel = dtoh32(ci.scan_channel);
3989         if (ci.scan_channel)
3990                 return -EAGAIN;
3991
3992 #if  !defined(CSCAN)
3993         if (g_ss_cache_ctrl.m_timer_expired) {
3994                 wl_iw_free_ss_cache();
3995                 g_ss_cache_ctrl.m_timer_expired ^= 1;
3996         }
3997         if ((!g_scan_specified_ssid && g_ss_cache_ctrl.m_prev_scan_mode) ||
3998                 g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
3999                 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4000                 
4001                 wl_iw_reset_ss_cache();
4002         }
4003         g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
4004         if (g_scan_specified_ssid) {
4005                 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4006         }
4007         else {
4008                 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
4009         }
4010 #endif 
4011
4012
4013         
4014         if (g_scan_specified_ssid) {
4015                 
4016                 list = kmalloc(len, GFP_KERNEL);
4017                 if (!list) {
4018                         WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", dev->name));
4019                         g_scan_specified_ssid = 0;
4020                         return -ENOMEM;
4021                 }
4022         }
4023
4024         memset(list, 0, len);
4025         list->buflen = htod32(len);
4026         if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) {
4027                 WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error));
4028                 dwrq->length = len;
4029                 if (g_scan_specified_ssid) {
4030                         g_scan_specified_ssid = 0;
4031                         kfree(list);
4032                 }
4033                 return 0;
4034         }
4035         list->buflen = dtoh32(list->buflen);
4036         list->version = dtoh32(list->version);
4037         list->count = dtoh32(list->count);
4038
4039         
4040         if (list->version != WL_BSS_INFO_VERSION) {
4041                 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
4042                           __FUNCTION__, list->version));
4043                 if (g_scan_specified_ssid) {
4044                         g_scan_specified_ssid = 0;
4045                         kfree(list);
4046                 }
4047                 return -EINVAL;
4048         }
4049
4050 #if  !defined(CSCAN)
4051         if (g_scan_specified_ssid) {
4052                 
4053                 wl_iw_add_bss_to_ss_cache(list);
4054                 kfree(list);
4055         }
4056 #endif
4057
4058 #if  !defined(CSCAN)
4059         DHD_OS_MUTEX_LOCK(&wl_cache_lock);
4060 #if defined(WL_IW_USE_ISCAN)
4061         if (g_scan_specified_ssid)
4062                 WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count));
4063         p_buf = iscan->list_hdr;
4064         
4065         while (p_buf != iscan->list_cur) {
4066                 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4067                 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4068                 counter += list_merge->count;
4069                 if (list_merge->count > 0)
4070                         len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4071                             extra+len_ret, buflen_from_user -len_ret);
4072                 p_buf = p_buf->next;
4073         }
4074         WL_TRACE(("%s merged with total Bcast APs=%d\n", __FUNCTION__, counter));
4075 #else
4076         list_merge = (wl_scan_results_t *) g_scan;
4077         len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user);
4078 #endif 
4079         DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
4080         if (g_ss_cache_ctrl.m_link_down) {
4081                 
4082                 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4083         }
4084         
4085         wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len);
4086         len_ret += merged_len;
4087         wl_iw_run_ss_cache_timer(0);
4088         wl_iw_run_ss_cache_timer(1);
4089 #else   
4090
4091         
4092         if (g_scan_specified_ssid) {
4093                 WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count));
4094                 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4095                 kfree(list);
4096
4097 #if defined(WL_IW_USE_ISCAN)
4098                 p_buf = iscan->list_hdr;
4099                 
4100                 while (p_buf != iscan->list_cur) {
4101                         list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4102                         WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4103                         if (list_merge->count > 0)
4104                                 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4105                                     extra+len_ret, buflen_from_user -len_ret);
4106                         p_buf = p_buf->next;
4107                 }
4108 #else
4109                 list_merge = (wl_scan_results_t *) g_scan;
4110                 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4111                 if (list_merge->count > 0)
4112                         len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret,
4113                                 buflen_from_user -len_ret);
4114 #endif 
4115         }
4116         else {
4117                 list = (wl_scan_results_t *) g_scan;
4118                 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4119         }
4120 #endif  
4121
4122 #if defined(WL_IW_USE_ISCAN)
4123         
4124         g_scan_specified_ssid = 0;
4125 #endif 
4126         
4127         if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
4128                 len = len_ret;
4129
4130         dwrq->length = len;
4131         dwrq->flags = 0;        
4132
4133         WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count));
4134         return 0;
4135 }
4136 #endif 
4137
4138 #if defined(WL_IW_USE_ISCAN)
4139 static int
4140 wl_iw_iscan_get_scan(
4141         struct net_device *dev,
4142         struct iw_request_info *info,
4143         struct iw_point *dwrq,
4144         char *extra
4145 )
4146 {
4147         wl_scan_results_t *list;
4148         struct iw_event iwe;
4149         wl_bss_info_t *bi = NULL;
4150         int ii, j;
4151         int apcnt;
4152         char *event = extra, *end = extra + dwrq->length, *value;
4153         iscan_info_t *iscan = g_iscan;
4154         iscan_buf_t * p_buf;
4155         uint32  counter = 0;
4156         uint8   channel;
4157 #if !defined(CSCAN)
4158         __u16 merged_len = 0;
4159         uint buflen_from_user = dwrq->length;
4160 #endif
4161
4162         WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length));
4163
4164 #if defined(SOFTAP)
4165         if (ap_cfg_running) {
4166                 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
4167                 return -EINVAL;
4168         }
4169 #endif
4170
4171         if (!extra) {
4172                 WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", dev->name));
4173                 return -EINVAL;
4174         }
4175
4176 #if defined(CONFIG_FIRST_SCAN)
4177         if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) {
4178                 WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n",
4179                           dev->name, __FUNCTION__));
4180                 return -EAGAIN;
4181         }
4182 #endif  
4183         
4184         if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
4185                 WL_ERROR(("%ssysioc_pid\n", __FUNCTION__));
4186                 return EAGAIN;
4187         }
4188
4189         
4190
4191 #if !defined(CSCAN)
4192         if (g_ss_cache_ctrl.m_timer_expired) {
4193                 wl_iw_free_ss_cache();
4194                 g_ss_cache_ctrl.m_timer_expired ^= 1;
4195         }
4196         if (g_scan_specified_ssid) {
4197                 return wl_iw_get_scan(dev, info, dwrq, extra);
4198         }
4199         else {
4200                 if (g_ss_cache_ctrl.m_link_down) {
4201                         
4202                         wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4203                 }
4204                 if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
4205                         g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4206                         
4207                         wl_iw_reset_ss_cache();
4208                 }
4209                 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
4210                 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
4211         }
4212 #endif 
4213
4214         WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
4215         apcnt = 0;
4216         p_buf = iscan->list_hdr;
4217         
4218         while (p_buf != iscan->list_cur) {
4219                 list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4220
4221                 counter += list->count;
4222
4223                 if (list->version != WL_BSS_INFO_VERSION) {
4224                         WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
4225                                   __FUNCTION__, list->version));
4226                         return -EINVAL;
4227                 }
4228
4229                 bi = NULL;
4230                 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
4231                         bi = (bi ?
4232                               (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) :
4233                               list->bss_info);
4234                         ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
4235                                                                       WLC_IW_ISCAN_MAXLEN));
4236
4237                         
4238                         if (event + ETHER_ADDR_LEN + bi->SSID_len +
4239                             IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end)
4240                                 return -E2BIG;
4241                         
4242                         iwe.cmd = SIOCGIWAP;
4243                         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
4244                         memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
4245                         event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
4246
4247                         
4248                         iwe.u.data.length = dtoh32(bi->SSID_len);
4249                         iwe.cmd = SIOCGIWESSID;
4250                         iwe.u.data.flags = 1;
4251                         event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
4252
4253                         
4254                         if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
4255                                 iwe.cmd = SIOCGIWMODE;
4256                                 if (dtoh16(bi->capability) & DOT11_CAP_ESS)
4257                                         iwe.u.mode = IW_MODE_INFRA;
4258                                 else
4259                                         iwe.u.mode = IW_MODE_ADHOC;
4260                                 event = IWE_STREAM_ADD_EVENT(info, event, end,
4261                                                              &iwe, IW_EV_UINT_LEN);
4262                         }
4263
4264                         
4265                         iwe.cmd = SIOCGIWFREQ;
4266                         channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
4267                         iwe.u.freq.m = wf_channel2mhz(channel,
4268                                                       channel <= CH_MAX_2G_CHANNEL ?
4269                                                       WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
4270                         iwe.u.freq.e = 6;
4271                         event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
4272
4273                         
4274                         iwe.cmd = IWEVQUAL;
4275                         iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
4276                         iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
4277                         iwe.u.qual.noise = 0x100 + bi->phy_noise;
4278                         event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
4279
4280                         
4281                         wl_iw_handle_scanresults_ies(&event, end, info, bi);
4282
4283                         
4284                         iwe.cmd = SIOCGIWENCODE;
4285                         if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
4286                                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4287                         else
4288                                 iwe.u.data.flags = IW_ENCODE_DISABLED;
4289                         iwe.u.data.length = 0;
4290                         event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
4291
4292                         
4293                         if (bi->rateset.count) {
4294                                 if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
4295                                         return -E2BIG;
4296
4297                                 value = event + IW_EV_LCP_LEN;
4298                                 iwe.cmd = SIOCGIWRATE;
4299                                 
4300                                 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4301                                 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
4302                                         iwe.u.bitrate.value =
4303                                                 (bi->rateset.rates[j] & 0x7f) * 500000;
4304                                         value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
4305                                                                      IW_EV_PARAM_LEN);
4306                                 }
4307                                 event = value;
4308                         }
4309                 }
4310                 p_buf = p_buf->next;
4311         } 
4312
4313         dwrq->length = event - extra;
4314         dwrq->flags = 0;        
4315
4316 #if !defined(CSCAN)
4317         
4318         wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
4319         dwrq->length += merged_len;
4320         wl_iw_run_ss_cache_timer(0);
4321         wl_iw_run_ss_cache_timer(1);
4322 #endif 
4323         
4324 #if defined(CONFIG_FIRST_SCAN)
4325         g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
4326 #endif 
4327
4328         WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
4329
4330         return 0;
4331 }
4332 #endif 
4333
4334 #define WL_JOIN_PARAMS_MAX 1600
4335 #ifdef CONFIG_PRESCANNED
4336 static int
4337 check_prescan(wl_join_params_t *join_params, int *join_params_size)
4338 {
4339         int cnt = 0;
4340         int indx = 0;
4341         wl_iw_ss_cache_t *node = NULL;
4342         wl_bss_info_t *bi = NULL;
4343         iscan_info_t *iscan = g_iscan;
4344         iscan_buf_t * buf;
4345         wl_scan_results_t *list;
4346         char *destbuf;
4347
4348         buf = iscan->list_hdr;
4349
4350         while (buf) {
4351                 list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
4352                 bi = NULL;
4353                 for (indx = 0;  indx < list->count; indx++) {
4354                         bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
4355                                 : list->bss_info;
4356                         if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
4357                                 continue;
4358                         if ((dtoh32(bi->SSID_len) != join_params->ssid.SSID_len) ||
4359                                 memcmp(bi->SSID, join_params->ssid.SSID,
4360                                 join_params->ssid.SSID_len))
4361                                 continue;
4362                         memcpy(&join_params->params.chanspec_list[cnt],
4363                                 &bi->chanspec, sizeof(chanspec_t));
4364                         WL_ERROR(("iscan : chanspec :%d, count %d \n", bi->chanspec, cnt));
4365                         cnt++;
4366                 }
4367                 buf = buf->next;
4368         }
4369
4370         if (!cnt) {
4371                 MUTEX_LOCK_WL_SCAN_SET();
4372                 node = g_ss_cache_ctrl.m_cache_head;
4373                 for (; node; ) {
4374                         if (!memcmp(&node->bss_info->SSID, join_params->ssid.SSID,
4375                                 join_params->ssid.SSID_len)) {
4376                                 memcpy(&join_params->params.chanspec_list[cnt],
4377                                         &node->bss_info->chanspec, sizeof(chanspec_t));
4378                                 WL_ERROR(("cache_scan : chanspec :%d, count %d \n",
4379                                 (int)node->bss_info->chanspec, cnt));
4380                                 cnt++;
4381                         }
4382                         node = node->next;
4383                 }
4384                 MUTEX_UNLOCK_WL_SCAN_SET();
4385         }
4386
4387         if (!cnt) {
4388                 return 0;
4389         }
4390
4391         destbuf = (char *)&join_params->params.chanspec_list[cnt];
4392         *join_params_size = destbuf - (char*)join_params;
4393         join_params->ssid.SSID_len = htod32(g_ssid.SSID_len);
4394         memcpy(&(join_params->params.bssid), &ether_bcast, ETHER_ADDR_LEN);
4395         join_params->params.chanspec_num = htod32(cnt);
4396
4397         if ((*join_params_size) > WL_JOIN_PARAMS_MAX) {
4398                 WL_ERROR(("can't fit bssids for all %d APs found\n", cnt));
4399                         kfree(join_params);
4400                 return 0;
4401         }
4402
4403         WL_ERROR(("Passing %d channel/bssid pairs.\n", cnt));
4404         return cnt;
4405 }
4406 #endif 
4407
4408 static int
4409 wl_iw_set_essid(
4410         struct net_device *dev,
4411         struct iw_request_info *info,
4412         struct iw_point *dwrq,
4413         char *extra
4414 )
4415 {
4416         int error;
4417         wl_join_params_t *join_params;
4418         int join_params_size;
4419
4420         WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
4421
4422         RETURN_IF_EXTRA_NULL(extra);
4423
4424 #ifdef OEM_CHROMIUMOS
4425         if (g_set_essid_before_scan)
4426                 return -EAGAIN;
4427 #endif
4428         if (!(join_params = kmalloc(WL_JOIN_PARAMS_MAX, GFP_KERNEL))) {
4429                 WL_ERROR(("allocation failed for join_params size is %d\n", WL_JOIN_PARAMS_MAX));
4430                 return -ENOMEM;
4431         }
4432
4433         memset(join_params, 0, WL_JOIN_PARAMS_MAX);
4434
4435         
4436         memset(&g_ssid, 0, sizeof(g_ssid));
4437
4438         if (dwrq->length && extra) {
4439 #if WIRELESS_EXT > 20
4440                 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length);
4441 #else
4442                 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length-1);
4443 #endif
4444                 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
4445
4446 #ifdef CONFIG_PRESCANNED
4447                 memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
4448                 join_params->ssid.SSID_len = g_ssid.SSID_len;
4449
4450                 if (check_prescan(join_params, &join_params_size)) {
4451                         if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID,
4452                                 join_params, join_params_size))) {
4453                                 WL_ERROR(("Invalid ioctl data=%d\n", error));
4454                                 kfree(join_params);
4455                                 return error;
4456                         }
4457                         kfree(join_params);
4458                         return 0;
4459                 } else {
4460                         WL_ERROR(("No matched found\n Trying to join to specific channel\n"));
4461                 }
4462 #endif 
4463         } else {
4464                 
4465                 g_ssid.SSID_len = 0;
4466         }
4467         g_ssid.SSID_len = htod32(g_ssid.SSID_len);
4468
4469         
4470         memset(join_params, 0, sizeof(join_params));
4471         join_params_size = sizeof(join_params->ssid);
4472
4473         memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
4474         join_params->ssid.SSID_len = htod32(g_ssid.SSID_len);
4475         memcpy(&(join_params->params.bssid), &ether_bcast, ETHER_ADDR_LEN);
4476
4477         
4478         
4479         wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, join_params, &join_params_size);
4480
4481         if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, join_params, join_params_size))) {
4482                 WL_ERROR(("Invalid ioctl data=%d\n", error));
4483                 return error;
4484         }
4485
4486         if (g_ssid.SSID_len) {
4487                 WL_ERROR(("%s: join SSID=%s ch=%d\n", __FUNCTION__,
4488                         g_ssid.SSID,  g_wl_iw_params.target_channel));
4489         }
4490         kfree(join_params);
4491         return 0;
4492 }
4493
4494 static int
4495 wl_iw_get_essid(
4496         struct net_device *dev,
4497         struct iw_request_info *info,
4498         struct iw_point *dwrq,
4499         char *extra
4500 )
4501 {
4502         wlc_ssid_t ssid;
4503         int error;
4504
4505         WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
4506
4507         if (!extra)
4508                 return -EINVAL;
4509
4510         if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
4511                 WL_ERROR(("Error getting the SSID\n"));
4512                 return error;
4513         }
4514
4515         ssid.SSID_len = dtoh32(ssid.SSID_len);
4516
4517         
4518         memcpy(extra, ssid.SSID, ssid.SSID_len);
4519
4520         dwrq->length = ssid.SSID_len;
4521
4522         dwrq->flags = 1; 
4523
4524         return 0;
4525 }
4526
4527 static int
4528 wl_iw_set_nick(
4529         struct net_device *dev,
4530         struct iw_request_info *info,
4531         struct iw_point *dwrq,
4532         char *extra
4533 )
4534 {
4535         wl_iw_t *iw = NETDEV_PRIV(dev);
4536
4537         WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
4538
4539         if (!extra)
4540                 return -EINVAL;
4541
4542         
4543         if (dwrq->length > sizeof(iw->nickname))
4544                 return -E2BIG;
4545
4546         memcpy(iw->nickname, extra, dwrq->length);
4547         iw->nickname[dwrq->length - 1] = '\0';
4548
4549         return 0;
4550 }
4551
4552 static int
4553 wl_iw_get_nick(
4554         struct net_device *dev,
4555         struct iw_request_info *info,
4556         struct iw_point *dwrq,
4557         char *extra
4558 )
4559 {
4560         wl_iw_t *iw = NETDEV_PRIV(dev);
4561
4562         WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
4563
4564         if (!extra)
4565                 return -EINVAL;
4566
4567         strcpy(extra, iw->nickname);
4568         dwrq->length = strlen(extra) + 1;
4569
4570         return 0;
4571 }
4572
4573 static int
4574 wl_iw_set_rate(
4575         struct net_device *dev,
4576         struct iw_request_info *info,
4577         struct iw_param *vwrq,
4578         char *extra
4579 )
4580 {
4581         wl_rateset_t rateset;
4582         int error, rate, i, error_bg, error_a;
4583
4584         WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
4585
4586         
4587         if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
4588                 return error;
4589
4590         rateset.count = dtoh32(rateset.count);
4591
4592         if (vwrq->value < 0) {
4593                 
4594                 rate = rateset.rates[rateset.count - 1] & 0x7f;
4595         } else if (vwrq->value < rateset.count) {
4596                 
4597                 rate = rateset.rates[vwrq->value] & 0x7f;
4598         } else {
4599                 
4600                 rate = vwrq->value / 500000;
4601         }
4602
4603         if (vwrq->fixed) {
4604                 
4605                 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
4606                 error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
4607
4608                 if (error_bg && error_a)
4609                         return (error_bg | error_a);
4610         } else {
4611                 
4612                 
4613                 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
4614                 
4615                 error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
4616
4617                 if (error_bg && error_a)
4618                         return (error_bg | error_a);
4619
4620                 
4621                 for (i = 0; i < rateset.count; i++)
4622                         if ((rateset.rates[i] & 0x7f) > rate)
4623                                 break;
4624                 rateset.count = htod32(i);
4625
4626                 
4627                 if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
4628                         return error;
4629         }
4630
4631         return 0;
4632 }
4633
4634 static int
4635 wl_iw_get_rate(
4636         struct net_device *dev,
4637         struct iw_request_info *info,
4638         struct iw_param *vwrq,
4639         char *extra
4640 )
4641 {
4642         int error, rate;
4643
4644         WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
4645
4646         
4647         if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
4648                 return error;
4649         rate = dtoh32(rate);
4650         vwrq->value = rate * 500000;
4651
4652         return 0;
4653 }
4654
4655 static int
4656 wl_iw_set_rts(
4657         struct net_device *dev,
4658         struct iw_request_info *info,
4659         struct iw_param *vwrq,
4660         char *extra
4661 )
4662 {
4663         int error, rts;
4664
4665         WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
4666
4667         if (vwrq->disabled)
4668                 rts = DOT11_DEFAULT_RTS_LEN;
4669         else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
4670                 return -EINVAL;
4671         else
4672                 rts = vwrq->value;
4673
4674         if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
4675                 return error;
4676
4677         return 0;
4678 }
4679
4680 static int
4681 wl_iw_get_rts(
4682         struct net_device *dev,
4683         struct iw_request_info *info,
4684         struct iw_param *vwrq,
4685         char *extra
4686 )
4687 {
4688         int error, rts;
4689
4690         WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
4691
4692         if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
4693                 return error;
4694
4695         vwrq->value = rts;
4696         vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
4697         vwrq->fixed = 1;
4698
4699         return 0;
4700 }
4701
4702 static int
4703 wl_iw_set_frag(
4704         struct net_device *dev,
4705         struct iw_request_info *info,
4706         struct iw_param *vwrq,
4707         char *extra
4708 )
4709 {
4710         int error, frag;
4711
4712         WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
4713
4714         if (vwrq->disabled)
4715                 frag = DOT11_DEFAULT_FRAG_LEN;
4716         else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
4717                 return -EINVAL;
4718         else
4719                 frag = vwrq->value;
4720
4721         if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
4722                 return error;
4723
4724         return 0;
4725 }
4726
4727 static int
4728 wl_iw_get_frag(
4729         struct net_device *dev,
4730         struct iw_request_info *info,
4731         struct iw_param *vwrq,
4732         char *extra
4733 )
4734 {
4735         int error, fragthreshold;
4736
4737         WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
4738
4739         if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
4740                 return error;
4741
4742         vwrq->value = fragthreshold;
4743         vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
4744         vwrq->fixed = 1;
4745
4746         return 0;
4747 }
4748
4749 static int
4750 wl_iw_set_txpow(
4751         struct net_device *dev,
4752         struct iw_request_info *info,
4753         struct iw_param *vwrq,
4754         char *extra
4755 )
4756 {
4757         int error, disable;
4758         uint16 txpwrmw;
4759         WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
4760
4761         
4762         disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
4763         disable += WL_RADIO_SW_DISABLE << 16;
4764
4765         disable = htod32(disable);
4766         if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
4767                 return error;
4768
4769         
4770         if (disable & WL_RADIO_SW_DISABLE)
4771                 return 0;
4772
4773         
4774         if (!(vwrq->flags & IW_TXPOW_MWATT))
4775                 return -EINVAL;
4776
4777         
4778         if (vwrq->value < 0)
4779                 return 0;
4780
4781         if (vwrq->value > 0xffff) txpwrmw = 0xffff;
4782         else txpwrmw = (uint16)vwrq->value;
4783
4784
4785         error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
4786         return error;
4787 }
4788
4789 static int
4790 wl_iw_get_txpow(
4791         struct net_device *dev,
4792         struct iw_request_info *info,
4793         struct iw_param *vwrq,
4794         char *extra
4795 )
4796 {
4797         int error, disable, txpwrdbm;
4798         uint8 result;
4799
4800         WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
4801
4802         if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
4803             (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
4804                 return error;
4805
4806         disable = dtoh32(disable);
4807         result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
4808         vwrq->value = (int32)bcm_qdbm_to_mw(result);
4809         vwrq->fixed = 0;
4810         vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
4811         vwrq->flags = IW_TXPOW_MWATT;
4812
4813         return 0;
4814 }
4815
4816 #if WIRELESS_EXT > 10
4817 static int
4818 wl_iw_set_retry(
4819         struct net_device *dev,
4820         struct iw_request_info *info,
4821         struct iw_param *vwrq,
4822         char *extra
4823 )
4824 {
4825         int error, lrl, srl;
4826
4827         WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
4828
4829         
4830         if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
4831                 return -EINVAL;
4832
4833         
4834         if (vwrq->flags & IW_RETRY_LIMIT) {
4835
4836                 
4837 #if WIRELESS_EXT > 20
4838         if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) ||
4839                 !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) {
4840 #else
4841         if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
4842 #endif 
4843                         lrl = htod32(vwrq->value);
4844                         if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
4845                                 return error;
4846                 }
4847
4848                 
4849 #if WIRELESS_EXT > 20
4850         if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) ||
4851                 !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) {
4852 #else
4853                 if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
4854 #endif 
4855                         srl = htod32(vwrq->value);
4856                         if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
4857                                 return error;
4858                 }
4859         }
4860         return 0;
4861 }
4862
4863 static int
4864 wl_iw_get_retry(
4865         struct net_device *dev,
4866         struct iw_request_info *info,
4867         struct iw_param *vwrq,
4868         char *extra
4869 )
4870 {
4871         int error, lrl, srl;
4872
4873         WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
4874
4875         vwrq->disabled = 0;      
4876
4877         
4878         if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
4879                 return -EINVAL;
4880
4881         
4882         if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
4883             (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
4884                 return error;
4885
4886         lrl = dtoh32(lrl);
4887         srl = dtoh32(srl);
4888
4889         
4890         if (vwrq->flags & IW_RETRY_MAX) {
4891                 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
4892                 vwrq->value = lrl;
4893         } else {
4894                 vwrq->flags = IW_RETRY_LIMIT;
4895                 vwrq->value = srl;
4896                 if (srl != lrl)
4897                         vwrq->flags |= IW_RETRY_MIN;
4898         }
4899
4900         return 0;
4901 }
4902 #endif 
4903
4904 static int
4905 wl_iw_set_encode(
4906         struct net_device *dev,
4907         struct iw_request_info *info,
4908         struct iw_point *dwrq,
4909         char *extra
4910 )
4911 {
4912         wl_wsec_key_t key;
4913         int error, val, wsec;
4914
4915         WL_TRACE(("%s: SIOCSIWENCODE index %d, len %d, flags %04x (%s%s%s%s%s)\n",
4916                 dev->name, dwrq->flags & IW_ENCODE_INDEX, dwrq->length, dwrq->flags,
4917                 dwrq->flags & IW_ENCODE_NOKEY ? "NOKEY" : "",
4918                 dwrq->flags & IW_ENCODE_DISABLED ? " DISABLED" : "",
4919                 dwrq->flags & IW_ENCODE_RESTRICTED ? " RESTRICTED" : "",
4920                 dwrq->flags & IW_ENCODE_OPEN ? " OPEN" : "",
4921                 dwrq->flags & IW_ENCODE_TEMP ? " TEMP" : ""));
4922
4923         memset(&key, 0, sizeof(key));
4924
4925         if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
4926                 
4927                 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
4928                         val = htod32(key.index);
4929                         if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
4930                                 return error;
4931                         val = dtoh32(val);
4932                         if (val)
4933                                 break;
4934                 }
4935                 
4936                 if (key.index == DOT11_MAX_DEFAULT_KEYS)
4937                         key.index = 0;
4938         } else {
4939                 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
4940                 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
4941                         return -EINVAL;
4942         }
4943
4944         
4945         if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
4946                 
4947                 val = htod32(key.index);
4948                 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
4949                         return error;
4950         } else {
4951                 key.len = dwrq->length;
4952
4953                 if (dwrq->length > sizeof(key.data))
4954                         return -EINVAL;
4955
4956                 memcpy(key.data, extra, dwrq->length);
4957
4958                 key.flags = WL_PRIMARY_KEY;
4959                 switch (key.len) {
4960                 case WEP1_KEY_SIZE:
4961                         key.algo = CRYPTO_ALGO_WEP1;
4962                         break;
4963                 case WEP128_KEY_SIZE:
4964                         key.algo = CRYPTO_ALGO_WEP128;
4965                         break;
4966 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
4967                 case TKIP_KEY_SIZE:
4968                         key.algo = CRYPTO_ALGO_TKIP;
4969                         break;
4970 #endif
4971                 case AES_KEY_SIZE:
4972                         key.algo = CRYPTO_ALGO_AES_CCM;
4973                         break;
4974                 default:
4975                         return -EINVAL;
4976                 }
4977
4978                 
4979                 swap_key_from_BE(&key);
4980                 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
4981                         return error;
4982         }
4983
4984         
4985         val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
4986
4987         if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
4988                 return error;
4989
4990         wsec  &= ~(WEP_ENABLED);
4991         wsec |= val;
4992
4993         if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
4994                 return error;
4995
4996         
4997         val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
4998         val = htod32(val);
4999         if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
5000                 return error;
5001
5002         return 0;
5003 }
5004
5005 static int
5006 wl_iw_get_encode(
5007         struct net_device *dev,
5008         struct iw_request_info *info,
5009         struct iw_point *dwrq,
5010         char *extra
5011 )
5012 {
5013         wl_wsec_key_t key;
5014         int error, val, wsec, auth;
5015
5016         WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
5017
5018         
5019         bzero(&key, sizeof(wl_wsec_key_t));
5020
5021         if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
5022                 
5023                 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
5024                         val = key.index;
5025                         if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
5026                                 return error;
5027                         val = dtoh32(val);
5028                         if (val)
5029                                 break;
5030                 }
5031         } else
5032                 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5033
5034         if (key.index >= DOT11_MAX_DEFAULT_KEYS)
5035                 key.index = 0;
5036
5037         
5038
5039         if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
5040             (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
5041                 return error;
5042
5043         swap_key_to_BE(&key);
5044
5045         wsec = dtoh32(wsec);
5046         auth = dtoh32(auth);
5047         
5048         dwrq->length = MIN(DOT11_MAX_KEY_SIZE, key.len);
5049
5050         
5051         dwrq->flags = key.index + 1;
5052         if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
5053                 
5054                 dwrq->flags |= IW_ENCODE_DISABLED;
5055         }
5056         if (auth) {
5057                 
5058                 dwrq->flags |= IW_ENCODE_RESTRICTED;
5059         }
5060
5061         
5062         if (dwrq->length && extra)
5063                 memcpy(extra, key.data, dwrq->length);
5064
5065         return 0;
5066 }
5067
5068 static int
5069 wl_iw_set_power(
5070         struct net_device *dev,
5071         struct iw_request_info *info,
5072         struct iw_param *vwrq,
5073         char *extra
5074 )
5075 {
5076         int error, pm;
5077
5078         WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
5079
5080         pm = vwrq->disabled ? PM_OFF : PM_MAX;
5081
5082         pm = htod32(pm);
5083         if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
5084                 return error;
5085
5086         return 0;
5087 }
5088
5089 static int
5090 wl_iw_get_power(
5091         struct net_device *dev,
5092         struct iw_request_info *info,
5093         struct iw_param *vwrq,
5094         char *extra
5095 )
5096 {
5097         int error, pm;
5098
5099         WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
5100
5101         if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
5102                 return error;
5103
5104         pm = dtoh32(pm);
5105         vwrq->disabled = pm ? 0 : 1;
5106         vwrq->flags = IW_POWER_ALL_R;
5107
5108         return 0;
5109 }
5110
5111 #if WIRELESS_EXT > 17
5112 static int
5113 wl_iw_set_wpaie(
5114         struct net_device *dev,
5115         struct iw_request_info *info,
5116         struct iw_point *iwp,
5117         char *extra
5118 )
5119 {
5120
5121         WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
5122
5123         RETURN_IF_EXTRA_NULL(extra);
5124
5125 #ifdef DHD_DEBUG
5126         {
5127                 int i;
5128
5129                 for (i = 0; i < iwp->length; i++)
5130                         WL_TRACE(("%02X ", extra[i]));
5131                 WL_TRACE(("\n"));
5132         }
5133 #endif
5134
5135                 dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
5136
5137         return 0;
5138 }
5139
5140 static int
5141 wl_iw_get_wpaie(
5142         struct net_device *dev,
5143         struct iw_request_info *info,
5144         struct iw_point *iwp,
5145         char *extra
5146 )
5147 {
5148         WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
5149         iwp->length = 64;
5150         dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
5151         return 0;
5152 }
5153
5154 static int
5155 wl_iw_set_encodeext(
5156         struct net_device *dev,
5157         struct iw_request_info *info,
5158         struct iw_point *dwrq,
5159         char *extra
5160 )
5161 {
5162         wl_wsec_key_t key;
5163         int error;
5164         struct iw_encode_ext *iwe;
5165
5166         WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
5167
5168         RETURN_IF_EXTRA_NULL(extra);
5169
5170         memset(&key, 0, sizeof(key));
5171         iwe = (struct iw_encode_ext *)extra;
5172
5173         
5174         if (dwrq->flags & IW_ENCODE_DISABLED) {
5175
5176         }
5177
5178         
5179         key.index = 0;
5180         if (dwrq->flags & IW_ENCODE_INDEX)
5181                 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5182
5183         key.len = iwe->key_len;
5184
5185         
5186         if (!ETHER_ISMULTI(iwe->addr.sa_data))
5187                 bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
5188
5189         
5190         if (key.len == 0) {
5191                 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5192                         WL_WSEC(("Changing the the primary Key to %d\n", key.index));
5193                         
5194                         key.index = htod32(key.index);
5195                         error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
5196                                 &key.index, sizeof(key.index));
5197                         if (error)
5198                                 return error;
5199                 }
5200                 
5201                 else {
5202                         swap_key_from_BE(&key);
5203                         dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5204                 }
5205         }
5206         else {
5207                 if (iwe->key_len > sizeof(key.data))
5208                         return -EINVAL;
5209
5210                 WL_WSEC(("Setting the key index %d\n", key.index));
5211                 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5212                         WL_WSEC(("key is a Primary Key\n"));
5213                         key.flags = WL_PRIMARY_KEY;
5214                 }
5215
5216                 bcopy((void *)iwe->key, key.data, iwe->key_len);
5217
5218                 if (iwe->alg == IW_ENCODE_ALG_TKIP) {
5219                         uint8 keybuf[8];
5220                         bcopy(&key.data[24], keybuf, sizeof(keybuf));
5221                         bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
5222                         bcopy(keybuf, &key.data[16], sizeof(keybuf));
5223                 }
5224
5225                 
5226                 if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
5227                         uchar *ivptr;
5228                         ivptr = (uchar *)iwe->rx_seq;
5229                         key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
5230                                 (ivptr[3] << 8) | ivptr[2];
5231                         key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
5232                         key.iv_initialized = TRUE;
5233                 }
5234
5235                 switch (iwe->alg) {
5236                         case IW_ENCODE_ALG_NONE:
5237                                 key.algo = CRYPTO_ALGO_OFF;
5238                                 break;
5239                         case IW_ENCODE_ALG_WEP:
5240                                 if (iwe->key_len == WEP1_KEY_SIZE)
5241                                         key.algo = CRYPTO_ALGO_WEP1;
5242                                 else
5243                                         key.algo = CRYPTO_ALGO_WEP128;
5244                                 break;
5245                         case IW_ENCODE_ALG_TKIP:
5246                                 key.algo = CRYPTO_ALGO_TKIP;
5247                                 break;
5248                         case IW_ENCODE_ALG_CCMP:
5249                                 key.algo = CRYPTO_ALGO_AES_CCM;
5250                                 break;
5251                         default:
5252                                 break;
5253                 }
5254                 swap_key_from_BE(&key);
5255
5256                 dhd_wait_pend8021x(dev);
5257
5258                 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5259                 if (error)
5260                         return error;
5261         }
5262         return 0;
5263 }
5264
5265 #if WIRELESS_EXT > 17
5266 struct {
5267         pmkid_list_t pmkids;
5268         pmkid_t foo[MAXPMKID-1];
5269 } pmkid_list;
5270
5271 static int
5272 wl_iw_set_pmksa(
5273         struct net_device *dev,
5274         struct iw_request_info *info,
5275         struct iw_param *vwrq,
5276         char *extra
5277 )
5278 {
5279         struct iw_pmksa *iwpmksa;
5280         uint i;
5281         int ret = 0;
5282         char eabuf[ETHER_ADDR_STR_LEN];
5283
5284         WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name));
5285
5286         RETURN_IF_EXTRA_NULL(extra);
5287
5288         iwpmksa = (struct iw_pmksa *)extra;
5289         bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
5290
5291         if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
5292                 WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
5293                 bzero((char *)&pmkid_list, sizeof(pmkid_list));
5294         }
5295
5296         else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
5297                 {
5298                         pmkid_list_t pmkid, *pmkidptr;
5299                         uint j;
5300                         pmkidptr = &pmkid;
5301
5302                         bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID,
5303                                 ETHER_ADDR_LEN);
5304                         bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
5305
5306                         WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
5307                                 bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
5308                                 eabuf)));
5309                         for (j = 0; j < WPA2_PMKID_LEN; j++)
5310                                 WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
5311                         WL_WSEC(("\n"));
5312                 }
5313
5314                 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5315                         if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
5316                                 ETHER_ADDR_LEN))
5317                                 break;
5318
5319                 if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) {
5320                         bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t));
5321                         for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
5322                                 bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID,
5323                                         &pmkid_list.pmkids.pmkid[i].BSSID,
5324                                         ETHER_ADDR_LEN);
5325                                 bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID,
5326                                         &pmkid_list.pmkids.pmkid[i].PMKID,
5327                                         WPA2_PMKID_LEN);
5328                         }
5329                         pmkid_list.pmkids.npmkid--;
5330                 }
5331                 else
5332                         ret = -EINVAL;
5333         }
5334
5335         else if (iwpmksa->cmd == IW_PMKSA_ADD) {
5336                 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5337                         if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
5338                                 ETHER_ADDR_LEN))
5339                                 break;
5340                 if (i < MAXPMKID) {
5341                         bcopy(&iwpmksa->bssid.sa_data[0],
5342                                 &pmkid_list.pmkids.pmkid[i].BSSID,
5343                                 ETHER_ADDR_LEN);
5344                         bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID,
5345                                 WPA2_PMKID_LEN);
5346                         if (i == pmkid_list.pmkids.npmkid)
5347                                 pmkid_list.pmkids.npmkid++;
5348                 }
5349                 else
5350                         ret = -EINVAL;
5351
5352                 {
5353                         uint j;
5354                         uint k;
5355                         k = pmkid_list.pmkids.npmkid;
5356                         WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
5357                                 bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID,
5358                                 eabuf)));
5359                         for (j = 0; j < WPA2_PMKID_LEN; j++)
5360                                 WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j]));
5361                         WL_WSEC(("\n"));
5362                 }
5363         }
5364         WL_WSEC(("PRINTING pmkid LIST - No of elements %d", pmkid_list.pmkids.npmkid));
5365         for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
5366                 uint j;
5367                 WL_WSEC(("\nPMKID[%d]: %s = ", i,
5368                         bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID,
5369                         eabuf)));
5370                 for (j = 0; j < WPA2_PMKID_LEN; j++)
5371                         WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
5372         }
5373         WL_WSEC(("\n"));
5374
5375         if (!ret)
5376                 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
5377                         sizeof(pmkid_list));
5378         return ret;
5379 }
5380 #endif 
5381
5382 static int
5383 wl_iw_get_encodeext(
5384         struct net_device *dev,
5385         struct iw_request_info *info,
5386         struct iw_param *vwrq,
5387         char *extra
5388 )
5389 {
5390         WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
5391         return 0;
5392 }
5393
5394
5395 static uint32
5396 wl_iw_create_wpaauth_wsec(struct net_device *dev)
5397 {
5398         wl_iw_t *iw = NETDEV_PRIV(dev);
5399         uint32 wsec;
5400
5401         
5402         if (iw->pcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
5403                 wsec = WEP_ENABLED;
5404         else if (iw->pcipher & IW_AUTH_CIPHER_TKIP)
5405                 wsec = TKIP_ENABLED;
5406         else if (iw->pcipher & IW_AUTH_CIPHER_CCMP)
5407                 wsec = AES_ENABLED;
5408         else
5409                 wsec = 0;
5410
5411         
5412         if (iw->gcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
5413                 wsec |= WEP_ENABLED;
5414         else if (iw->gcipher & IW_AUTH_CIPHER_TKIP)
5415                 wsec |= TKIP_ENABLED;
5416         else if (iw->gcipher & IW_AUTH_CIPHER_CCMP)
5417                 wsec |= AES_ENABLED;
5418
5419         
5420         if (wsec == 0 && iw->privacy_invoked)
5421                 wsec = WEP_ENABLED;
5422
5423         WL_INFORM(("%s: returning wsec of %d\n", __FUNCTION__, wsec));
5424
5425         return wsec;
5426 }
5427
5428 static int
5429 wl_iw_set_wpaauth(
5430         struct net_device *dev,
5431         struct iw_request_info *info,
5432         struct iw_param *vwrq,
5433         char *extra
5434 )
5435 {
5436         int error = 0;
5437         int paramid;
5438         int paramval;
5439         int val = 0;
5440         wl_iw_t *iw = NETDEV_PRIV(dev);
5441
5442         paramid = vwrq->flags & IW_AUTH_INDEX;
5443         paramval = vwrq->value;
5444
5445         WL_TRACE(("%s: SIOCSIWAUTH, %s(%d), paramval = 0x%0x\n",
5446                 dev->name,
5447                 paramid == IW_AUTH_WPA_VERSION ? "IW_AUTH_WPA_VERSION" :
5448                 paramid == IW_AUTH_CIPHER_PAIRWISE ? "IW_AUTH_CIPHER_PAIRWISE" :
5449                 paramid == IW_AUTH_CIPHER_GROUP ? "IW_AUTH_CIPHER_GROUP" :
5450                 paramid == IW_AUTH_KEY_MGMT ? "IW_AUTH_KEY_MGMT" :
5451                 paramid == IW_AUTH_TKIP_COUNTERMEASURES ? "IW_AUTH_TKIP_COUNTERMEASURES" :
5452                 paramid == IW_AUTH_DROP_UNENCRYPTED ? "IW_AUTH_DROP_UNENCRYPTED" :
5453                 paramid == IW_AUTH_80211_AUTH_ALG ? "IW_AUTH_80211_AUTH_ALG" :
5454                 paramid == IW_AUTH_WPA_ENABLED ? "IW_AUTH_WPA_ENABLED" :
5455                 paramid == IW_AUTH_RX_UNENCRYPTED_EAPOL ? "IW_AUTH_RX_UNENCRYPTED_EAPOL" :
5456                 paramid == IW_AUTH_ROAMING_CONTROL ? "IW_AUTH_ROAMING_CONTROL" :
5457                 paramid == IW_AUTH_PRIVACY_INVOKED ? "IW_AUTH_PRIVACY_INVOKED" :
5458                 "UNKNOWN",
5459                 paramid, paramval));
5460
5461 #if defined(SOFTAP)
5462         if (ap_cfg_running) {
5463                 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
5464                 return 0;
5465         }
5466 #endif
5467
5468         switch (paramid) {
5469         case IW_AUTH_WPA_VERSION:
5470                 
5471                 iw->wpaversion = paramval;
5472                 break;
5473
5474         case IW_AUTH_CIPHER_PAIRWISE:
5475                 iw->pcipher = paramval;
5476                 val = wl_iw_create_wpaauth_wsec(dev);
5477                 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5478                         return error;
5479                 break;
5480
5481         case IW_AUTH_CIPHER_GROUP:
5482                 iw->gcipher = paramval;
5483                 val = wl_iw_create_wpaauth_wsec(dev);
5484                 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5485                         return error;
5486                 break;
5487
5488         case IW_AUTH_KEY_MGMT:
5489                 if (paramval & IW_AUTH_KEY_MGMT_PSK) {
5490                         if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
5491                                 val = WPA_AUTH_PSK;
5492                         else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
5493                                 val = WPA2_AUTH_PSK;
5494                         else 
5495                                 val = WPA_AUTH_DISABLED;
5496                 } else if (paramval & IW_AUTH_KEY_MGMT_802_1X) {
5497                         if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
5498                                 val = WPA_AUTH_UNSPECIFIED;
5499                         else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
5500                                 val = WPA2_AUTH_UNSPECIFIED;
5501                         else 
5502                                 val = WPA_AUTH_DISABLED;
5503                 }
5504                 else
5505                         val = WPA_AUTH_DISABLED;
5506
5507                 WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
5508                 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
5509                         return error;
5510                 break;
5511
5512         case IW_AUTH_TKIP_COUNTERMEASURES:
5513                 dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
5514                 break;
5515
5516         case IW_AUTH_80211_AUTH_ALG:
5517                 
5518                 WL_INFORM(("Setting the D11auth %d\n", paramval));
5519                 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
5520                         val = 0;
5521                 else if (paramval == IW_AUTH_ALG_SHARED_KEY)
5522                         val = 1;
5523                 else if (paramval == (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
5524                         val = 2;
5525                 else
5526                         error = 1;
5527                 if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
5528                         return error;
5529                 break;
5530
5531         case IW_AUTH_WPA_ENABLED:
5532                 if (paramval == 0) {
5533                         iw->privacy_invoked = 0; 
5534                         iw->pcipher = 0;
5535                         iw->gcipher = 0;
5536                         val = wl_iw_create_wpaauth_wsec(dev);
5537                         if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5538                                 return error;
5539                         WL_INFORM(("%s: %d: setting wpa_auth to %d, wsec to %d\n",
5540                                 __FUNCTION__, __LINE__, paramval, val));
5541                         dev_wlc_intvar_set(dev, "wpa_auth", paramval);
5542                         return error;
5543                 }
5544
5545                 
5546                 break;
5547
5548         case IW_AUTH_DROP_UNENCRYPTED:
5549                 if ((error = dev_wlc_intvar_set(dev, "wsec_restrict", paramval)))
5550                         return error;
5551                 break;
5552
5553         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5554                 dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
5555                 break;
5556
5557 #if WIRELESS_EXT > 17
5558         case IW_AUTH_ROAMING_CONTROL:
5559                 WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5560                 
5561                 break;
5562
5563         case IW_AUTH_PRIVACY_INVOKED:
5564                 iw->privacy_invoked = paramval;
5565                 val = wl_iw_create_wpaauth_wsec(dev);
5566                 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5567                         return error;
5568                 break;
5569
5570 #endif 
5571         default:
5572                 break;
5573         }
5574         return 0;
5575 }
5576 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
5577
5578 static int
5579 wl_iw_get_wpaauth(
5580         struct net_device *dev,
5581         struct iw_request_info *info,
5582         struct iw_param *vwrq,
5583         char *extra
5584 )
5585 {
5586         int error;
5587         int paramid;
5588         int paramval = 0;
5589         int val;
5590         wl_iw_t *iw = NETDEV_PRIV(dev);
5591
5592         WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
5593
5594         paramid = vwrq->flags & IW_AUTH_INDEX;
5595
5596         switch (paramid) {
5597         case IW_AUTH_WPA_VERSION:
5598                 paramval = iw->wpaversion;
5599                 break;
5600
5601         case IW_AUTH_CIPHER_PAIRWISE:
5602                 paramval = iw->pcipher;
5603                 break;
5604
5605         case IW_AUTH_CIPHER_GROUP:
5606                 paramval = iw->gcipher;
5607                 break;
5608
5609         case IW_AUTH_KEY_MGMT:
5610                 
5611                 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5612                         return error;
5613                 if (VAL_PSK(val))
5614                         paramval = IW_AUTH_KEY_MGMT_PSK;
5615                 else
5616                         paramval = IW_AUTH_KEY_MGMT_802_1X;
5617
5618                 break;
5619
5620         case IW_AUTH_TKIP_COUNTERMEASURES:
5621                 dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)&paramval, 1);
5622                 break;
5623
5624         case IW_AUTH_DROP_UNENCRYPTED:
5625                 dev_wlc_intvar_get(dev, "wsec_restrict", &paramval);
5626                 break;
5627
5628         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5629                 dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
5630                 break;
5631
5632         case IW_AUTH_80211_AUTH_ALG:
5633                 
5634                 if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
5635                         return error;
5636                 if (!val)
5637                         paramval = IW_AUTH_ALG_OPEN_SYSTEM;
5638                 else
5639                         paramval = IW_AUTH_ALG_SHARED_KEY;
5640                 break;
5641         case IW_AUTH_WPA_ENABLED:
5642                 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5643                         return error;
5644                 if (val)
5645                         paramval = TRUE;
5646                 else
5647                         paramval = FALSE;
5648                 break;
5649 #if WIRELESS_EXT > 17
5650         case IW_AUTH_ROAMING_CONTROL:
5651                 WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5652                 
5653                 break;
5654         case IW_AUTH_PRIVACY_INVOKED:
5655                 paramval = iw->privacy_invoked;
5656                 break;
5657
5658 #endif 
5659         }
5660         vwrq->value = paramval;
5661         return 0;
5662 }
5663 #endif 
5664
5665
5666 #ifdef SOFTAP
5667
5668 static int ap_macmode = MACLIST_MODE_DISABLED;
5669 static struct mflist ap_black_list;
5670
5671 static int
5672 wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key)
5673 {
5674         char hex[] = "XX";
5675         unsigned char *data = key->data;
5676
5677         switch (strlen(keystr)) {
5678         case 5:
5679         case 13:
5680         case 16:
5681                 key->len = strlen(keystr);
5682                 memcpy(data, keystr, key->len + 1);
5683                 break;
5684         case 12:
5685         case 28:
5686         case 34:
5687         case 66:
5688                 
5689                 if (!strnicmp(keystr, "0x", 2))
5690                         keystr += 2;
5691                 else
5692                         return -1;
5693                 
5694         case 10:
5695         case 26:
5696         case 32:
5697         case 64:
5698                 key->len = strlen(keystr) / 2;
5699                 while (*keystr) {
5700                         strncpy(hex, keystr, 2);
5701                         *data++ = (char) bcm_strtoul(hex, NULL, 16);
5702                         keystr += 2;
5703                 }
5704                 break;
5705         default:
5706                 return -1;
5707         }
5708
5709         switch (key->len) {
5710         case 5:
5711                 key->algo = CRYPTO_ALGO_WEP1;
5712                 break;
5713         case 13:
5714                 key->algo = CRYPTO_ALGO_WEP128;
5715                 break;
5716         case 16:
5717                 
5718                 key->algo = CRYPTO_ALGO_AES_CCM;
5719                 break;
5720         case 32:
5721                 key->algo = CRYPTO_ALGO_TKIP;
5722                 break;
5723         default:
5724                 return -1;
5725         }
5726
5727         
5728         key->flags |= WL_PRIMARY_KEY;
5729
5730         return 0;
5731 }
5732
5733 #ifdef EXT_WPA_CRYPTO
5734 #define SHA1HashSize 20
5735 extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5736                         int iterations, u8 *buf, size_t buflen);
5737
5738 #else
5739
5740 #define SHA1HashSize 20
5741 static int
5742 pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5743             int iterations, u8 *buf, size_t buflen)
5744 {
5745         WL_ERROR(("WARNING: %s is not implemented !!!\n", __FUNCTION__));
5746         return -1;
5747 }
5748
5749 #endif 
5750
5751
5752 static int
5753 dev_iw_write_cfg1_bss_var(struct net_device *dev, int val)
5754 {
5755         struct {
5756                 int cfg;
5757                 int val;
5758         } bss_setbuf;
5759
5760         int bss_set_res;
5761         char smbuf[WLC_IOCTL_SMLEN];
5762         memset(smbuf, 0, sizeof(smbuf));
5763
5764         bss_setbuf.cfg = 1;
5765         bss_setbuf.val = val;
5766
5767         bss_set_res = dev_iw_iovar_setbuf(dev, "bss",
5768                 &bss_setbuf, sizeof(bss_setbuf), smbuf, sizeof(smbuf));
5769         WL_TRACE(("%s: bss_set_result:%d set with %d\n", __FUNCTION__, bss_set_res, val));
5770
5771         return bss_set_res;
5772 }
5773
5774
5775
5776 #ifndef AP_ONLY
5777 static int
5778 wl_bssiovar_mkbuf(
5779                 const char *iovar,
5780                 int bssidx,
5781                 void *param,
5782                 int paramlen,
5783                 void *bufptr,
5784                 int buflen,
5785                 int *perr)
5786 {
5787         const char *prefix = "bsscfg:";
5788         int8* p;
5789         uint prefixlen;
5790         uint namelen;
5791         uint iolen;
5792
5793         prefixlen = strlen(prefix);     
5794         namelen = strlen(iovar) + 1;    
5795         iolen = prefixlen + namelen + sizeof(int) + paramlen;
5796
5797         
5798         if (buflen < 0 || iolen > (uint)buflen) {
5799                 *perr = BCME_BUFTOOSHORT;
5800                 return 0;
5801         }
5802
5803         p = (int8*)bufptr;
5804
5805         
5806         memcpy(p, prefix, prefixlen);
5807         p += prefixlen;
5808
5809         
5810         memcpy(p, iovar, namelen);
5811         p += namelen;
5812
5813         
5814         bssidx = htod32(bssidx);
5815         memcpy(p, &bssidx, sizeof(int32));
5816         p += sizeof(int32);
5817
5818         
5819         if (paramlen)
5820                 memcpy(p, param, paramlen);
5821
5822         *perr = 0;
5823         return iolen;
5824 }
5825 #endif 
5826
5827
5828
5829
5830 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
5831
5832
5833 #if defined(CSCAN)
5834
5835
5836
5837 static int
5838 wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan)
5839 {
5840         int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
5841         int err = 0;
5842         char *p;
5843         int i;
5844         iscan_info_t *iscan = g_iscan;
5845
5846         WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan));
5847
5848         if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) {
5849                 WL_ERROR(("%s error exit\n", __FUNCTION__));
5850                 err = -1;
5851                 goto exit;
5852         }
5853
5854 #ifdef PNO_SUPPORT
5855         
5856         if  (dhd_dev_get_pno_status(dev)) {
5857                 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
5858         }
5859 #endif 
5860
5861         params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
5862
5863         
5864         if (nssid > 0) {
5865                 i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
5866                 i = ROUNDUP(i, sizeof(uint32));
5867                 if (i + nssid * sizeof(wlc_ssid_t) > params_size) {
5868                         printf("additional ssids exceed params_size\n");
5869                         err = -1;
5870                         goto exit;
5871                 }
5872
5873                 p = ((char*)&iscan->iscan_ex_params_p->params) + i;
5874                 memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t));
5875                 p += nssid * sizeof(wlc_ssid_t);
5876         } else {
5877                 p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16);
5878         }
5879
5880         
5881         iscan->iscan_ex_params_p->params.channel_num =
5882                 htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) |
5883                        (nchan & WL_SCAN_PARAMS_COUNT_MASK));
5884
5885         nssid = (uint)
5886                 ((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) &
5887                  WL_SCAN_PARAMS_COUNT_MASK);
5888
5889         
5890         params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t));
5891         iscan->iscan_ex_param_size = params_size;
5892
5893         iscan->list_cur = iscan->list_hdr;
5894         iscan->iscan_state = ISCAN_STATE_SCANING;
5895         wl_iw_set_event_mask(dev);
5896         mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
5897
5898         iscan->timer_on = 1;
5899
5900 #ifdef SCAN_DUMP
5901         {
5902                 int i;
5903                 WL_SCAN(("\n### List of SSIDs to scan ###\n"));
5904                 for (i = 0; i < nssid; i++) {
5905                         if (!ssids_local[i].SSID_len)
5906                                 WL_SCAN(("%d: Broadcast scan\n", i));
5907                         else
5908                         WL_SCAN(("%d: scan  for  %s size =%d\n", i,
5909                                 ssids_local[i].SSID, ssids_local[i].SSID_len));
5910                 }
5911                 WL_SCAN(("### List of channels to scan ###\n"));
5912                 for (i = 0; i < nchan; i++)
5913                 {
5914                         WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i]));
5915                 }
5916                 WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes));
5917                 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
5918                 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
5919                 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
5920                 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
5921                 WL_SCAN(("\n###################\n"));
5922         }
5923 #endif 
5924
5925         if (params_size > WLC_IOCTL_MEDLEN) {
5926                         WL_ERROR(("Set ISCAN for %s due to params_size=%d  \n",
5927                                 __FUNCTION__, params_size));
5928                         err = -1;
5929         }
5930
5931         if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p,
5932                                        iscan->iscan_ex_param_size,
5933                                        iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
5934                 WL_TRACE(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
5935                 err = -1;
5936         }
5937
5938 exit:
5939         return err;
5940 }
5941
5942
5943 static int
5944 iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info,
5945                  union iwreq_data *wrqu, char *ext)
5946 {
5947         int res;
5948         char  *extra = NULL;
5949         iscan_info_t *iscan = g_iscan;
5950         wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
5951         int nssid = 0;
5952         int nchan = 0;
5953         char *str_ptr;
5954
5955         WL_TRACE(("%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
5956                 __FUNCTION__, info->cmd, info->flags,
5957                 wrqu->data.pointer, wrqu->data.length));
5958
5959         if (g_onoff == G_WLAN_SET_OFF) {
5960                 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
5961                 return -ENODEV;
5962         }
5963
5964         if (wrqu->data.length == 0) {
5965                 WL_ERROR(("IWPRIV argument len = 0\n"));
5966                 return -EINVAL;
5967         }
5968
5969         if (!iscan->iscan_ex_params_p) {
5970                 return -EFAULT;
5971         }
5972
5973         if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
5974                 return -ENOMEM;
5975
5976         if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
5977                 res = -EFAULT;
5978                 goto exit_proc;
5979         }
5980
5981         extra[wrqu->data.length] = 0;
5982         WL_ERROR(("Got str param in iw_point:\n %s\n", extra));
5983
5984         str_ptr = extra;
5985
5986         
5987         if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) {
5988                 WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__));
5989                 res = -EINVAL;
5990                 goto exit_proc;
5991         }
5992
5993         str_ptr += strlen(GET_SSID);
5994         nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid,
5995                                       WL_SCAN_PARAMS_SSID_MAX);
5996         if (nssid == -1) {
5997                 WL_ERROR(("%s wrong ssid list", __FUNCTION__));
5998                 res = -EINVAL;
5999                 goto exit_proc;
6000         }
6001
6002         memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
6003         ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN);
6004
6005         
6006         wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
6007         iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
6008         iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
6009         iscan->iscan_ex_params_p->scan_duration = htod16(0);
6010
6011         
6012         if ((nchan = wl_iw_parse_channel_list(&str_ptr,
6013                                               &iscan->iscan_ex_params_p->params.channel_list[0],
6014                                               WL_NUMCHANNELS)) == -1) {
6015                 WL_ERROR(("%s missing channel list\n", __FUNCTION__));
6016                 res = -EINVAL;
6017                 goto exit_proc;
6018         }
6019
6020         
6021         get_parameter_from_string(&str_ptr,
6022                                   GET_NPROBE, PTYPE_INTDEC,
6023                                   &iscan->iscan_ex_params_p->params.nprobes, 2);
6024
6025         get_parameter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC,
6026                                   &iscan->iscan_ex_params_p->params.active_time, 4);
6027
6028         get_parameter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC,
6029                                   &iscan->iscan_ex_params_p->params.passive_time, 4);
6030
6031         get_parameter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC,
6032                                   &iscan->iscan_ex_params_p->params.home_time, 4);
6033
6034         get_parameter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC,
6035                                   &iscan->iscan_ex_params_p->params.scan_type, 1);
6036
6037         
6038         res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
6039
6040 exit_proc:
6041         kfree(extra);
6042
6043         return res;
6044 }
6045
6046
6047 static int
6048 wl_iw_set_cscan(
6049         struct net_device *dev,
6050         struct iw_request_info *info,
6051         union iwreq_data *wrqu,
6052         char *extra
6053 )
6054 {
6055         int res = -1;
6056         iscan_info_t *iscan = g_iscan;
6057         wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
6058         int nssid = 0;
6059         int nchan = 0;
6060         cscan_tlv_t *cscan_tlv_temp;
6061         char type;
6062         char *str_ptr;
6063         int tlv_size_left;
6064 #ifdef TLV_DEBUG
6065         int i;
6066         char tlv_in_example[] = {
6067                 'C', 'S', 'C', 'A', 'N', ' ',
6068                 0x53, 0x01, 0x00, 0x00,
6069                 'S',      
6070                 0x00, 
6071                 'S',    
6072                 0x04, 
6073                 'B', 'R', 'C', 'M',
6074                 'C',
6075                 0x06, 
6076                 'P', 
6077                 0x94,
6078                 0x11,
6079                 'T',     
6080                 0x01  
6081         };
6082 #endif 
6083
6084         WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
6085                 __FUNCTION__, info->cmd, info->flags,
6086                 wrqu->data.pointer, wrqu->data.length));
6087
6088         net_os_wake_lock(dev);
6089
6090         if (g_onoff == G_WLAN_SET_OFF) {
6091                 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
6092                 return -1;
6093         }
6094
6095         if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
6096                 WL_ERROR(("%s argument=%d  less %d\n", __FUNCTION__,
6097                           wrqu->data.length, (int)(strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))));
6098                 return -1;
6099         }
6100
6101 #ifdef TLV_DEBUG
6102         memcpy(extra, tlv_in_example, sizeof(tlv_in_example));
6103         wrqu->data.length = sizeof(tlv_in_example);
6104         for (i = 0; i < wrqu->data.length; i++)
6105                 printf("%02X ", extra[i]);
6106         printf("\n");
6107 #endif 
6108
6109         str_ptr = extra;
6110         str_ptr +=  strlen(CSCAN_COMMAND);
6111         tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND);
6112
6113         cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
6114         memset(ssids_local, 0, sizeof(ssids_local));
6115         
6116         if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) &&
6117                 (cscan_tlv_temp->version == CSCAN_TLV_VERSION) &&
6118                 (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
6119         {
6120                 str_ptr += sizeof(cscan_tlv_t);
6121                 tlv_size_left  -= sizeof(cscan_tlv_t);
6122
6123                 
6124                 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
6125                         WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
6126                         WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
6127                         goto exit_proc;
6128                 }
6129                 else {
6130                         
6131                         memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
6132
6133                         
6134                         wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
6135                         iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
6136                         iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
6137                         iscan->iscan_ex_params_p->scan_duration = htod16(0);
6138
6139                         
6140                         while (tlv_size_left > 0)
6141                         {
6142                         type = str_ptr[0];
6143                         switch (type) {
6144                                 case CSCAN_TLV_TYPE_CHANNEL_IE:
6145                                         
6146                                         if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr,
6147                                         &iscan->iscan_ex_params_p->params.channel_list[0],
6148                                         WL_NUMCHANNELS, &tlv_size_left)) == -1) {
6149                                         WL_ERROR(("%s missing channel list\n",
6150                                                 __FUNCTION__));
6151                                                 goto exit_proc;
6152                                         }
6153                                 break;
6154                                 case CSCAN_TLV_TYPE_NPROBE_IE:
6155                                         if ((res = wl_iw_parse_data_tlv(&str_ptr,
6156                                                 &iscan->iscan_ex_params_p->params.nprobes,
6157                                                 sizeof(iscan->iscan_ex_params_p->params.nprobes),
6158                                                 type, sizeof(char), &tlv_size_left)) == -1) {
6159                                                 WL_ERROR(("%s return %d\n",
6160                                                         __FUNCTION__, res));
6161                                                         goto exit_proc;
6162                                         }
6163                                 break;
6164                                 case CSCAN_TLV_TYPE_ACTIVE_IE:
6165                                         if ((res = wl_iw_parse_data_tlv(&str_ptr,
6166                                         &iscan->iscan_ex_params_p->params.active_time,
6167                                         sizeof(iscan->iscan_ex_params_p->params.active_time),
6168                                         type, sizeof(short), &tlv_size_left)) == -1) {
6169                                                 WL_ERROR(("%s return %d\n",
6170                                                 __FUNCTION__, res));
6171                                                 goto exit_proc;
6172                                         }
6173                                 break;
6174                                 case CSCAN_TLV_TYPE_PASSIVE_IE:
6175                                         if ((res = wl_iw_parse_data_tlv(&str_ptr,
6176                                         &iscan->iscan_ex_params_p->params.passive_time,
6177                                         sizeof(iscan->iscan_ex_params_p->params.passive_time),
6178                                         type, sizeof(short), &tlv_size_left)) == -1) {
6179                                                 WL_ERROR(("%s return %d\n",
6180                                                 __FUNCTION__, res));
6181                                                 goto exit_proc;
6182                                         }
6183                                 break;
6184                                 case CSCAN_TLV_TYPE_HOME_IE:
6185                                         if ((res = wl_iw_parse_data_tlv(&str_ptr,
6186                                         &iscan->iscan_ex_params_p->params.home_time,
6187                                         sizeof(iscan->iscan_ex_params_p->params.home_time),
6188                                         type, sizeof(short), &tlv_size_left)) == -1) {
6189                                                 WL_ERROR(("%s return %d\n",
6190                                                 __FUNCTION__, res));
6191                                                 goto exit_proc;
6192                                         }
6193                                 break;
6194                                 case CSCAN_TLV_TYPE_STYPE_IE:
6195                                         if ((res = wl_iw_parse_data_tlv(&str_ptr,
6196                                         &iscan->iscan_ex_params_p->params.scan_type,
6197                                         sizeof(iscan->iscan_ex_params_p->params.scan_type),
6198                                         type, sizeof(char), &tlv_size_left)) == -1) {
6199                                         WL_ERROR(("%s return %d\n",
6200                                                 __FUNCTION__, res));
6201                                                 goto exit_proc;
6202                                         }
6203                                 break;
6204
6205                                 default :
6206                                         WL_ERROR(("%s get unkwown type %X\n",
6207                                         __FUNCTION__, type));
6208                                         goto exit_proc;
6209                                 break;
6210                                 }
6211                         } 
6212                         }
6213                 }
6214                 else {
6215                         WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
6216                         goto exit_proc;
6217                 }
6218
6219 #if defined(CONFIG_FIRST_SCAN)
6220                 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
6221                         if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
6222                                 
6223                                 WL_ERROR(("%s Clean up First scan flag which is %d\n",
6224                                         __FUNCTION__, g_first_broadcast_scan));
6225                                 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
6226                         }
6227                         else {
6228                                 WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n",
6229                                         __FUNCTION__, g_first_counter_scans));
6230                                 return -EBUSY;
6231                         }
6232                 }
6233 #endif 
6234
6235                 
6236                 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
6237
6238 exit_proc:
6239         net_os_wake_unlock(dev);
6240         return res;
6241 }
6242
6243 #endif 
6244
6245
6246
6247 #ifdef SOFTAP
6248 #ifndef AP_ONLY
6249
6250
6251 static int
6252 thr_wait_for_2nd_eth_dev(void *data)
6253 {
6254         wl_iw_t *iw;
6255         int ret = 0;
6256         unsigned long flags = 0;
6257
6258         tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
6259         struct net_device *dev = (struct net_device *)tsk_ctl->parent;
6260         iw = *(wl_iw_t **)netdev_priv(dev);
6261
6262         DAEMONIZE("wl0_eth_wthread");
6263
6264
6265         WL_SOFTAP(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid));
6266
6267 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
6268         if (!iw) {
6269                 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6270                 tsk_ctl->thr_pid = -1;
6271                 complete(&tsk_ctl->completed);
6272                 return -1;
6273         }
6274         DHD_OS_WAKE_LOCK(iw->pub);
6275         complete(&tsk_ctl->completed);
6276         if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(1000)) != 0) {
6277 #else
6278         if (down_interruptible(&tsk_ctl->sema) != 0) {
6279 #endif 
6280                 WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__));
6281                 ret = -1;
6282                 goto fail;
6283         }
6284
6285         SMP_RD_BARRIER_DEPENDS();
6286         if (tsk_ctl->terminated) {
6287                         ret = -1;
6288                         goto fail;
6289         }
6290
6291         flags = dhd_os_spin_lock(iw->pub);
6292         if (!ap_net_dev) {
6293                 WL_ERROR((" ap_net_dev is null !!!"));
6294                 ret = -1;
6295                 dhd_os_spin_unlock(iw->pub, flags);
6296                 goto fail;
6297         }
6298
6299         WL_SOFTAP(("\n>%s: Thread:'softap ethdev IF:%s is detected!'\n\n",
6300                 __FUNCTION__, ap_net_dev->name));
6301
6302         ap_cfg_running = TRUE;
6303
6304         dhd_os_spin_unlock(iw->pub, flags);
6305         bcm_mdelay(500); 
6306
6307         
6308         wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK");
6309
6310 fail:
6311
6312         DHD_OS_WAKE_UNLOCK(iw->pub);
6313
6314         WL_SOFTAP(("\n>%s, thread completed\n", __FUNCTION__));
6315
6316         complete_and_exit(&tsk_ctl->completed, 0);
6317         return ret;
6318 }
6319 #endif 
6320 #ifndef AP_ONLY
6321 static int last_auto_channel = 6;
6322 #endif
6323
6324 static int
6325 get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap)
6326 {
6327         int chosen = 0;
6328         wl_uint32_list_t request;
6329         int retry = 0;
6330         int updown = 0;
6331         int ret = 0;
6332         wlc_ssid_t null_ssid;
6333         int res = 0;
6334 #ifndef AP_ONLY
6335  &