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