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