]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/brcm80211/brcmfmac/wl_iw.c
staging: brcm80211: removed wl_ (vendor specific acronym)
[mv-sheeva.git] / drivers / staging / brcm80211 / brcmfmac / wl_iw.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/kthread.h>
18 #include <linux/semaphore.h>
19 #include <bcmdefs.h>
20 #include <linux/netdevice.h>
21 #include <linux/etherdevice.h>
22 #include <linux/wireless.h>
23
24 #include <bcmutils.h>
25 #include <bcmwifi.h>
26
27 #include <linux/if_arp.h>
28 #include <asm/uaccess.h>
29
30 #include <dngl_stats.h>
31 #include <dhd.h>
32 #include <linux/ieee80211.h>
33
34 struct si_pub;
35
36 #include <dngl_stats.h>
37 #include <dhd.h>
38
39 #define WPA_OUI                 "\x00\x50\xF2"
40 #define DOT11_MNG_RSN_ID                        48
41 #define DOT11_MNG_WPA_ID                        221
42
43 #define WL_ERROR(fmt, args...)  printk(fmt, ##args)
44 #define WL_TRACE(fmt, args...)  no_printk(fmt, ##args)
45 #define WL_INFORM(fmt, args...) no_printk(fmt, ##args)
46 #define WL_WSEC(fmt, args...)   no_printk(fmt, ##args)
47 #define WL_SCAN(fmt, args...)   no_printk(fmt, ##args)
48
49 #include <wl_iw.h>
50
51 #define IW_WSEC_ENABLED(wsec)   ((wsec) & (WEP_ENABLED |        \
52                                          TKIP_ENABLED | AES_ENABLED))
53
54 #include <linux/rtnetlink.h>
55
56 #define WL_IW_USE_ISCAN  1
57 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS  1
58
59 bool g_set_essid_before_scan = true;
60
61 #define WL_IW_IOCTL_CALL(func_call) \
62         do {                            \
63                 func_call;              \
64         } while (0)
65
66 static int g_onoff = G_WLAN_SET_ON;
67 wl_iw_extra_params_t g_wl_iw_params;
68
69 extern bool wl_iw_conn_status_str(u32 event_type, u32 status,
70                                   u32 reason, char *stringBuf, uint buflen);
71
72 uint brcm_msg_level = LOG_ERROR_VAL;
73
74 #define MAX_WLIW_IOCTL_LEN 1024
75
76 #ifdef CONFIG_WIRELESS_EXT
77 extern int dhd_wait_pend8021x(struct net_device *dev);
78 #endif
79
80 #if WIRELESS_EXT < 19
81 #define IW_IOCTL_IDX(cmd)       ((cmd) - SIOCIWFIRST)
82 #define IW_EVENT_IDX(cmd)       ((cmd) - IWEVFIRST)
83 #endif
84
85 static void *g_scan;
86 static volatile uint g_scan_specified_ssid;
87 static wlc_ssid_t g_specific_ssid;
88
89 static wlc_ssid_t g_ssid;
90
91 #if defined(WL_IW_USE_ISCAN)
92 #define ISCAN_STATE_IDLE   0
93 #define ISCAN_STATE_SCANING 1
94
95 #define WLC_IW_ISCAN_MAXLEN   2048
96 typedef struct iscan_buf {
97         struct iscan_buf *next;
98         char iscan_buf[WLC_IW_ISCAN_MAXLEN];
99 } iscan_buf_t;
100
101 typedef struct iscan_info {
102         struct net_device *dev;
103         struct timer_list timer;
104         u32 timer_ms;
105         u32 timer_on;
106         int iscan_state;
107         iscan_buf_t *list_hdr;
108         iscan_buf_t *list_cur;
109
110         struct task_struct *sysioc_tsk;
111         struct semaphore sysioc_sem;
112
113 #if defined CSCAN
114         char ioctlbuf[WLC_IOCTL_MEDLEN];
115 #else
116         char ioctlbuf[WLC_IOCTL_SMLEN];
117 #endif
118         wl_iscan_params_t *iscan_ex_params_p;
119         int iscan_ex_param_size;
120 } iscan_info_t;
121 iscan_info_t *g_iscan;
122
123 typedef enum sup_auth_status {
124         WLC_SUP_DISCONNECTED = 0,
125         WLC_SUP_CONNECTING,
126         WLC_SUP_IDREQUIRED,
127         WLC_SUP_AUTHENTICATING,
128         WLC_SUP_AUTHENTICATED,
129         WLC_SUP_KEYXCHANGE,
130         WLC_SUP_KEYED,
131         WLC_SUP_TIMEOUT,
132         WLC_SUP_LAST_BASIC_STATE,
133         WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED,
134         WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE,
135         WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE,
136         WLC_SUP_KEYXCHANGE_PREP_M4,
137         WLC_SUP_KEYXCHANGE_WAIT_G1,
138         WLC_SUP_KEYXCHANGE_PREP_G2
139 } sup_auth_status_t;
140
141 static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
142
143 /* Global ASSERT type flag */
144 u32 g_assert_type;
145
146 static void wl_iw_timerfunc(unsigned long data);
147 static void wl_iw_set_event_mask(struct net_device *dev);
148 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action);
149 #endif                          /* defined(WL_IW_USE_ISCAN) */
150
151 static int
152 wl_iw_set_scan(struct net_device *dev,
153                struct iw_request_info *info,
154                union iwreq_data *wrqu, char *extra);
155
156 static int
157 wl_iw_get_scan(struct net_device *dev,
158                struct iw_request_info *info,
159                struct iw_point *dwrq, char *extra);
160
161 static uint
162 wl_iw_get_scan_prep(wl_scan_results_t *list,
163                     struct iw_request_info *info, char *extra, short max_size);
164
165 static void swap_key_from_BE(wl_wsec_key_t *key)
166 {
167         key->index = cpu_to_le32(key->index);
168         key->len = cpu_to_le32(key->len);
169         key->algo = cpu_to_le32(key->algo);
170         key->flags = cpu_to_le32(key->flags);
171         key->rxiv.hi = cpu_to_le32(key->rxiv.hi);
172         key->rxiv.lo = cpu_to_le16(key->rxiv.lo);
173         key->iv_initialized = cpu_to_le32(key->iv_initialized);
174 }
175
176 static void swap_key_to_BE(wl_wsec_key_t *key)
177 {
178         key->index = le32_to_cpu(key->index);
179         key->len = le32_to_cpu(key->len);
180         key->algo = le32_to_cpu(key->algo);
181         key->flags = le32_to_cpu(key->flags);
182         key->rxiv.hi = le32_to_cpu(key->rxiv.hi);
183         key->rxiv.lo = le16_to_cpu(key->rxiv.lo);
184         key->iv_initialized = le32_to_cpu(key->iv_initialized);
185 }
186
187 static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
188 {
189         struct ifreq ifr;
190         wl_ioctl_t ioc;
191         mm_segment_t fs;
192         int ret = -EINVAL;
193
194         if (!dev) {
195                 WL_ERROR("%s: dev is null\n", __func__);
196                 return ret;
197         }
198
199         WL_INFORM("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d\n",
200                   __func__, current->pid, cmd, arg, len);
201
202         if (g_onoff == G_WLAN_SET_ON) {
203                 memset(&ioc, 0, sizeof(ioc));
204                 ioc.cmd = cmd;
205                 ioc.buf = arg;
206                 ioc.len = len;
207
208                 strcpy(ifr.ifr_name, dev->name);
209                 ifr.ifr_data = (caddr_t)&ioc;
210
211                 ret = dev_open(dev);
212                 if (ret) {
213                         WL_ERROR("%s: Error dev_open: %d\n", __func__, ret);
214                         return ret;
215                 }
216
217                 fs = get_fs();
218                 set_fs(get_ds());
219                 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
220                 set_fs(fs);
221         } else {
222                 WL_TRACE("%s: call after driver stop : ignored\n", __func__);
223         }
224         return ret;
225 }
226
227 static int dev_wlc_intvar_set(struct net_device *dev, char *name, int val)
228 {
229         char buf[WLC_IOCTL_SMLEN];
230         uint len;
231
232         val = cpu_to_le32(val);
233         len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
234         ASSERT(len);
235
236         return dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len);
237 }
238
239 #if defined(WL_IW_USE_ISCAN)
240 static int
241 dev_iw_iovar_setbuf(struct net_device *dev,
242                     char *iovar,
243                     void *param, int paramlen, void *bufptr, int buflen)
244 {
245         int iolen;
246
247         iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
248         ASSERT(iolen);
249
250         if (iolen == 0)
251                 return 0;
252
253         return dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
254 }
255
256 static int
257 dev_iw_iovar_getbuf(struct net_device *dev,
258                     char *iovar,
259                     void *param, int paramlen, void *bufptr, int buflen)
260 {
261         int iolen;
262
263         iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
264         ASSERT(iolen);
265
266         return dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen);
267 }
268 #endif                          /* defined(WL_IW_USE_ISCAN) */
269
270 #if WIRELESS_EXT > 17
271 static int
272 dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
273 {
274         static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
275         uint buflen;
276
277         buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
278         ASSERT(buflen);
279
280         return dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen);
281 }
282 #endif                          /* WIRELESS_EXT > 17 */
283
284 static int
285 dev_wlc_bufvar_get(struct net_device *dev, char *name, char *buf, int buflen)
286 {
287         static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
288         int error;
289         uint len;
290
291         len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
292         ASSERT(len);
293         error =
294             dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf,
295                           MAX_WLIW_IOCTL_LEN);
296         if (!error)
297                 memcpy(buf, ioctlbuf, buflen);
298
299         return error;
300 }
301
302 static int dev_wlc_intvar_get(struct net_device *dev, char *name, int *retval)
303 {
304         union {
305                 char buf[WLC_IOCTL_SMLEN];
306                 int val;
307         } var;
308         int error;
309
310         uint len;
311         uint data_null;
312
313         len =
314             bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
315                         sizeof(var.buf));
316         ASSERT(len);
317         error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
318
319         *retval = le32_to_cpu(var.val);
320
321         return error;
322 }
323
324 #if WIRELESS_EXT < 13
325 struct iw_request_info {
326         __u16 cmd;
327         __u16 flags;
328 };
329
330 typedef int (*iw_handler) (struct net_device *dev,
331                            struct iw_request_info *info,
332                            void *wrqu, char *extra);
333 #endif
334
335 static int
336 wl_iw_config_commit(struct net_device *dev,
337                     struct iw_request_info *info, void *zwrq, char *extra)
338 {
339         wlc_ssid_t ssid;
340         int error;
341         struct sockaddr bssid;
342
343         WL_TRACE("%s: SIOCSIWCOMMIT\n", dev->name);
344
345         error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
346         if (error)
347                 return error;
348
349         ssid.SSID_len = le32_to_cpu(ssid.SSID_len);
350
351         if (!ssid.SSID_len)
352                 return 0;
353
354         memset(&bssid, 0, sizeof(struct sockaddr));
355         error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETH_ALEN);
356         if (error) {
357                 WL_ERROR("%s: WLC_REASSOC to %s failed\n",
358                          __func__, ssid.SSID);
359                 return error;
360         }
361
362         return 0;
363 }
364
365 static int
366 wl_iw_get_name(struct net_device *dev,
367                struct iw_request_info *info, char *cwrq, char *extra)
368 {
369         WL_TRACE("%s: SIOCGIWNAME\n", dev->name);
370
371         strcpy(cwrq, "IEEE 802.11-DS");
372
373         return 0;
374 }
375
376 static int
377 wl_iw_set_freq(struct net_device *dev,
378                struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
379 {
380         int error, chan;
381         uint sf = 0;
382
383         WL_TRACE("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name);
384
385         if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
386                 chan = fwrq->m;
387         } else {
388                 if (fwrq->e >= 6) {
389                         fwrq->e -= 6;
390                         while (fwrq->e--)
391                                 fwrq->m *= 10;
392                 } else if (fwrq->e < 6) {
393                         while (fwrq->e++ < 6)
394                                 fwrq->m /= 10;
395                 }
396                 if (fwrq->m > 4000 && fwrq->m < 5000)
397                         sf = WF_CHAN_FACTOR_4_G;
398
399                 chan = bcm_mhz2channel(fwrq->m, sf);
400         }
401         chan = cpu_to_le32(chan);
402
403         error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan));
404         if (error)
405                 return error;
406
407         g_wl_iw_params.target_channel = chan;
408         return -EINPROGRESS;
409 }
410
411 static int
412 wl_iw_get_freq(struct net_device *dev,
413                struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
414 {
415         channel_info_t ci;
416         int error;
417
418         WL_TRACE("%s: SIOCGIWFREQ\n", dev->name);
419
420         error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
421         if (error)
422                 return error;
423
424         fwrq->m = le32_to_cpu(ci.hw_channel);
425         fwrq->e = le32_to_cpu(0);
426         return 0;
427 }
428
429 static int
430 wl_iw_set_mode(struct net_device *dev,
431                struct iw_request_info *info, __u32 *uwrq, char *extra)
432 {
433         int infra = 0, ap = 0, error = 0;
434
435         WL_TRACE("%s: SIOCSIWMODE\n", dev->name);
436
437         switch (*uwrq) {
438         case IW_MODE_MASTER:
439                 infra = ap = 1;
440                 break;
441         case IW_MODE_ADHOC:
442         case IW_MODE_AUTO:
443                 break;
444         case IW_MODE_INFRA:
445                 infra = 1;
446                 break;
447         default:
448                 return -EINVAL;
449         }
450         infra = cpu_to_le32(infra);
451         ap = cpu_to_le32(ap);
452
453         error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra));
454         if (error)
455                 return error;
456
457         error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap));
458         if (error)
459                 return error;
460
461         return -EINPROGRESS;
462 }
463
464 static int
465 wl_iw_get_mode(struct net_device *dev,
466                struct iw_request_info *info, __u32 *uwrq, char *extra)
467 {
468         int error, infra = 0, ap = 0;
469
470         WL_TRACE("%s: SIOCGIWMODE\n", dev->name);
471
472         error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra));
473         if (error)
474                 return error;
475
476         error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap));
477         if (error)
478                 return error;
479
480         infra = le32_to_cpu(infra);
481         ap = le32_to_cpu(ap);
482         *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
483
484         return 0;
485 }
486
487 static int
488 wl_iw_get_range(struct net_device *dev,
489                 struct iw_request_info *info,
490                 struct iw_point *dwrq, char *extra)
491 {
492         struct iw_range *range = (struct iw_range *)extra;
493         wl_u32_list_t *list;
494         wl_rateset_t rateset;
495         s8 *channels;
496         int error, i, k;
497         uint ch;
498
499         int phytype;
500         int bw_cap = 0, sgi_tx = 0, nmode = 0;
501         channel_info_t ci;
502         u8 nrate_list2copy = 0;
503         u16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
504         {14, 29, 43, 58, 87, 116, 130, 144},
505         {27, 54, 81, 108, 162, 216, 243, 270},
506         {30, 60, 90, 120, 180, 240, 270, 300}
507         };
508
509         WL_TRACE("%s: SIOCGIWRANGE\n", dev->name);
510
511         if (!extra)
512                 return -EINVAL;
513
514         channels = kmalloc((MAXCHANNEL + 1) * 4, GFP_KERNEL);
515         if (!channels) {
516                 WL_ERROR("Could not alloc channels\n");
517                 return -ENOMEM;
518         }
519         list = (wl_u32_list_t *) channels;
520
521         dwrq->length = sizeof(struct iw_range);
522         memset(range, 0, sizeof(*range));
523
524         list->count = cpu_to_le32(MAXCHANNEL);
525         error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels,
526                                 (MAXCHANNEL + 1) * 4);
527         if (error) {
528                 kfree(channels);
529                 return error;
530         }
531         for (i = 0; i < le32_to_cpu(list->count) && i < IW_MAX_FREQUENCIES;
532              i++) {
533                 range->freq[i].i = le32_to_cpu(list->element[i]);
534
535                 ch = le32_to_cpu(list->element[i]);
536                 if (ch <= CH_MAX_2G_CHANNEL) {
537                         range->freq[i].m = ieee80211_dsss_chan_to_freq(ch);
538                 } else {
539                         range->freq[i].m = ieee80211_ofdm_chan_to_freq(
540                                                 WF_CHAN_FACTOR_5_G/2, ch);
541                 }
542                 range->freq[i].e = 6;
543         }
544         range->num_frequency = range->num_channels = i;
545
546         range->max_qual.qual = 5;
547         range->max_qual.level = 0x100 - 200;
548         range->max_qual.noise = 0x100 - 200;
549         range->sensitivity = 65535;
550
551 #if WIRELESS_EXT > 11
552         range->avg_qual.qual = 3;
553         range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
554         range->avg_qual.noise = 0x100 - 75;
555 #endif
556
557         error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
558                                 sizeof(rateset));
559         if (error) {
560                 kfree(channels);
561                 return error;
562         }
563         rateset.count = le32_to_cpu(rateset.count);
564         range->num_bitrates = rateset.count;
565         for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
566                 range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000;
567         dev_wlc_intvar_get(dev, "nmode", &nmode);
568         dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
569
570         if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
571                 dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
572                 dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
573                 dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci,
574                               sizeof(channel_info_t));
575                 ci.hw_channel = le32_to_cpu(ci.hw_channel);
576
577                 if (bw_cap == 0 || (bw_cap == 2 && ci.hw_channel <= 14)) {
578                         if (sgi_tx == 0)
579                                 nrate_list2copy = 0;
580                         else
581                                 nrate_list2copy = 1;
582                 }
583                 if (bw_cap == 1 || (bw_cap == 2 && ci.hw_channel >= 36)) {
584                         if (sgi_tx == 0)
585                                 nrate_list2copy = 2;
586                         else
587                                 nrate_list2copy = 3;
588                 }
589                 range->num_bitrates += 8;
590                 for (k = 0; i < range->num_bitrates; k++, i++) {
591                         range->bitrate[i] =
592                             (nrate_list[nrate_list2copy][k]) * 500000;
593                 }
594         }
595
596         error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i));
597         if (error) {
598                 kfree(channels);
599                 return error;
600         }
601         i = le32_to_cpu(i);
602         if (i == WLC_PHY_TYPE_A)
603                 range->throughput = 24000000;
604         else
605                 range->throughput = 1500000;
606
607         range->min_rts = 0;
608         range->max_rts = 2347;
609         range->min_frag = 256;
610         range->max_frag = 2346;
611
612         range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
613         range->num_encoding_sizes = 4;
614         range->encoding_size[0] = WLAN_KEY_LEN_WEP40;
615         range->encoding_size[1] = WLAN_KEY_LEN_WEP104;
616 #if WIRELESS_EXT > 17
617         range->encoding_size[2] = WLAN_KEY_LEN_TKIP;
618 #else
619         range->encoding_size[2] = 0;
620 #endif
621         range->encoding_size[3] = WLAN_KEY_LEN_AES_CMAC;
622
623         range->min_pmp = 0;
624         range->max_pmp = 0;
625         range->min_pmt = 0;
626         range->max_pmt = 0;
627         range->pmp_flags = 0;
628         range->pm_capa = 0;
629
630         range->num_txpower = 2;
631         range->txpower[0] = 1;
632         range->txpower[1] = 255;
633         range->txpower_capa = IW_TXPOW_MWATT;
634
635 #if WIRELESS_EXT > 10
636         range->we_version_compiled = WIRELESS_EXT;
637         range->we_version_source = 19;
638
639         range->retry_capa = IW_RETRY_LIMIT;
640         range->retry_flags = IW_RETRY_LIMIT;
641         range->r_time_flags = 0;
642         range->min_retry = 1;
643         range->max_retry = 255;
644         range->min_r_time = 0;
645         range->max_r_time = 0;
646 #endif
647
648 #if WIRELESS_EXT > 17
649         range->enc_capa = IW_ENC_CAPA_WPA;
650         range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
651         range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
652         range->enc_capa |= IW_ENC_CAPA_WPA2;
653
654         IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
655         IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
656         IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
657         IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
658         IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
659         IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
660 #endif                          /* WIRELESS_EXT > 17 */
661
662         kfree(channels);
663
664         return 0;
665 }
666
667 static int rssi_to_qual(int rssi)
668 {
669         if (rssi <= WL_IW_RSSI_NO_SIGNAL)
670                 return 0;
671         else if (rssi <= WL_IW_RSSI_VERY_LOW)
672                 return 1;
673         else if (rssi <= WL_IW_RSSI_LOW)
674                 return 2;
675         else if (rssi <= WL_IW_RSSI_GOOD)
676                 return 3;
677         else if (rssi <= WL_IW_RSSI_VERY_GOOD)
678                 return 4;
679         else
680                 return 5;
681 }
682
683 static int
684 wl_iw_set_spy(struct net_device *dev,
685               struct iw_request_info *info, struct iw_point *dwrq, char *extra)
686 {
687         wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
688         struct sockaddr *addr = (struct sockaddr *)extra;
689         int i;
690
691         WL_TRACE("%s: SIOCSIWSPY\n", dev->name);
692
693         if (!extra)
694                 return -EINVAL;
695
696         iw->spy_num = min_t(int, ARRAY_SIZE(iw->spy_addr), dwrq->length);
697         for (i = 0; i < iw->spy_num; i++)
698                 memcpy(iw->spy_addr[i], addr[i].sa_data, ETH_ALEN);
699         memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
700
701         return 0;
702 }
703
704 static int
705 wl_iw_get_spy(struct net_device *dev,
706               struct iw_request_info *info, struct iw_point *dwrq, char *extra)
707 {
708         wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
709         struct sockaddr *addr = (struct sockaddr *)extra;
710         struct iw_quality *qual = (struct iw_quality *)&addr[iw->spy_num];
711         int i;
712
713         WL_TRACE("%s: SIOCGIWSPY\n", dev->name);
714
715         if (!extra)
716                 return -EINVAL;
717
718         dwrq->length = iw->spy_num;
719         for (i = 0; i < iw->spy_num; i++) {
720                 memcpy(addr[i].sa_data, iw->spy_addr[i], ETH_ALEN);
721                 addr[i].sa_family = AF_UNIX;
722                 memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
723                 iw->spy_qual[i].updated = 0;
724         }
725
726         return 0;
727 }
728
729 static int
730 wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params,
731                      int *join_params_size)
732 {
733         chanspec_t chanspec = 0;
734
735         if (ch != 0) {
736                 join_params->params.chanspec_num = 1;
737                 join_params->params.chanspec_list[0] = ch;
738
739                 if (join_params->params.chanspec_list[0])
740                         chanspec |= WL_CHANSPEC_BAND_2G;
741                 else
742                         chanspec |= WL_CHANSPEC_BAND_5G;
743
744                 chanspec |= WL_CHANSPEC_BW_20;
745                 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
746
747                 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
748                     join_params->params.chanspec_num * sizeof(chanspec_t);
749
750                 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
751                 join_params->params.chanspec_list[0] |= chanspec;
752                 join_params->params.chanspec_list[0] =
753                     cpu_to_le16(join_params->params.chanspec_list[0]);
754
755                 join_params->params.chanspec_num =
756                     cpu_to_le32(join_params->params.chanspec_num);
757
758                 WL_TRACE("%s  join_params->params.chanspec_list[0]= %X\n",
759                          __func__, join_params->params.chanspec_list[0]);
760         }
761         return 1;
762 }
763
764 static int
765 wl_iw_set_wap(struct net_device *dev,
766               struct iw_request_info *info, struct sockaddr *awrq, char *extra)
767 {
768         int error = -EINVAL;
769         wl_join_params_t join_params;
770         int join_params_size;
771
772         WL_TRACE("%s: SIOCSIWAP\n", dev->name);
773
774         if (awrq->sa_family != ARPHRD_ETHER) {
775                 WL_ERROR("Invalid Header...sa_family\n");
776                 return -EINVAL;
777         }
778
779         if (is_broadcast_ether_addr(awrq->sa_data) ||
780             is_zero_ether_addr(awrq->sa_data)) {
781                 scb_val_t scbval;
782                 memset(&scbval, 0, sizeof(scb_val_t));
783                 (void)dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
784                                     sizeof(scb_val_t));
785                 return 0;
786         }
787
788         memset(&join_params, 0, sizeof(join_params));
789         join_params_size = sizeof(join_params.ssid);
790
791         memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
792         join_params.ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
793         memcpy(&join_params.params.bssid, awrq->sa_data, ETH_ALEN);
794
795         WL_TRACE("%s  target_channel=%d\n",
796                  __func__, g_wl_iw_params.target_channel);
797         wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
798                              &join_params_size);
799
800         error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
801                                 join_params_size);
802         if (error) {
803                 WL_ERROR("%s Invalid ioctl data=%d\n", __func__, error);
804         }
805
806         if (g_ssid.SSID_len) {
807                 WL_TRACE("%s: join SSID=%s BSSID=%pM ch=%d\n",
808                          __func__, g_ssid.SSID, awrq->sa_data,
809                          g_wl_iw_params.target_channel);
810         }
811
812         memset(&g_ssid, 0, sizeof(g_ssid));
813         return 0;
814 }
815
816 static int
817 wl_iw_get_wap(struct net_device *dev,
818               struct iw_request_info *info, struct sockaddr *awrq, char *extra)
819 {
820         WL_TRACE("%s: SIOCGIWAP\n", dev->name);
821
822         awrq->sa_family = ARPHRD_ETHER;
823         memset(awrq->sa_data, 0, ETH_ALEN);
824
825         (void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETH_ALEN);
826
827         return 0;
828 }
829
830 #if WIRELESS_EXT > 17
831 static int
832 wl_iw_mlme(struct net_device *dev,
833            struct iw_request_info *info, struct sockaddr *awrq, char *extra)
834 {
835         struct iw_mlme *mlme;
836         scb_val_t scbval;
837         int error = -EINVAL;
838
839         WL_TRACE("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name);
840
841         mlme = (struct iw_mlme *)extra;
842         if (mlme == NULL) {
843                 WL_ERROR("Invalid ioctl data\n");
844                 return error;
845         }
846
847         scbval.val = mlme->reason_code;
848         memcpy(&scbval.ea, &mlme->addr.sa_data, ETH_ALEN);
849
850         if (mlme->cmd == IW_MLME_DISASSOC) {
851                 scbval.val = cpu_to_le32(scbval.val);
852                 error =
853                     dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
854                                   sizeof(scb_val_t));
855         } else if (mlme->cmd == IW_MLME_DEAUTH) {
856                 scbval.val = cpu_to_le32(scbval.val);
857                 error =
858                     dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
859                                   &scbval, sizeof(scb_val_t));
860         } else {
861                 WL_ERROR("Invalid ioctl data\n");
862                 return error;
863         }
864
865         return error;
866 }
867 #endif                          /* WIRELESS_EXT > 17 */
868
869 #ifndef WL_IW_USE_ISCAN
870 static int
871 wl_iw_get_aplist(struct net_device *dev,
872                  struct iw_request_info *info,
873                  struct iw_point *dwrq, char *extra)
874 {
875         wl_scan_results_t *list;
876         struct sockaddr *addr = (struct sockaddr *)extra;
877         struct iw_quality qual[IW_MAX_AP];
878         wl_bss_info_t *bi = NULL;
879         int error, i;
880         uint buflen = dwrq->length;
881
882         WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
883
884         if (!extra)
885                 return -EINVAL;
886
887         list = kzalloc(buflen, GFP_KERNEL);
888         if (!list)
889                 return -ENOMEM;
890         list->buflen = cpu_to_le32(buflen);
891         error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen);
892         if (error) {
893                 WL_ERROR("%d: Scan results error %d\n", __LINE__, error);
894                 kfree(list);
895                 return error;
896         }
897         list->buflen = le32_to_cpu(list->buflen);
898         list->version = le32_to_cpu(list->version);
899         list->count = le32_to_cpu(list->count);
900         if (list->version != WL_BSS_INFO_VERSION) {
901                 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
902                          __func__, list->version);
903                 kfree(list);
904                 return -EINVAL;
905         }
906
907         for (i = 0, dwrq->length = 0;
908              i < list->count && dwrq->length < IW_MAX_AP; i++) {
909                 bi = bi ? (wl_bss_info_t *) ((unsigned long)bi +
910                                              le32_to_cpu(bi->length)) : list->
911                     bss_info;
912                 ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
913                        ((unsigned long)list + buflen));
914
915                 if (!(le16_to_cpu(bi->capability) & WLAN_CAPABILITY_ESS))
916                         continue;
917
918                 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETH_ALEN);
919                 addr[dwrq->length].sa_family = ARPHRD_ETHER;
920                 qual[dwrq->length].qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
921                 qual[dwrq->length].level = 0x100 + le16_to_cpu(bi->RSSI);
922                 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
923
924 #if WIRELESS_EXT > 18
925                 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
926 #else
927                 qual[dwrq->length].updated = 7;
928 #endif
929                 dwrq->length++;
930         }
931
932         kfree(list);
933
934         if (dwrq->length) {
935                 memcpy(&addr[dwrq->length], qual,
936                        sizeof(struct iw_quality) * dwrq->length);
937                 dwrq->flags = 1;
938         }
939
940         return 0;
941 }
942 #endif                          /* WL_IW_USE_ISCAN */
943
944 #ifdef WL_IW_USE_ISCAN
945 static int
946 wl_iw_iscan_get_aplist(struct net_device *dev,
947                        struct iw_request_info *info,
948                        struct iw_point *dwrq, char *extra)
949 {
950         wl_scan_results_t *list;
951         iscan_buf_t *buf;
952         iscan_info_t *iscan = g_iscan;
953
954         struct sockaddr *addr = (struct sockaddr *)extra;
955         struct iw_quality qual[IW_MAX_AP];
956         wl_bss_info_t *bi = NULL;
957         int i;
958
959         WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
960
961         if (!extra)
962                 return -EINVAL;
963
964         if ((!iscan) || (!iscan->sysioc_tsk)) {
965                 WL_ERROR("%s error\n", __func__);
966                 return 0;
967         }
968
969         buf = iscan->list_hdr;
970         while (buf) {
971                 list = &((wl_iscan_results_t *) buf->iscan_buf)->results;
972                 if (list->version != WL_BSS_INFO_VERSION) {
973                         WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
974                                  __func__, list->version);
975                         return -EINVAL;
976                 }
977
978                 bi = NULL;
979                 for (i = 0, dwrq->length = 0;
980                      i < list->count && dwrq->length < IW_MAX_AP; i++) {
981                         bi = bi ? (wl_bss_info_t *) ((unsigned long)bi +
982                                                      le32_to_cpu(bi->length)) :
983                             list->bss_info;
984                         ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
985                                ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
986
987                         if (!(le16_to_cpu(bi->capability) &
988                               WLAN_CAPABILITY_ESS))
989                                 continue;
990
991                         memcpy(addr[dwrq->length].sa_data, &bi->BSSID,
992                                ETH_ALEN);
993                         addr[dwrq->length].sa_family = ARPHRD_ETHER;
994                         qual[dwrq->length].qual =
995                             rssi_to_qual(le16_to_cpu(bi->RSSI));
996                         qual[dwrq->length].level = 0x100 +
997                                                         le16_to_cpu(bi->RSSI);
998                         qual[dwrq->length].noise = 0x100 + bi->phy_noise;
999
1000 #if WIRELESS_EXT > 18
1001                         qual[dwrq->length].updated =
1002                             IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1003 #else
1004                         qual[dwrq->length].updated = 7;
1005 #endif
1006
1007                         dwrq->length++;
1008                 }
1009                 buf = buf->next;
1010         }
1011         if (dwrq->length) {
1012                 memcpy(&addr[dwrq->length], qual,
1013                        sizeof(struct iw_quality) * dwrq->length);
1014                 dwrq->flags = 1;
1015         }
1016
1017         return 0;
1018 }
1019
1020 static int wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
1021 {
1022         int err = 0;
1023
1024         memcpy(params->bssid, ether_bcast, ETH_ALEN);
1025         params->bss_type = DOT11_BSSTYPE_ANY;
1026         params->scan_type = 0;
1027         params->nprobes = -1;
1028         params->active_time = -1;
1029         params->passive_time = -1;
1030         params->home_time = -1;
1031         params->channel_num = 0;
1032
1033         params->nprobes = cpu_to_le32(params->nprobes);
1034         params->active_time = cpu_to_le32(params->active_time);
1035         params->passive_time = cpu_to_le32(params->passive_time);
1036         params->home_time = cpu_to_le32(params->home_time);
1037         if (ssid && ssid->SSID_len)
1038                 memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
1039
1040         return err;
1041 }
1042
1043 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action)
1044 {
1045         int err = 0;
1046
1047         iscan->iscan_ex_params_p->version = cpu_to_le32(ISCAN_REQ_VERSION);
1048         iscan->iscan_ex_params_p->action = cpu_to_le16(action);
1049         iscan->iscan_ex_params_p->scan_duration = cpu_to_le16(0);
1050
1051         WL_SCAN("%s : nprobes=%d\n",
1052                 __func__, iscan->iscan_ex_params_p->params.nprobes);
1053         WL_SCAN("active_time=%d\n",
1054                  iscan->iscan_ex_params_p->params.active_time);
1055         WL_SCAN("passive_time=%d\n",
1056                  iscan->iscan_ex_params_p->params.passive_time);
1057         WL_SCAN("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time);
1058         WL_SCAN("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type);
1059         WL_SCAN("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type);
1060
1061         (void)dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p,
1062                                   iscan->iscan_ex_param_size, iscan->ioctlbuf,
1063                                   sizeof(iscan->ioctlbuf));
1064
1065         return err;
1066 }
1067
1068 static void wl_iw_timerfunc(unsigned long data)
1069 {
1070         iscan_info_t *iscan = (iscan_info_t *) data;
1071         if (iscan) {
1072                 iscan->timer_on = 0;
1073                 if (iscan->iscan_state != ISCAN_STATE_IDLE) {
1074                         WL_TRACE("timer trigger\n");
1075                         up(&iscan->sysioc_sem);
1076                 }
1077         }
1078 }
1079
1080 static void wl_iw_set_event_mask(struct net_device *dev)
1081 {
1082         char eventmask[WL_EVENTING_MASK_LEN];
1083         char iovbuf[WL_EVENTING_MASK_LEN + 12];
1084
1085         dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
1086         memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
1087         setbit(eventmask, WLC_E_SCAN_COMPLETE);
1088         dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
1089                             iovbuf, sizeof(iovbuf));
1090 }
1091
1092 static u32 wl_iw_iscan_get(iscan_info_t *iscan)
1093 {
1094         iscan_buf_t *buf;
1095         iscan_buf_t *ptr;
1096         wl_iscan_results_t *list_buf;
1097         wl_iscan_results_t list;
1098         wl_scan_results_t *results;
1099         u32 status;
1100         int res = 0;
1101
1102         MUTEX_LOCK_WL_SCAN_SET();
1103         if (iscan->list_cur) {
1104                 buf = iscan->list_cur;
1105                 iscan->list_cur = buf->next;
1106         } else {
1107                 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
1108                 if (!buf) {
1109                         WL_ERROR("%s can't alloc iscan_buf_t : going to abort current iscan\n",
1110                                  __func__);
1111                         MUTEX_UNLOCK_WL_SCAN_SET();
1112                         return WL_SCAN_RESULTS_NO_MEM;
1113                 }
1114                 buf->next = NULL;
1115                 if (!iscan->list_hdr)
1116                         iscan->list_hdr = buf;
1117                 else {
1118                         ptr = iscan->list_hdr;
1119                         while (ptr->next) {
1120                                 ptr = ptr->next;
1121                         }
1122                         ptr->next = buf;
1123                 }
1124         }
1125         memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1126         list_buf = (wl_iscan_results_t *) buf->iscan_buf;
1127         results = &list_buf->results;
1128         results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1129         results->version = 0;
1130         results->count = 0;
1131
1132         memset(&list, 0, sizeof(list));
1133         list.results.buflen = cpu_to_le32(WLC_IW_ISCAN_MAXLEN);
1134         res = dev_iw_iovar_getbuf(iscan->dev,
1135                                   "iscanresults",
1136                                   &list,
1137                                   WL_ISCAN_RESULTS_FIXED_SIZE,
1138                                   buf->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1139         if (res == 0) {
1140                 results->buflen = le32_to_cpu(results->buflen);
1141                 results->version = le32_to_cpu(results->version);
1142                 results->count = le32_to_cpu(results->count);
1143                 WL_TRACE("results->count = %d\n", results->count);
1144                 WL_TRACE("results->buflen = %d\n", results->buflen);
1145                 status = le32_to_cpu(list_buf->status);
1146         } else {
1147                 WL_ERROR("%s returns error %d\n", __func__, res);
1148                 status = WL_SCAN_RESULTS_NO_MEM;
1149         }
1150         MUTEX_UNLOCK_WL_SCAN_SET();
1151         return status;
1152 }
1153
1154 static void wl_iw_force_specific_scan(iscan_info_t *iscan)
1155 {
1156         WL_TRACE("%s force Specific SCAN for %s\n",
1157                  __func__, g_specific_ssid.SSID);
1158         rtnl_lock();
1159
1160         (void)dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid,
1161                             sizeof(g_specific_ssid));
1162
1163         rtnl_unlock();
1164 }
1165
1166 static void wl_iw_send_scan_complete(iscan_info_t *iscan)
1167 {
1168 #ifndef SANDGATE2G
1169         union iwreq_data wrqu;
1170
1171         memset(&wrqu, 0, sizeof(wrqu));
1172
1173         wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
1174         WL_TRACE("Send Event ISCAN complete\n");
1175 #endif
1176 }
1177
1178 static int _iscan_sysioc_thread(void *data)
1179 {
1180         u32 status;
1181         iscan_info_t *iscan = (iscan_info_t *) data;
1182         static bool iscan_pass_abort = false;
1183
1184         allow_signal(SIGTERM);
1185         status = WL_SCAN_RESULTS_PARTIAL;
1186         while (down_interruptible(&iscan->sysioc_sem) == 0) {
1187                 if (kthread_should_stop())
1188                         break;
1189
1190                 if (iscan->timer_on) {
1191                         del_timer_sync(&iscan->timer);
1192                         iscan->timer_on = 0;
1193                 }
1194                 rtnl_lock();
1195                 status = wl_iw_iscan_get(iscan);
1196                 rtnl_unlock();
1197                 if (g_scan_specified_ssid && (iscan_pass_abort == true)) {
1198                         WL_TRACE("%s Get results from specific scan status = %d\n",
1199                                  __func__, status);
1200                         wl_iw_send_scan_complete(iscan);
1201                         iscan_pass_abort = false;
1202                         status = -1;
1203                 }
1204
1205                 switch (status) {
1206                 case WL_SCAN_RESULTS_PARTIAL:
1207                         WL_TRACE("iscanresults incomplete\n");
1208                         rtnl_lock();
1209                         wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
1210                         rtnl_unlock();
1211                         mod_timer(&iscan->timer,
1212                                   jiffies + iscan->timer_ms * HZ / 1000);
1213                         iscan->timer_on = 1;
1214                         break;
1215                 case WL_SCAN_RESULTS_SUCCESS:
1216                         WL_TRACE("iscanresults complete\n");
1217                         iscan->iscan_state = ISCAN_STATE_IDLE;
1218                         wl_iw_send_scan_complete(iscan);
1219                         break;
1220                 case WL_SCAN_RESULTS_PENDING:
1221                         WL_TRACE("iscanresults pending\n");
1222                         mod_timer(&iscan->timer,
1223                                   jiffies + iscan->timer_ms * HZ / 1000);
1224                         iscan->timer_on = 1;
1225                         break;
1226                 case WL_SCAN_RESULTS_ABORTED:
1227                         WL_TRACE("iscanresults aborted\n");
1228                         iscan->iscan_state = ISCAN_STATE_IDLE;
1229                         if (g_scan_specified_ssid == 0)
1230                                 wl_iw_send_scan_complete(iscan);
1231                         else {
1232                                 iscan_pass_abort = true;
1233                                 wl_iw_force_specific_scan(iscan);
1234                         }
1235                         break;
1236                 case WL_SCAN_RESULTS_NO_MEM:
1237                         WL_TRACE("iscanresults can't alloc memory: skip\n");
1238                         iscan->iscan_state = ISCAN_STATE_IDLE;
1239                         break;
1240                 default:
1241                         WL_TRACE("iscanresults returned unknown status %d\n",
1242                                  status);
1243                         break;
1244                 }
1245         }
1246
1247         if (iscan->timer_on) {
1248                 del_timer_sync(&iscan->timer);
1249                 iscan->timer_on = 0;
1250         }
1251         return 0;
1252 }
1253 #endif                          /* WL_IW_USE_ISCAN */
1254
1255 static int
1256 wl_iw_set_scan(struct net_device *dev,
1257                struct iw_request_info *info,
1258                union iwreq_data *wrqu, char *extra)
1259 {
1260         int error;
1261         WL_TRACE("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name);
1262
1263         g_set_essid_before_scan = false;
1264 #if defined(CSCAN)
1265         WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1266         return -EINVAL;
1267 #endif
1268
1269         if (g_onoff == G_WLAN_SET_OFF)
1270                 return 0;
1271
1272         memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
1273 #ifndef WL_IW_USE_ISCAN
1274         g_scan_specified_ssid = 0;
1275 #endif
1276
1277 #if WIRELESS_EXT > 17
1278         if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1279                 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1280                         struct iw_scan_req *req = (struct iw_scan_req *)extra;
1281                         if (g_scan_specified_ssid) {
1282                                 WL_TRACE("%s Specific SCAN is not done ignore scan for = %s\n",
1283                                          __func__, req->essid);
1284                                 return -EBUSY;
1285                         } else {
1286                                 g_specific_ssid.SSID_len = min_t(size_t,
1287                                                 sizeof(g_specific_ssid.SSID),
1288                                                 req->essid_len);
1289                                 memcpy(g_specific_ssid.SSID, req->essid,
1290                                        g_specific_ssid.SSID_len);
1291                                 g_specific_ssid.SSID_len =
1292                                     cpu_to_le32(g_specific_ssid.SSID_len);
1293                                 g_scan_specified_ssid = 1;
1294                                 WL_TRACE("### Specific scan ssid=%s len=%d\n",
1295                                          g_specific_ssid.SSID,
1296                                          g_specific_ssid.SSID_len);
1297                         }
1298                 }
1299         }
1300 #endif                          /* WIRELESS_EXT > 17 */
1301         error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid,
1302                                 sizeof(g_specific_ssid));
1303         if (error) {
1304                 WL_TRACE("#### Set SCAN for %s failed with %d\n",
1305                          g_specific_ssid.SSID, error);
1306                 g_scan_specified_ssid = 0;
1307                 return -EBUSY;
1308         }
1309
1310         return 0;
1311 }
1312
1313 #ifdef WL_IW_USE_ISCAN
1314 int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
1315 {
1316         wlc_ssid_t ssid;
1317         iscan_info_t *iscan = g_iscan;
1318
1319         if (flag)
1320                 rtnl_lock();
1321
1322         wl_iw_set_event_mask(dev);
1323
1324         WL_TRACE("+++: Set Broadcast ISCAN\n");
1325         memset(&ssid, 0, sizeof(ssid));
1326
1327         iscan->list_cur = iscan->list_hdr;
1328         iscan->iscan_state = ISCAN_STATE_SCANING;
1329
1330         memset(&iscan->iscan_ex_params_p->params, 0,
1331                iscan->iscan_ex_param_size);
1332         wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
1333         wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
1334
1335         if (flag)
1336                 rtnl_unlock();
1337
1338         mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
1339
1340         iscan->timer_on = 1;
1341
1342         return 0;
1343 }
1344
1345 static int
1346 wl_iw_iscan_set_scan(struct net_device *dev,
1347                      struct iw_request_info *info,
1348                      union iwreq_data *wrqu, char *extra)
1349 {
1350         wlc_ssid_t ssid;
1351         iscan_info_t *iscan = g_iscan;
1352
1353         WL_TRACE("%s: SIOCSIWSCAN : ISCAN\n", dev->name);
1354
1355 #if defined(CSCAN)
1356         WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1357         return -EINVAL;
1358 #endif
1359
1360         if (g_onoff == G_WLAN_SET_OFF) {
1361                 WL_TRACE("%s: driver is not up yet after START\n", __func__);
1362                 return 0;
1363         }
1364 #ifdef PNO_SUPPORT
1365         if (dhd_dev_get_pno_status(dev)) {
1366                 WL_ERROR("%s: Scan called when PNO is active\n", __func__);
1367         }
1368 #endif
1369
1370         if ((!iscan) || (!iscan->sysioc_tsk))
1371                 return wl_iw_set_scan(dev, info, wrqu, extra);
1372
1373         if (g_scan_specified_ssid) {
1374                 WL_TRACE("%s Specific SCAN already running ignoring BC scan\n",
1375                          __func__);
1376                 return -EBUSY;
1377         }
1378
1379         memset(&ssid, 0, sizeof(ssid));
1380
1381 #if WIRELESS_EXT > 17
1382         if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1383                 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1384                         struct iw_scan_req *req = (struct iw_scan_req *)extra;
1385                         ssid.SSID_len = min_t(size_t, sizeof(ssid.SSID),
1386                                                 req->essid_len);
1387                         memcpy(ssid.SSID, req->essid, ssid.SSID_len);
1388                         ssid.SSID_len = cpu_to_le32(ssid.SSID_len);
1389                 } else {
1390                         g_scan_specified_ssid = 0;
1391
1392                         if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1393                                 WL_TRACE("%s ISCAN already in progress\n",
1394                                          __func__);
1395                                 return 0;
1396                         }
1397                 }
1398         }
1399 #endif                          /* WIRELESS_EXT > 17 */
1400         wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1401
1402         return 0;
1403 }
1404 #endif                          /* WL_IW_USE_ISCAN */
1405
1406 #if WIRELESS_EXT > 17
1407 static bool ie_is_wpa_ie(u8 **wpaie, u8 **tlvs, int *tlvs_len)
1408 {
1409
1410         u8 *ie = *wpaie;
1411
1412         if ((ie[1] >= 6) &&
1413             !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
1414                 return true;
1415         }
1416
1417         ie += ie[1] + 2;
1418         *tlvs_len -= (int)(ie - *tlvs);
1419         *tlvs = ie;
1420         return false;
1421 }
1422
1423 static bool ie_is_wps_ie(u8 **wpsie, u8 **tlvs, int *tlvs_len)
1424 {
1425
1426         u8 *ie = *wpsie;
1427
1428         if ((ie[1] >= 4) &&
1429             !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
1430                 return true;
1431         }
1432
1433         ie += ie[1] + 2;
1434         *tlvs_len -= (int)(ie - *tlvs);
1435         *tlvs = ie;
1436         return false;
1437 }
1438 #endif                          /* WIRELESS_EXT > 17 */
1439
1440 static int
1441 wl_iw_handle_scanresults_ies(char **event_p, char *end,
1442                              struct iw_request_info *info, wl_bss_info_t *bi)
1443 {
1444 #if WIRELESS_EXT > 17
1445         struct iw_event iwe;
1446         char *event;
1447
1448         event = *event_p;
1449         if (bi->ie_length) {
1450                 bcm_tlv_t *ie;
1451                 u8 *ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1452                 int ptr_len = bi->ie_length;
1453
1454                 ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID);
1455                 if (ie) {
1456                         iwe.cmd = IWEVGENIE;
1457                         iwe.u.data.length = ie->len + 2;
1458                         event =
1459                             IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1460                                                  (char *)ie);
1461                 }
1462                 ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1463
1464                 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
1465                         if (ie_is_wps_ie(((u8 **)&ie), &ptr, &ptr_len)) {
1466                                 iwe.cmd = IWEVGENIE;
1467                                 iwe.u.data.length = ie->len + 2;
1468                                 event =
1469                                     IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1470                                                          (char *)ie);
1471                                 break;
1472                         }
1473                 }
1474
1475                 ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1476                 ptr_len = bi->ie_length;
1477                 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
1478                         if (ie_is_wpa_ie(((u8 **)&ie), &ptr, &ptr_len)) {
1479                                 iwe.cmd = IWEVGENIE;
1480                                 iwe.u.data.length = ie->len + 2;
1481                                 event =
1482                                     IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1483                                                          (char *)ie);
1484                                 break;
1485                         }
1486                 }
1487
1488                 *event_p = event;
1489         }
1490 #endif          /* WIRELESS_EXT > 17 */
1491         return 0;
1492 }
1493
1494 static uint
1495 wl_iw_get_scan_prep(wl_scan_results_t *list,
1496                     struct iw_request_info *info, char *extra, short max_size)
1497 {
1498         int i, j;
1499         struct iw_event iwe;
1500         wl_bss_info_t *bi = NULL;
1501         char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
1502         int ret = 0;
1503
1504         ASSERT(list);
1505
1506         for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
1507                 if (list->version != WL_BSS_INFO_VERSION) {
1508                         WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1509                                  __func__, list->version);
1510                         return ret;
1511                 }
1512
1513                 bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1514                                              le32_to_cpu(bi->length)) : list->
1515                     bss_info;
1516
1517                 WL_TRACE("%s : %s\n", __func__, bi->SSID);
1518
1519                 iwe.cmd = SIOCGIWAP;
1520                 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1521                 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETH_ALEN);
1522                 event =
1523                     IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1524                                          IW_EV_ADDR_LEN);
1525                 iwe.u.data.length = le32_to_cpu(bi->SSID_len);
1526                 iwe.cmd = SIOCGIWESSID;
1527                 iwe.u.data.flags = 1;
1528                 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
1529
1530                 if (le16_to_cpu(bi->capability) & (WLAN_CAPABILITY_ESS |
1531                     WLAN_CAPABILITY_IBSS)) {
1532                         iwe.cmd = SIOCGIWMODE;
1533                         if (le16_to_cpu(bi->capability) & WLAN_CAPABILITY_ESS)
1534                                 iwe.u.mode = IW_MODE_INFRA;
1535                         else
1536                                 iwe.u.mode = IW_MODE_ADHOC;
1537                         event =
1538                             IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1539                                                  IW_EV_UINT_LEN);
1540                 }
1541
1542                 iwe.cmd = SIOCGIWFREQ;
1543
1544                 if (CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL)
1545                         iwe.u.freq.m = ieee80211_dsss_chan_to_freq(
1546                                                 CHSPEC_CHANNEL(bi->chanspec));
1547                 else
1548                         iwe.u.freq.m = ieee80211_ofdm_chan_to_freq(
1549                                                 WF_CHAN_FACTOR_5_G/2,
1550                                                 CHSPEC_CHANNEL(bi->chanspec));
1551
1552                 iwe.u.freq.e = 6;
1553                 event =
1554                     IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1555                                          IW_EV_FREQ_LEN);
1556
1557                 iwe.cmd = IWEVQUAL;
1558                 iwe.u.qual.qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
1559                 iwe.u.qual.level = 0x100 + le16_to_cpu(bi->RSSI);
1560                 iwe.u.qual.noise = 0x100 + bi->phy_noise;
1561                 event =
1562                     IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1563                                          IW_EV_QUAL_LEN);
1564
1565                 wl_iw_handle_scanresults_ies(&event, end, info, bi);
1566
1567                 iwe.cmd = SIOCGIWENCODE;
1568                 if (le16_to_cpu(bi->capability) & WLAN_CAPABILITY_PRIVACY)
1569                         iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1570                 else
1571                         iwe.u.data.flags = IW_ENCODE_DISABLED;
1572                 iwe.u.data.length = 0;
1573                 event =
1574                     IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
1575
1576                 if (bi->rateset.count) {
1577                         if (((event - extra) +
1578                                 IW_EV_LCP_LEN) <= (unsigned long)end) {
1579                                 value = event + IW_EV_LCP_LEN;
1580                                 iwe.cmd = SIOCGIWRATE;
1581                                 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled =
1582                                     0;
1583                                 for (j = 0;
1584                                      j < bi->rateset.count
1585                                      && j < IW_MAX_BITRATES; j++) {
1586                                         iwe.u.bitrate.value =
1587                                             (bi->rateset.rates[j] & 0x7f) *
1588                                             500000;
1589                                         value =
1590                                             IWE_STREAM_ADD_VALUE(info, event,
1591                                                  value, end, &iwe,
1592                                                  IW_EV_PARAM_LEN);
1593                                 }
1594                                 event = value;
1595                         }
1596                 }
1597         }
1598
1599         ret = event - extra;
1600         if (ret < 0) {
1601                 WL_ERROR("==> Wrong size\n");
1602                 ret = 0;
1603         }
1604         WL_TRACE("%s: size=%d bytes prepared\n",
1605                  __func__, (unsigned int)(event - extra));
1606         return (uint)ret;
1607 }
1608
1609 static int
1610 wl_iw_get_scan(struct net_device *dev,
1611                struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1612 {
1613         channel_info_t ci;
1614         wl_scan_results_t *list_merge;
1615         wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
1616         int error;
1617         uint buflen_from_user = dwrq->length;
1618         uint len = G_SCAN_RESULTS;
1619         __u16 len_ret = 0;
1620 #if defined(WL_IW_USE_ISCAN)
1621         iscan_info_t *iscan = g_iscan;
1622         iscan_buf_t *p_buf;
1623 #endif
1624
1625         WL_TRACE("%s: buflen_from_user %d:\n", dev->name, buflen_from_user);
1626
1627         if (!extra) {
1628                 WL_TRACE("%s: wl_iw_get_scan return -EINVAL\n", dev->name);
1629                 return -EINVAL;
1630         }
1631
1632         error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
1633         if (error)
1634                 return error;
1635         ci.scan_channel = le32_to_cpu(ci.scan_channel);
1636         if (ci.scan_channel)
1637                 return -EAGAIN;
1638
1639         if (g_scan_specified_ssid) {
1640                 list = kmalloc(len, GFP_KERNEL);
1641                 if (!list) {
1642                         WL_TRACE("%s: wl_iw_get_scan return -ENOMEM\n",
1643                                  dev->name);
1644                         g_scan_specified_ssid = 0;
1645                         return -ENOMEM;
1646                 }
1647         }
1648
1649         memset(list, 0, len);
1650         list->buflen = cpu_to_le32(len);
1651         error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len);
1652         if (error) {
1653                 WL_ERROR("%s: %s : Scan_results ERROR %d\n",
1654                          dev->name, __func__, error);
1655                 dwrq->length = len;
1656                 if (g_scan_specified_ssid) {
1657                         g_scan_specified_ssid = 0;
1658                         kfree(list);
1659                 }
1660                 return 0;
1661         }
1662         list->buflen = le32_to_cpu(list->buflen);
1663         list->version = le32_to_cpu(list->version);
1664         list->count = le32_to_cpu(list->count);
1665
1666         if (list->version != WL_BSS_INFO_VERSION) {
1667                 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1668                          __func__, list->version);
1669                 if (g_scan_specified_ssid) {
1670                         g_scan_specified_ssid = 0;
1671                         kfree(list);
1672                 }
1673                 return -EINVAL;
1674         }
1675
1676         if (g_scan_specified_ssid) {
1677                 WL_TRACE("%s: Specified scan APs in the list =%d\n",
1678                          __func__, list->count);
1679                 len_ret =
1680                     (__u16) wl_iw_get_scan_prep(list, info, extra,
1681                                                 buflen_from_user);
1682                 kfree(list);
1683
1684 #if defined(WL_IW_USE_ISCAN)
1685                 p_buf = iscan->list_hdr;
1686                 while (p_buf != iscan->list_cur) {
1687                         list_merge =
1688                             &((wl_iscan_results_t *) p_buf->iscan_buf)->results;
1689                         WL_TRACE("%s: Bcast APs list=%d\n",
1690                                  __func__, list_merge->count);
1691                         if (list_merge->count > 0)
1692                                 len_ret +=
1693                                     (__u16) wl_iw_get_scan_prep(list_merge,
1694                                         info, extra + len_ret,
1695                                         buflen_from_user - len_ret);
1696                         p_buf = p_buf->next;
1697                 }
1698 #else
1699                 list_merge = (wl_scan_results_t *) g_scan;
1700                 WL_TRACE("%s: Bcast APs list=%d\n",
1701                          __func__, list_merge->count);
1702                 if (list_merge->count > 0)
1703                         len_ret +=
1704                             (__u16) wl_iw_get_scan_prep(list_merge, info,
1705                                                         extra + len_ret,
1706                                                         buflen_from_user -
1707                                                         len_ret);
1708 #endif                          /* defined(WL_IW_USE_ISCAN) */
1709         } else {
1710                 list = (wl_scan_results_t *) g_scan;
1711                 len_ret =
1712                     (__u16) wl_iw_get_scan_prep(list, info, extra,
1713                                                 buflen_from_user);
1714         }
1715
1716 #if defined(WL_IW_USE_ISCAN)
1717         g_scan_specified_ssid = 0;
1718 #endif
1719         if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
1720                 len = len_ret;
1721
1722         dwrq->length = len;
1723         dwrq->flags = 0;
1724
1725         WL_TRACE("%s return to WE %d bytes APs=%d\n",
1726                  __func__, dwrq->length, list->count);
1727         return 0;
1728 }
1729
1730 #if defined(WL_IW_USE_ISCAN)
1731 static int
1732 wl_iw_iscan_get_scan(struct net_device *dev,
1733                      struct iw_request_info *info,
1734                      struct iw_point *dwrq, char *extra)
1735 {
1736         wl_scan_results_t *list;
1737         struct iw_event iwe;
1738         wl_bss_info_t *bi = NULL;
1739         int ii, j;
1740         int apcnt;
1741         char *event = extra, *end = extra + dwrq->length, *value;
1742         iscan_info_t *iscan = g_iscan;
1743         iscan_buf_t *p_buf;
1744         u32 counter = 0;
1745         u8 channel;
1746
1747         WL_TRACE("%s %s buflen_from_user %d:\n",
1748                  dev->name, __func__, dwrq->length);
1749
1750         if (!extra) {
1751                 WL_TRACE("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
1752                          dev->name);
1753                 return -EINVAL;
1754         }
1755
1756         if ((!iscan) || (!iscan->sysioc_tsk)) {
1757                 WL_ERROR("%ssysioc_tsk\n", __func__);
1758                 return wl_iw_get_scan(dev, info, dwrq, extra);
1759         }
1760
1761         if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1762                 WL_TRACE("%s: SIOCGIWSCAN GET still scanning\n", dev->name);
1763                 return -EAGAIN;
1764         }
1765
1766         WL_TRACE("%s: SIOCGIWSCAN GET broadcast results\n", dev->name);
1767         apcnt = 0;
1768         p_buf = iscan->list_hdr;
1769         while (p_buf != iscan->list_cur) {
1770                 list = &((wl_iscan_results_t *) p_buf->iscan_buf)->results;
1771
1772                 counter += list->count;
1773
1774                 if (list->version != WL_BSS_INFO_VERSION) {
1775                         WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1776                                  __func__, list->version);
1777                         return -EINVAL;
1778                 }
1779
1780                 bi = NULL;
1781                 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP;
1782                      apcnt++, ii++) {
1783                         bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1784                                                      le32_to_cpu(bi->length)) :
1785                             list->bss_info;
1786                         ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
1787                                ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
1788
1789                         if (event + ETH_ALEN + bi->SSID_len +
1790                             IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >=
1791                             end)
1792                                 return -E2BIG;
1793                         iwe.cmd = SIOCGIWAP;
1794                         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1795                         memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID,
1796                                ETH_ALEN);
1797                         event =
1798                             IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1799                                                  IW_EV_ADDR_LEN);
1800
1801                         iwe.u.data.length = le32_to_cpu(bi->SSID_len);
1802                         iwe.cmd = SIOCGIWESSID;
1803                         iwe.u.data.flags = 1;
1804                         event =
1805                             IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1806                                                  bi->SSID);
1807
1808                         if (le16_to_cpu(bi->capability) &
1809                             (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
1810                                 iwe.cmd = SIOCGIWMODE;
1811                                 if (le16_to_cpu(bi->capability) &
1812                                     WLAN_CAPABILITY_ESS)
1813                                         iwe.u.mode = IW_MODE_INFRA;
1814                                 else
1815                                         iwe.u.mode = IW_MODE_ADHOC;
1816                                 event =
1817                                     IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1818                                                          IW_EV_UINT_LEN);
1819                         }
1820
1821                         iwe.cmd = SIOCGIWFREQ;
1822                         channel =
1823                             (bi->ctl_ch ==
1824                              0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
1825
1826                         if (channel <= CH_MAX_2G_CHANNEL)
1827                                 iwe.u.freq.m =
1828                                         ieee80211_dsss_chan_to_freq(channel);
1829                         else
1830                                 iwe.u.freq.m = ieee80211_ofdm_chan_to_freq(
1831                                                         WF_CHAN_FACTOR_5_G/2,
1832                                                         channel);
1833
1834                         iwe.u.freq.e = 6;
1835                         event =
1836                             IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1837                                                  IW_EV_FREQ_LEN);
1838
1839                         iwe.cmd = IWEVQUAL;
1840                         iwe.u.qual.qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
1841                         iwe.u.qual.level = 0x100 + le16_to_cpu(bi->RSSI);
1842                         iwe.u.qual.noise = 0x100 + bi->phy_noise;
1843                         event =
1844                             IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1845                                                  IW_EV_QUAL_LEN);
1846
1847                         wl_iw_handle_scanresults_ies(&event, end, info, bi);
1848
1849                         iwe.cmd = SIOCGIWENCODE;
1850                         if (le16_to_cpu(bi->capability) &
1851                             WLAN_CAPABILITY_PRIVACY)
1852                                 iwe.u.data.flags =
1853                                     IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1854                         else
1855                                 iwe.u.data.flags = IW_ENCODE_DISABLED;
1856                         iwe.u.data.length = 0;
1857                         event =
1858                             IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1859                                                  (char *)event);
1860
1861                         if (bi->rateset.count) {
1862                                 if (event + IW_MAX_BITRATES * IW_EV_PARAM_LEN >=
1863                                     end)
1864                                         return -E2BIG;
1865
1866                                 value = event + IW_EV_LCP_LEN;
1867                                 iwe.cmd = SIOCGIWRATE;
1868                                 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled =
1869                                     0;
1870                                 for (j = 0;
1871                                      j < bi->rateset.count
1872                                      && j < IW_MAX_BITRATES; j++) {
1873                                         iwe.u.bitrate.value =
1874                                             (bi->rateset.rates[j] & 0x7f) *
1875                                             500000;
1876                                         value =
1877                                             IWE_STREAM_ADD_VALUE(info, event,
1878                                                  value, end,
1879                                                  &iwe,
1880                                                  IW_EV_PARAM_LEN);
1881                                 }
1882                                 event = value;
1883                         }
1884                 }
1885                 p_buf = p_buf->next;
1886         }
1887
1888         dwrq->length = event - extra;
1889         dwrq->flags = 0;
1890
1891         WL_TRACE("%s return to WE %d bytes APs=%d\n",
1892                  __func__, dwrq->length, counter);
1893
1894         if (!dwrq->length)
1895                 return -EAGAIN;
1896
1897         return 0;
1898 }
1899 #endif                          /* defined(WL_IW_USE_ISCAN) */
1900
1901 static int
1902 wl_iw_set_essid(struct net_device *dev,
1903                 struct iw_request_info *info,
1904                 struct iw_point *dwrq, char *extra)
1905 {
1906         int error;
1907         wl_join_params_t join_params;
1908         int join_params_size;
1909
1910         WL_TRACE("%s: SIOCSIWESSID\n", dev->name);
1911
1912         if (g_set_essid_before_scan)
1913                 return -EAGAIN;
1914
1915         memset(&g_ssid, 0, sizeof(g_ssid));
1916
1917         CHECK_EXTRA_FOR_NULL(extra);
1918
1919         if (dwrq->length && extra) {
1920 #if WIRELESS_EXT > 20
1921                 g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1922                                         dwrq->length);
1923 #else
1924                 g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1925                                         dwrq->length - 1);
1926 #endif
1927                 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
1928         } else {
1929                 g_ssid.SSID_len = 0;
1930         }
1931         g_ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
1932
1933         memset(&join_params, 0, sizeof(join_params));
1934         join_params_size = sizeof(join_params.ssid);
1935
1936         memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
1937         join_params.ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
1938         memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
1939
1940         wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
1941                              &join_params_size);
1942
1943         error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
1944                                 join_params_size);
1945         if (error)
1946                 WL_ERROR("Invalid ioctl data=%d\n", error);
1947
1948         if (g_ssid.SSID_len) {
1949                 WL_TRACE("%s: join SSID=%s ch=%d\n",
1950                          __func__, g_ssid.SSID, g_wl_iw_params.target_channel);
1951         }
1952         return 0;
1953 }
1954
1955 static int
1956 wl_iw_get_essid(struct net_device *dev,
1957                 struct iw_request_info *info,
1958                 struct iw_point *dwrq, char *extra)
1959 {
1960         wlc_ssid_t ssid;
1961         int error;
1962
1963         WL_TRACE("%s: SIOCGIWESSID\n", dev->name);
1964
1965         if (!extra)
1966                 return -EINVAL;
1967
1968         error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1969         if (error) {
1970                 WL_ERROR("Error getting the SSID\n");
1971                 return error;
1972         }
1973
1974         ssid.SSID_len = le32_to_cpu(ssid.SSID_len);
1975
1976         memcpy(extra, ssid.SSID, ssid.SSID_len);
1977
1978         dwrq->length = ssid.SSID_len;
1979
1980         dwrq->flags = 1;
1981
1982         return 0;
1983 }
1984
1985 static int
1986 wl_iw_set_nick(struct net_device *dev,
1987                struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1988 {
1989         wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
1990
1991         WL_TRACE("%s: SIOCSIWNICKN\n", dev->name);
1992
1993         if (!extra)
1994                 return -EINVAL;
1995
1996         if (dwrq->length > sizeof(iw->nickname))
1997                 return -E2BIG;
1998
1999         memcpy(iw->nickname, extra, dwrq->length);
2000         iw->nickname[dwrq->length - 1] = '\0';
2001
2002         return 0;
2003 }
2004
2005 static int
2006 wl_iw_get_nick(struct net_device *dev,
2007                struct iw_request_info *info, struct iw_point *dwrq, char *extra)
2008 {
2009         wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2010
2011         WL_TRACE("%s: SIOCGIWNICKN\n", dev->name);
2012
2013         if (!extra)
2014                 return -EINVAL;
2015
2016         strcpy(extra, iw->nickname);
2017         dwrq->length = strlen(extra) + 1;
2018
2019         return 0;
2020 }
2021
2022 static int
2023 wl_iw_set_rate(struct net_device *dev,
2024                struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2025 {
2026         wl_rateset_t rateset;
2027         int error, rate, i, error_bg, error_a;
2028
2029         WL_TRACE("%s: SIOCSIWRATE\n", dev->name);
2030
2031         error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
2032                                 sizeof(rateset));
2033         if (error)
2034                 return error;
2035
2036         rateset.count = le32_to_cpu(rateset.count);
2037
2038         if (vwrq->value < 0)
2039                 rate = rateset.rates[rateset.count - 1] & 0x7f;
2040         else if (vwrq->value < rateset.count)
2041                 rate = rateset.rates[vwrq->value] & 0x7f;
2042         else
2043                 rate = vwrq->value / 500000;
2044
2045         if (vwrq->fixed) {
2046                 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
2047                 error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
2048
2049                 if (error_bg && error_a)
2050                         return error_bg | error_a;
2051         } else {
2052                 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
2053                 error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
2054
2055                 if (error_bg && error_a)
2056                         return error_bg | error_a;
2057
2058                 for (i = 0; i < rateset.count; i++)
2059                         if ((rateset.rates[i] & 0x7f) > rate)
2060                                 break;
2061                 rateset.count = cpu_to_le32(i);
2062
2063                 error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset,
2064                                         sizeof(rateset));
2065                 if (error)
2066                         return error;
2067         }
2068
2069         return 0;
2070 }
2071
2072 static int
2073 wl_iw_get_rate(struct net_device *dev,
2074                struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2075 {
2076         int error, rate;
2077
2078         WL_TRACE("%s: SIOCGIWRATE\n", dev->name);
2079
2080         error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate));
2081         if (error)
2082                 return error;
2083         rate = le32_to_cpu(rate);
2084         vwrq->value = rate * 500000;
2085
2086         return 0;
2087 }
2088
2089 static int
2090 wl_iw_set_rts(struct net_device *dev,
2091               struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2092 {
2093         int error, rts;
2094
2095         WL_TRACE("%s: SIOCSIWRTS\n", dev->name);
2096
2097         if (vwrq->disabled)
2098                 rts = DOT11_DEFAULT_RTS_LEN;
2099         else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
2100                 return -EINVAL;
2101         else
2102                 rts = vwrq->value;
2103
2104         error = dev_wlc_intvar_set(dev, "rtsthresh", rts);
2105         if (error)
2106                 return error;
2107
2108         return 0;
2109 }
2110
2111 static int
2112 wl_iw_get_rts(struct net_device *dev,
2113               struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2114 {
2115         int error, rts;
2116
2117         WL_TRACE("%s: SIOCGIWRTS\n", dev->name);
2118
2119         error = dev_wlc_intvar_get(dev, "rtsthresh", &rts);
2120         if (error)
2121                 return error;
2122
2123         vwrq->value = rts;
2124         vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
2125         vwrq->fixed = 1;
2126
2127         return 0;
2128 }
2129
2130 static int
2131 wl_iw_set_frag(struct net_device *dev,
2132                struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2133 {
2134         int error, frag;
2135
2136         WL_TRACE("%s: SIOCSIWFRAG\n", dev->name);
2137
2138         if (vwrq->disabled)
2139                 frag = DOT11_DEFAULT_FRAG_LEN;
2140         else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
2141                 return -EINVAL;
2142         else
2143                 frag = vwrq->value;
2144
2145         error = dev_wlc_intvar_set(dev, "fragthresh", frag);
2146         if (error)
2147                 return error;
2148
2149         return 0;
2150 }
2151
2152 static int
2153 wl_iw_get_frag(struct net_device *dev,
2154                struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2155 {
2156         int error, fragthreshold;
2157
2158         WL_TRACE("%s: SIOCGIWFRAG\n", dev->name);
2159
2160         error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold);
2161         if (error)
2162                 return error;
2163
2164         vwrq->value = fragthreshold;
2165         vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
2166         vwrq->fixed = 1;
2167
2168         return 0;
2169 }
2170
2171 static int
2172 wl_iw_set_txpow(struct net_device *dev,
2173                 struct iw_request_info *info,
2174                 struct iw_param *vwrq, char *extra)
2175 {
2176         int error, disable;
2177         u16 txpwrmw;
2178         WL_TRACE("%s: SIOCSIWTXPOW\n", dev->name);
2179
2180         disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
2181         disable += WL_RADIO_SW_DISABLE << 16;
2182
2183         disable = cpu_to_le32(disable);
2184         error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable));
2185         if (error)
2186                 return error;
2187
2188         if (disable & WL_RADIO_SW_DISABLE)
2189                 return 0;
2190
2191         if (!(vwrq->flags & IW_TXPOW_MWATT))
2192                 return -EINVAL;
2193
2194         if (vwrq->value < 0)
2195                 return 0;
2196
2197         if (vwrq->value > 0xffff)
2198                 txpwrmw = 0xffff;
2199         else
2200                 txpwrmw = (u16) vwrq->value;
2201
2202         error =
2203             dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
2204         return error;
2205 }
2206
2207 static int
2208 wl_iw_get_txpow(struct net_device *dev,
2209                 struct iw_request_info *info,
2210                 struct iw_param *vwrq, char *extra)
2211 {
2212         int error, disable, txpwrdbm;
2213         u8 result;
2214
2215         WL_TRACE("%s: SIOCGIWTXPOW\n", dev->name);
2216
2217         error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable));
2218         if (error)
2219                 return error;
2220
2221         error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm);
2222         if (error)
2223                 return error;
2224
2225         disable = le32_to_cpu(disable);
2226         result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
2227         vwrq->value = (s32) bcm_qdbm_to_mw(result);
2228         vwrq->fixed = 0;
2229         vwrq->disabled =
2230             (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
2231         vwrq->flags = IW_TXPOW_MWATT;
2232
2233         return 0;
2234 }
2235
2236 #if WIRELESS_EXT > 10
2237 static int
2238 wl_iw_set_retry(struct net_device *dev,
2239                 struct iw_request_info *info,
2240                 struct iw_param *vwrq, char *extra)
2241 {
2242         int error, lrl, srl;
2243
2244         WL_TRACE("%s: SIOCSIWRETRY\n", dev->name);
2245
2246         if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
2247                 return -EINVAL;
2248
2249         if (vwrq->flags & IW_RETRY_LIMIT) {
2250
2251 #if WIRELESS_EXT > 20
2252                 if ((vwrq->flags & IW_RETRY_LONG)
2253                     || (vwrq->flags & IW_RETRY_MAX)
2254                     || !((vwrq->flags & IW_RETRY_SHORT)
2255                          || (vwrq->flags & IW_RETRY_MIN))) {
2256 #else
2257                 if ((vwrq->flags & IW_RETRY_MAX)
2258                     || !(vwrq->flags & IW_RETRY_MIN)) {
2259 #endif
2260                         lrl = cpu_to_le32(vwrq->value);
2261                         error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl,
2262                                                 sizeof(lrl));
2263                         if (error)
2264                                 return error;
2265                 }
2266 #if WIRELESS_EXT > 20
2267                 if ((vwrq->flags & IW_RETRY_SHORT)
2268                     || (vwrq->flags & IW_RETRY_MIN)
2269                     || !((vwrq->flags & IW_RETRY_LONG)
2270                          || (vwrq->flags & IW_RETRY_MAX))) {
2271 #else
2272                 if ((vwrq->flags & IW_RETRY_MIN)
2273                     || !(vwrq->flags & IW_RETRY_MAX)) {
2274 #endif
2275                         srl = cpu_to_le32(vwrq->value);
2276                         error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl,
2277                                                 sizeof(srl));
2278                         if (error)
2279                                 return error;
2280                 }
2281         }
2282         return 0;
2283 }
2284
2285 static int
2286 wl_iw_get_retry(struct net_device *dev,
2287                 struct iw_request_info *info,
2288                 struct iw_param *vwrq, char *extra)
2289 {
2290         int error, lrl, srl;
2291
2292         WL_TRACE("%s: SIOCGIWRETRY\n", dev->name);
2293
2294         vwrq->disabled = 0;
2295
2296         if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
2297                 return -EINVAL;
2298
2299         error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl));
2300         if (error)
2301                 return error;
2302
2303         error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl));
2304         if (error)
2305                 return error;
2306
2307         lrl = le32_to_cpu(lrl);
2308         srl = le32_to_cpu(srl);
2309
2310         if (vwrq->flags & IW_RETRY_MAX) {
2311                 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
2312                 vwrq->value = lrl;
2313         } else {
2314                 vwrq->flags = IW_RETRY_LIMIT;
2315                 vwrq->value = srl;
2316                 if (srl != lrl)
2317                         vwrq->flags |= IW_RETRY_MIN;
2318         }
2319
2320         return 0;
2321 }
2322 #endif                          /* WIRELESS_EXT > 10 */
2323
2324 static int
2325 wl_iw_set_encode(struct net_device *dev,
2326                  struct iw_request_info *info,
2327                  struct iw_point *dwrq, char *extra)
2328 {
2329         wl_wsec_key_t key;
2330         int error, val, wsec;
2331
2332         WL_TRACE("%s: SIOCSIWENCODE\n", dev->name);
2333
2334         memset(&key, 0, sizeof(key));
2335
2336         if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2337                 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2338                      key.index++) {
2339                         val = cpu_to_le32(key.index);
2340                         error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2341                                                 sizeof(val));
2342                         if (error)
2343                                 return error;
2344                         val = le32_to_cpu(val);
2345                         if (val)
2346                                 break;
2347                 }
2348                 if (key.index == DOT11_MAX_DEFAULT_KEYS)
2349                         key.index = 0;
2350         } else {
2351                 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2352                 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2353                         return -EINVAL;
2354         }
2355
2356         if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
2357                 val = cpu_to_le32(key.index);
2358                 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val,
2359                                         sizeof(val));
2360                 if (error)
2361                         return error;
2362         } else {
2363                 key.len = dwrq->length;
2364
2365                 if (dwrq->length > sizeof(key.data))
2366                         return -EINVAL;
2367
2368                 memcpy(key.data, extra, dwrq->length);
2369
2370                 key.flags = WL_PRIMARY_KEY;
2371                 switch (key.len) {
2372                 case WLAN_KEY_LEN_WEP40:
2373                         key.algo = CRYPTO_ALGO_WEP1;
2374                         break;
2375                 case WLAN_KEY_LEN_WEP104:
2376                         key.algo = CRYPTO_ALGO_WEP128;
2377                         break;
2378                 case WLAN_KEY_LEN_TKIP:
2379                         key.algo = CRYPTO_ALGO_TKIP;
2380                         break;
2381                 case WLAN_KEY_LEN_AES_CMAC:
2382                         key.algo = CRYPTO_ALGO_AES_CCM;
2383                         break;
2384                 default:
2385                         return -EINVAL;
2386                 }
2387
2388                 swap_key_from_BE(&key);
2389                 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2390                 if (error)
2391                         return error;
2392         }
2393
2394         val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
2395
2396         error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2397         if (error)
2398                 return error;
2399
2400         wsec &= ~(WEP_ENABLED);
2401         wsec |= val;
2402
2403         error = dev_wlc_intvar_set(dev, "wsec", wsec);
2404         if (error)
2405                 return error;
2406
2407         val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
2408         val = cpu_to_le32(val);
2409         error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
2410         if (error)
2411                 return error;
2412
2413         return 0;
2414 }
2415
2416 static int
2417 wl_iw_get_encode(struct net_device *dev,
2418                  struct iw_request_info *info,
2419                  struct iw_point *dwrq, char *extra)
2420 {
2421         wl_wsec_key_t key;
2422         int error, val, wsec, auth;
2423
2424         WL_TRACE("%s: SIOCGIWENCODE\n", dev->name);
2425
2426         memset(&key, 0, sizeof(wl_wsec_key_t));
2427
2428         if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2429                 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2430                      key.index++) {
2431                         val = key.index;
2432                         error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2433                                                 sizeof(val));
2434                         if (error)
2435                                 return error;
2436                         val = le32_to_cpu(val);
2437                         if (val)
2438                                 break;
2439                 }
2440         } else
2441                 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2442
2443         if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2444                 key.index = 0;
2445
2446         error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
2447         if (error)
2448                 return error;
2449
2450         error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth));
2451         if (error)
2452                 return error;
2453
2454         swap_key_to_BE(&key);
2455
2456         wsec = le32_to_cpu(wsec);
2457         auth = le32_to_cpu(auth);
2458         dwrq->length = min_t(u16, WLAN_MAX_KEY_LEN, key.len);
2459
2460         dwrq->flags = key.index + 1;
2461         if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)))
2462                 dwrq->flags |= IW_ENCODE_DISABLED;
2463
2464         if (auth)
2465                 dwrq->flags |= IW_ENCODE_RESTRICTED;
2466
2467         if (dwrq->length && extra)
2468                 memcpy(extra, key.data, dwrq->length);
2469
2470         return 0;
2471 }
2472
2473 static int
2474 wl_iw_set_power(struct net_device *dev,
2475                 struct iw_request_info *info,
2476                 struct iw_param *vwrq, char *extra)
2477 {
2478         int error, pm;
2479
2480         WL_TRACE("%s: SIOCSIWPOWER\n", dev->name);
2481
2482         pm = vwrq->disabled ? PM_OFF : PM_MAX;
2483
2484         pm = cpu_to_le32(pm);
2485         error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
2486         if (error)
2487                 return error;
2488
2489         return 0;
2490 }
2491
2492 static int
2493 wl_iw_get_power(struct net_device *dev,
2494                 struct iw_request_info *info,
2495                 struct iw_param *vwrq, char *extra)
2496 {
2497         int error, pm;
2498
2499         WL_TRACE("%s: SIOCGIWPOWER\n", dev->name);
2500
2501         error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
2502         if (error)
2503                 return error;
2504
2505         pm = le32_to_cpu(pm);
2506         vwrq->disabled = pm ? 0 : 1;
2507         vwrq->flags = IW_POWER_ALL_R;
2508
2509         return 0;
2510 }
2511
2512 #if WIRELESS_EXT > 17
2513 static int
2514 wl_iw_set_wpaie(struct net_device *dev,
2515                 struct iw_request_info *info, struct iw_point *iwp, char *extra)
2516 {
2517
2518         WL_TRACE("%s: SIOCSIWGENIE\n", dev->name);
2519
2520         CHECK_EXTRA_FOR_NULL(extra);
2521
2522         dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
2523
2524         return 0;
2525 }
2526
2527 static int
2528 wl_iw_get_wpaie(struct net_device *dev,
2529                 struct iw_request_info *info, struct iw_point *iwp, char *extra)
2530 {
2531         WL_TRACE("%s: SIOCGIWGENIE\n", dev->name);
2532         iwp->length = 64;
2533         dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
2534         return 0;
2535 }
2536
2537 static int
2538 wl_iw_set_encodeext(struct net_device *dev,
2539                     struct iw_request_info *info,
2540                     struct iw_point *dwrq, char *extra)
2541 {
2542         wl_wsec_key_t key;
2543         int error;
2544         struct iw_encode_ext *iwe;
2545
2546         WL_TRACE("%s: SIOCSIWENCODEEXT\n", dev->name);
2547
2548         CHECK_EXTRA_FOR_NULL(extra);
2549
2550         memset(&key, 0, sizeof(key));
2551         iwe = (struct iw_encode_ext *)extra;
2552
2553         if (dwrq->flags & IW_ENCODE_DISABLED) {
2554
2555         }
2556
2557         key.index = 0;
2558         if (dwrq->flags & IW_ENCODE_INDEX)
2559                 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2560
2561         key.len = iwe->key_len;
2562
2563         if (!is_multicast_ether_addr(iwe->addr.sa_data))
2564                 memcpy(&key.ea, &iwe->addr.sa_data, ETH_ALEN);
2565
2566         if (key.len == 0) {
2567                 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
2568                         WL_WSEC("Changing the the primary Key to %d\n",
2569                                 key.index);
2570                         key.index = cpu_to_le32(key.index);
2571                         error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
2572                                               &key.index, sizeof(key.index));
2573                         if (error)
2574                                 return error;
2575                 } else {
2576                         swap_key_from_BE(&key);
2577                         dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2578                 }
2579         } else {
2580                 if (iwe->key_len > sizeof(key.data))
2581                         return -EINVAL;
2582
2583                 WL_WSEC("Setting the key index %d\n", key.index);
2584                 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
2585                         WL_WSEC("key is a Primary Key\n");
2586                         key.flags = WL_PRIMARY_KEY;
2587                 }
2588
2589                 memcpy(key.data, iwe->key, iwe->key_len);
2590
2591                 if (iwe->alg == IW_ENCODE_ALG_TKIP) {
2592                         u8 keybuf[8];
2593                         memcpy(keybuf, &key.data[24], sizeof(keybuf));
2594                         memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2595                         memcpy(&key.data[16], keybuf, sizeof(keybuf));
2596                 }
2597
2598                 if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
2599                         unsigned char *ivptr;
2600                         ivptr = (unsigned char *) iwe->rx_seq;
2601                         key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2602                             (ivptr[3] << 8) | ivptr[2];
2603                         key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2604                         key.iv_initialized = true;
2605                 }
2606
2607                 switch (iwe->alg) {
2608                 case IW_ENCODE_ALG_NONE:
2609                         key.algo = CRYPTO_ALGO_OFF;
2610                         break;
2611                 case IW_ENCODE_ALG_WEP:
2612                         if (iwe->key_len == WLAN_KEY_LEN_WEP40)
2613                                 key.algo = CRYPTO_ALGO_WEP1;
2614                         else
2615                                 key.algo = CRYPTO_ALGO_WEP128;
2616                         break;
2617                 case IW_ENCODE_ALG_TKIP:
2618                         key.algo = CRYPTO_ALGO_TKIP;
2619                         break;
2620                 case IW_ENCODE_ALG_CCMP:
2621                         key.algo = CRYPTO_ALGO_AES_CCM;
2622                         break;
2623                 default:
2624                         break;
2625                 }
2626                 swap_key_from_BE(&key);
2627
2628                 dhd_wait_pend8021x(dev);
2629
2630                 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2631                 if (error)
2632                         return error;
2633         }
2634         return 0;
2635 }
2636
2637 #if WIRELESS_EXT > 17
2638 struct {
2639         pmkid_list_t pmkids;
2640         pmkid_t foo[MAXPMKID - 1];
2641 } pmkid_list;
2642
2643 static int
2644 wl_iw_set_pmksa(struct net_device *dev,
2645                 struct iw_request_info *info,
2646                 struct iw_param *vwrq, char *extra)
2647 {
2648         struct iw_pmksa *iwpmksa;
2649         uint i;
2650         int ret = 0;
2651
2652         WL_WSEC("%s: SIOCSIWPMKSA\n", dev->name);
2653
2654         CHECK_EXTRA_FOR_NULL(extra);
2655
2656         iwpmksa = (struct iw_pmksa *)extra;
2657
2658         if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
2659                 WL_WSEC("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n");
2660                 memset((char *)&pmkid_list, 0, sizeof(pmkid_list));
2661         }
2662
2663         else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
2664                 {
2665                         pmkid_list_t pmkid, *pmkidptr;
2666                         uint j;
2667                         pmkidptr = &pmkid;
2668
2669                         memcpy(&pmkidptr->pmkid[0].BSSID,
2670                                &iwpmksa->bssid.sa_data[0],
2671                                ETH_ALEN);
2672                         memcpy(&pmkidptr->pmkid[0].PMKID,
2673                                &iwpmksa->pmkid[0],
2674                                WLAN_PMKID_LEN);
2675
2676                         WL_WSEC("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: "
2677                                 "%pM = ", &pmkidptr->pmkid[0].BSSID);
2678                         for (j = 0; j < WLAN_PMKID_LEN; j++)
2679                                 WL_WSEC("%02x ", pmkidptr->pmkid[0].PMKID[j]);
2680                         WL_WSEC("\n");
2681                 }
2682
2683                 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2684                         if (!memcmp
2685                             (&iwpmksa->bssid.sa_data[0],
2686                              &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
2687                                 break;
2688
2689                 if ((pmkid_list.pmkids.npmkid > 0)
2690                     && (i < pmkid_list.pmkids.npmkid)) {
2691                         memset(&pmkid_list.pmkids.pmkid[i], 0, sizeof(pmkid_t));
2692                         for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
2693                                 memcpy(&pmkid_list.pmkids.pmkid[i].BSSID,
2694                                        &pmkid_list.pmkids.pmkid[i + 1].BSSID,
2695                                        ETH_ALEN);
2696                                 memcpy(&pmkid_list.pmkids.pmkid[i].PMKID,
2697                                        &pmkid_list.pmkids.pmkid[i + 1].PMKID,
2698                                        WLAN_PMKID_LEN);
2699                         }
2700                         pmkid_list.pmkids.npmkid--;
2701                 } else
2702                         ret = -EINVAL;
2703         }
2704
2705         else if (iwpmksa->cmd == IW_PMKSA_ADD) {
2706                 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2707                         if (!memcmp
2708                             (&iwpmksa->bssid.sa_data[0],
2709                              &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
2710                                 break;
2711                 if (i < MAXPMKID) {
2712                         memcpy(&pmkid_list.pmkids.pmkid[i].BSSID,
2713                                &iwpmksa->bssid.sa_data[0],
2714                                ETH_ALEN);
2715                         memcpy(&pmkid_list.pmkids.pmkid[i].PMKID,
2716                                &iwpmksa->pmkid[0],
2717                                WLAN_PMKID_LEN);
2718                         if (i == pmkid_list.pmkids.npmkid)
2719                                 pmkid_list.pmkids.npmkid++;
2720                 } else
2721                         ret = -EINVAL;
2722                 {
2723                         uint j;
2724                         uint k;
2725                         k = pmkid_list.pmkids.npmkid;
2726                         WL_WSEC("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %pM = ",
2727                                 &pmkid_list.pmkids.pmkid[k].BSSID);
2728                         for (j = 0; j < WLAN_PMKID_LEN; j++)
2729                                 WL_WSEC("%02x ",
2730                                         pmkid_list.pmkids.pmkid[k].PMKID[j]);
2731                         WL_WSEC("\n");
2732                 }
2733         }
2734         WL_WSEC("PRINTING pmkid LIST - No of elements %d\n",
2735                 pmkid_list.pmkids.npmkid);
2736         for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
2737                 uint j;
2738                 WL_WSEC("PMKID[%d]: %pM = ",
2739                         i, &pmkid_list.pmkids.pmkid[i].BSSID);
2740                 for (j = 0; j < WLAN_PMKID_LEN; j++)
2741                         WL_WSEC("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]);
2742                 WL_WSEC("\n");
2743         }
2744         WL_WSEC("\n");
2745
2746         if (!ret)
2747                 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
2748                                          sizeof(pmkid_list));
2749         return ret;
2750 }
2751 #endif                          /* WIRELESS_EXT > 17 */
2752
2753 static int
2754 wl_iw_get_encodeext(struct net_device *dev,
2755                     struct iw_request_info *info,
2756                     struct iw_param *vwrq, char *extra)
2757 {
2758         WL_TRACE("%s: SIOCGIWENCODEEXT\n", dev->name);
2759         return 0;
2760 }
2761
2762 static int
2763 wl_iw_set_wpaauth(struct net_device *dev,
2764                   struct iw_request_info *info,
2765                   struct iw_param *vwrq, char *extra)
2766 {
2767         int error = 0;
2768         int paramid;
2769         int paramval;
2770         int val = 0;
2771         wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2772
2773         WL_TRACE("%s: SIOCSIWAUTH\n", dev->name);
2774
2775         paramid = vwrq->flags & IW_AUTH_INDEX;
2776         paramval = vwrq->value;
2777
2778         WL_TRACE("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
2779                  dev->name, paramid, paramval);
2780
2781         switch (paramid) {
2782         case IW_AUTH_WPA_VERSION:
2783                 if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
2784                         val = WPA_AUTH_DISABLED;
2785                 else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
2786                         val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
2787                 else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
2788                         val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
2789                 WL_INFORM("%s: %d: setting wpa_auth to 0x%0x\n",
2790                           __func__, __LINE__, val);
2791                 error = dev_wlc_intvar_set(dev, "wpa_auth", val);
2792                 if (error)
2793                         return error;
2794                 break;
2795         case IW_AUTH_CIPHER_PAIRWISE:
2796         case IW_AUTH_CIPHER_GROUP:
2797                 if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
2798                         val = WEP_ENABLED;
2799                 if (paramval & IW_AUTH_CIPHER_TKIP)
2800                         val = TKIP_ENABLED;
2801                 if (paramval & IW_AUTH_CIPHER_CCMP)
2802                         val = AES_ENABLED;
2803
2804                 if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
2805                         iw->pwsec = val;
2806                         val |= iw->gwsec;
2807                 } else {
2808                         iw->gwsec = val;
2809                         val |= iw->pwsec;
2810                 }
2811
2812                 if (iw->privacy_invoked && !val) {
2813                         WL_WSEC("%s: %s: 'Privacy invoked' true but clearing wsec, assuming we're a WPS enrollee\n",
2814                                 dev->name, __func__);
2815                         error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
2816                                                         true);
2817                         if (error) {
2818                                 WL_WSEC("Failed to set is_WPS_enrollee\n");
2819                                 return error;
2820                         }
2821                 } else if (val) {
2822                         error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
2823                                                         false);
2824                         if (error) {
2825                                 WL_WSEC("Failed to clear is_WPS_enrollee\n");
2826                                 return error;
2827                         }
2828                 }
2829
2830                 error = dev_wlc_intvar_set(dev, "wsec", val);
2831                 if (error)
2832                         return error;
2833
2834                 break;
2835
2836         case IW_AUTH_KEY_MGMT:
2837                 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2838                 if (error)
2839                         return error;
2840
2841                 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
2842                         if (paramval & IW_AUTH_KEY_MGMT_PSK)
2843                                 val = WPA_AUTH_PSK;
2844                         else
2845                                 val = WPA_AUTH_UNSPECIFIED;
2846                 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
2847                         if (paramval & IW_AUTH_KEY_MGMT_PSK)
2848                                 val = WPA2_AUTH_PSK;
2849                         else
2850                                 val = WPA2_AUTH_UNSPECIFIED;
2851                 }
2852                 WL_INFORM("%s: %d: setting wpa_auth to %d\n",
2853                           __func__, __LINE__, val);
2854                 error = dev_wlc_intvar_set(dev, "wpa_auth", val);
2855                 if (error)
2856                         return error;
2857
2858                 break;
2859         case IW_AUTH_TKIP_COUNTERMEASURES:
2860                 dev_wlc_bufvar_set(dev, "tkip_countermeasures",
2861                                    (char *)&paramval, 1);
2862                 break;
2863
2864         case IW_AUTH_80211_AUTH_ALG:
2865                 WL_INFORM("Setting the D11auth %d\n", paramval);
2866                 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
2867                         val = 0;
2868                 else if (paramval == IW_AUTH_ALG_SHARED_KEY)
2869                         val = 1;
2870                 else if (paramval ==
2871                          (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
2872                         val = 2;
2873                 else
2874                         error = 1;
2875                 if (!error) {
2876                         error = dev_wlc_intvar_set(dev, "auth", val);
2877                         if (error)
2878                                 return error;
2879                 }
2880                 break;
2881
2882         case IW_AUTH_WPA_ENABLED:
2883                 if (paramval == 0) {
2884                         iw->pwsec = 0;
2885                         iw->gwsec = 0;
2886                         error = dev_wlc_intvar_get(dev, "wsec", &val);
2887                         if (error)
2888                                 return error;
2889                         if (val & (TKIP_ENABLED | AES_ENABLED)) {
2890                                 val &= ~(TKIP_ENABLED | AES_ENABLED);
2891                                 dev_wlc_intvar_set(dev, "wsec", val);
2892                         }
2893                         val = 0;
2894                         WL_INFORM("%s: %d: setting wpa_auth to %d\n",
2895                                   __func__, __LINE__, val);
2896                         dev_wlc_intvar_set(dev, "wpa_auth", 0);
2897                         return error;
2898                 }
2899                 break;
2900
2901         case IW_AUTH_DROP_UNENCRYPTED:
2902                 dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)&paramval, 1);
2903                 break;
2904
2905         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
2906                 dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol",
2907                                    (char *)&paramval, 1);
2908                 break;
2909
2910 #if WIRELESS_EXT > 17
2911         case IW_AUTH_ROAMING_CONTROL:
2912                 WL_INFORM("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
2913                 break;
2914         case IW_AUTH_PRIVACY_INVOKED:
2915                 {
2916                         int wsec;
2917
2918                         if (paramval == 0) {
2919                                 iw->privacy_invoked = false;
2920                                 error = dev_wlc_intvar_set(dev,
2921                                                 "is_WPS_enrollee", false);
2922                                 if (error) {
2923                                         WL_WSEC("Failed to clear iovar is_WPS_enrollee\n");
2924                                         return error;
2925                                 }
2926                         } else {
2927                                 iw->privacy_invoked = true;
2928                                 error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2929                                 if (error)
2930                                         return error;
2931
2932                                 if (!(IW_WSEC_ENABLED(wsec))) {
2933                                         error = dev_wlc_intvar_set(dev,
2934                                                         "is_WPS_enrollee",
2935                                                         true);
2936                                         if (error) {
2937                                                 WL_WSEC("Failed to set iovar is_WPS_enrollee\n");
2938                                                 return error;
2939                                         }
2940                                 } else {
2941                                         error = dev_wlc_intvar_set(dev,
2942                                                         "is_WPS_enrollee",
2943                                                         false);
2944                                         if (error) {
2945                                                 WL_WSEC("Failed to clear is_WPS_enrollee\n");
2946                                                 return error;
2947                                         }
2948                                 }
2949                         }
2950                         break;
2951                 }
2952 #endif                          /* WIRELESS_EXT > 17 */
2953         default:
2954                 break;
2955         }
2956         return 0;
2957 }
2958
2959 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
2960
2961 static int
2962 wl_iw_get_wpaauth(struct net_device *dev,
2963                   struct iw_request_info *info,
2964                   struct iw_param *vwrq, char *extra)
2965 {
2966         int error;
2967         int paramid;
2968         int paramval = 0;
2969         int val;
2970         wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2971
2972         WL_TRACE("%s: SIOCGIWAUTH\n", dev->name);
2973
2974         paramid = vwrq->flags & IW_AUTH_INDEX;
2975
2976         switch (paramid) {
2977         case IW_AUTH_WPA_VERSION:
2978                 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2979                 if (error)
2980                         return error;
2981                 if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
2982                         paramval = IW_AUTH_WPA_VERSION_DISABLED;
2983                 else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
2984                         paramval = IW_AUTH_WPA_VERSION_WPA;
2985                 else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
2986                         paramval = IW_AUTH_WPA_VERSION_WPA2;
2987                 break;
2988         case IW_AUTH_CIPHER_PAIRWISE:
2989         case IW_AUTH_CIPHER_GROUP:
2990                 if (paramid == IW_AUTH_CIPHER_PAIRWISE)
2991                         val = iw->pwsec;
2992                 else
2993                         val = iw->gwsec;
2994
2995                 paramval = 0;
2996                 if (val) {
2997                         if (val & WEP_ENABLED)
2998                                 paramval |=
2999                                     (IW_AUTH_CIPHER_WEP40 |
3000                                      IW_AUTH_CIPHER_WEP104);
3001                         if (val & TKIP_ENABLED)
3002                                 paramval |= (IW_AUTH_CIPHER_TKIP);
3003                         if (val & AES_ENABLED)
3004                                 paramval |= (IW_AUTH_CIPHER_CCMP);
3005                 } else
3006                         paramval = IW_AUTH_CIPHER_NONE;
3007                 break;
3008         case IW_AUTH_KEY_MGMT:
3009                 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
3010                 if (error)
3011                         return error;
3012                 if (VAL_PSK(val))
3013                         paramval = IW_AUTH_KEY_MGMT_PSK;
3014                 else
3015                         paramval = IW_AUTH_KEY_MGMT_802_1X;
3016
3017                 break;
3018         case IW_AUTH_TKIP_COUNTERMEASURES:
3019                 dev_wlc_bufvar_get(dev, "tkip_countermeasures",
3020                                    (char *)&paramval, 1);
3021                 break;
3022
3023         case IW_AUTH_DROP_UNENCRYPTED:
3024                 dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)&paramval, 1);
3025                 break;
3026
3027         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
3028                 dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol",
3029                                    (char *)&paramval, 1);
3030                 break;
3031
3032         case IW_AUTH_80211_AUTH_ALG:
3033                 error = dev_wlc_intvar_get(dev, "auth", &val);
3034                 if (error)
3035                         return error;
3036                 if (!val)
3037                         paramval = IW_AUTH_ALG_OPEN_SYSTEM;
3038                 else
3039                         paramval = IW_AUTH_ALG_SHARED_KEY;
3040                 break;
3041         case IW_AUTH_WPA_ENABLED:
3042                 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
3043                 if (error)
3044                         return error;
3045                 if (val)
3046                         paramval = true;
3047                 else
3048                         paramval = false;
3049                 break;
3050 #if WIRELESS_EXT > 17
3051         case IW_AUTH_ROAMING_CONTROL:
3052                 WL_ERROR("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
3053                 break;
3054         case IW_AUTH_PRIVACY_INVOKED:
3055                 paramval = iw->privacy_invoked;
3056                 break;
3057
3058 #endif
3059         }
3060         vwrq->value = paramval;
3061         return 0;
3062 }
3063 #endif                          /* WIRELESS_EXT > 17 */
3064
3065 static const iw_handler wl_iw_handler[] = {
3066         (iw_handler) wl_iw_config_commit,
3067         (iw_handler) wl_iw_get_name,
3068         (iw_handler) NULL,
3069         (iw_handler) NULL,
3070         (iw_handler) wl_iw_set_freq,
3071         (iw_handler) wl_iw_get_freq,
3072         (iw_handler) wl_iw_set_mode,
3073         (iw_handler) wl_iw_get_mode,
3074         (iw_handler) NULL,
3075         (iw_handler) NULL,
3076         (iw_handler) NULL,
3077         (iw_handler) wl_iw_get_range,
3078         (iw_handler) NULL,
3079         (iw_handler) NULL,
3080         (iw_handler) NULL,
3081         (iw_handler) NULL,
3082         (iw_handler) wl_iw_set_spy,
3083         (iw_handler) wl_iw_get_spy,
3084         (iw_handler) NULL,
3085         (iw_handler) NULL,
3086         (iw_handler) wl_iw_set_wap,
3087         (iw_handler) wl_iw_get_wap,
3088 #if WIRELESS_EXT > 17
3089         (iw_handler) wl_iw_mlme,
3090 #else
3091         (iw_handler) NULL,
3092 #endif
3093 #if defined(WL_IW_USE_ISCAN)
3094         (iw_handler) wl_iw_iscan_get_aplist,
3095 #else
3096         (iw_handler) wl_iw_get_aplist,
3097 #endif
3098 #if WIRELESS_EXT > 13
3099 #if defined(WL_IW_USE_ISCAN)
3100         (iw_handler) wl_iw_iscan_set_scan,
3101         (iw_handler) wl_iw_iscan_get_scan,
3102 #else
3103         (iw_handler) wl_iw_set_scan,
3104         (iw_handler) wl_iw_get_scan,
3105 #endif
3106 #else
3107         (iw_handler) NULL,
3108         (iw_handler) NULL,
3109 #endif                          /* WIRELESS_EXT > 13 */
3110         (iw_handler) wl_iw_set_essid,
3111         (iw_handler) wl_iw_get_essid,
3112         (iw_handler) wl_iw_set_nick,
3113         (iw_handler) wl_iw_get_nick,
3114         (iw_handler) NULL,
3115         (iw_handler) NULL,
3116         (iw_handler) wl_iw_set_rate,
3117         (iw_handler) wl_iw_get_rate,
3118         (iw_handler) wl_iw_set_rts,
3119         (iw_handler) wl_iw_get_rts,
3120         (iw_handler) wl_iw_set_frag,
3121         (iw_handler) wl_iw_get_frag,
3122         (iw_handler) wl_iw_set_txpow,
3123         (iw_handler) wl_iw_get_txpow,
3124 #if WIRELESS_EXT > 10
3125         (iw_handler) wl_iw_set_retry,
3126         (iw_handler) wl_iw_get_retry,
3127 #endif
3128         (iw_handler) wl_iw_set_encode,
3129         (iw_handler) wl_iw_get_encode,
3130         (iw_handler) wl_iw_set_power,
3131         (iw_handler) wl_iw_get_power,
3132 #if WIRELESS_EXT > 17
3133         (iw_handler) NULL,
3134         (iw_handler) NULL,
3135         (iw_handler) wl_iw_set_wpaie,
3136         (iw_handler) wl_iw_get_wpaie,
3137         (iw_handler) wl_iw_set_wpaauth,
3138         (iw_handler) wl_iw_get_wpaauth,
3139         (iw_handler) wl_iw_set_encodeext,
3140         (iw_handler) wl_iw_get_encodeext,
3141         (iw_handler) wl_iw_set_pmksa,
3142 #endif                          /* WIRELESS_EXT > 17 */
3143 };
3144
3145 #if WIRELESS_EXT > 12
3146
3147 const struct iw_handler_def wl_iw_handler_def = {
3148         .num_standard = ARRAY_SIZE(wl_iw_handler),
3149         .standard = (iw_handler *) wl_iw_handler,
3150         .num_private = 0,
3151         .num_private_args = 0,
3152         .private = 0,
3153         .private_args = 0,
3154
3155 #if WIRELESS_EXT >= 19
3156         .get_wireless_stats = NULL,
3157 #endif
3158 };
3159 #endif                          /* WIRELESS_EXT > 12 */
3160
3161 int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
3162 {
3163         struct iwreq *wrq = (struct iwreq *)rq;
3164         struct iw_request_info info;
3165         iw_handler handler;
3166         char *extra = NULL;
3167         int token_size = 1, max_tokens = 0, ret = 0;
3168
3169         WL_TRACE("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
3170                  __func__, cmd);
3171         if (cmd < SIOCIWFIRST ||
3172                 IW_IOCTL_IDX(cmd) >= ARRAY_SIZE(wl_iw_handler)) {
3173                 WL_ERROR("%s: error in cmd=%x : out of range\n",
3174                          __func__, cmd);
3175                 return -EOPNOTSUPP;
3176         }
3177
3178         handler = wl_iw_handler[IW_IOCTL_IDX(cmd)];
3179         if (!handler) {
3180                 WL_ERROR("%s: error in cmd=%x : not supported\n",
3181                          __func__, cmd);
3182                 return -EOPNOTSUPP;
3183         }
3184
3185         switch (cmd) {
3186
3187         case SIOCSIWESSID:
3188         case SIOCGIWESSID:
3189         case SIOCSIWNICKN:
3190         case SIOCGIWNICKN:
3191                 max_tokens = IW_ESSID_MAX_SIZE + 1;
3192                 break;
3193
3194         case SIOCSIWENCODE:
3195         case SIOCGIWENCODE:
3196 #if WIRELESS_EXT > 17
3197         case SIOCSIWENCODEEXT:
3198         case SIOCGIWENCODEEXT:
3199 #endif
3200                 max_tokens = wrq->u.data.length;
3201                 break;
3202
3203         case SIOCGIWRANGE:
3204                 max_tokens = sizeof(struct iw_range) + 500;
3205                 break;
3206
3207         case SIOCGIWAPLIST:
3208                 token_size =
3209                     sizeof(struct sockaddr) + sizeof(struct iw_quality);
3210                 max_tokens = IW_MAX_AP;
3211                 break;
3212
3213 #if WIRELESS_EXT > 13
3214         case SIOCGIWSCAN:
3215 #if defined(WL_IW_USE_ISCAN)
3216                 if (g_iscan)
3217                         max_tokens = wrq->u.data.length;
3218                 else
3219 #endif
3220                         max_tokens = IW_SCAN_MAX_DATA;
3221                 break;
3222 #endif                          /* WIRELESS_EXT > 13 */
3223
3224         case SIOCSIWSPY:
3225                 token_size = sizeof(struct sockaddr);
3226                 max_tokens = IW_MAX_SPY;
3227                 break;
3228
3229         case SIOCGIWSPY:
3230                 token_size =
3231                     sizeof(struct sockaddr) + sizeof(struct iw_quality);
3232                 max_tokens = IW_MAX_SPY;
3233                 break;
3234
3235 #if WIRELESS_EXT > 17
3236         case SIOCSIWPMKSA:
3237         case SIOCSIWGENIE:
3238 #endif
3239         case SIOCSIWPRIV:
3240                 max_tokens = wrq->u.data.length;
3241                 break;
3242         }
3243
3244         if (max_tokens && wrq->u.data.pointer) {
3245                 if (wrq->u.data.length > max_tokens) {
3246                         WL_ERROR("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n",
3247                                  __func__, cmd, wrq->u.data.length, max_tokens);
3248                         return -E2BIG;
3249                 }
3250                 extra = kmalloc(max_tokens * token_size, GFP_KERNEL);
3251                 if (!extra)
3252                         return -ENOMEM;
3253
3254                 if (copy_from_user
3255                     (extra, wrq->u.data.pointer,
3256                      wrq->u.data.length * token_size)) {
3257                         kfree(extra);
3258                         return -EFAULT;
3259                 }
3260         }
3261
3262         info.cmd = cmd;
3263         info.flags = 0;
3264
3265         ret = handler(dev, &info, &wrq->u, extra);
3266
3267         if (extra) {
3268                 if (copy_to_user
3269                     (wrq->u.data.pointer, extra,
3270                      wrq->u.data.length * token_size)) {
3271                         kfree(extra);
3272                         return -EFAULT;
3273                 }
3274
3275                 kfree(extra);
3276         }
3277
3278         return ret;
3279 }
3280
3281 bool
3282 wl_iw_conn_status_str(u32 event_type, u32 status, u32 reason,
3283                       char *stringBuf, uint buflen)
3284 {
3285         typedef struct conn_fail_event_map_t {
3286                 u32 inEvent;
3287                 u32 inStatus;
3288                 u32 inReason;
3289                 const char *outName;
3290                 const char *outCause;
3291         } conn_fail_event_map_t;
3292
3293 #define WL_IW_DONT_CARE 9999
3294         const conn_fail_event_map_t event_map[] = {
3295                 {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE,
3296                  "Conn", "Success"},
3297                 {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
3298                  "Conn", "NoNetworks"},
3299                 {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3300                  "Conn", "ConfigMismatch"},
3301                 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH,
3302                  "Conn", "EncrypMismatch"},
3303                 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH,
3304                  "Conn", "RsnMismatch"},
3305                 {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
3306                  "Conn", "AuthTimeout"},
3307                 {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3308                  "Conn", "AuthFail"},
3309                 {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE,
3310                  "Conn", "AuthNoAck"},
3311                 {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3312                  "Conn", "ReassocFail"},
3313                 {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
3314                  "Conn", "ReassocTimeout"},
3315                 {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE,
3316                  "Conn", "ReassocAbort"},
3317                 {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE,
3318                  "Sup", "ConnSuccess"},
3319                 {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3320                  "Sup", "WpaHandshakeFail"},
3321                 {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3322                  "Conn", "Deauth"},
3323                 {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3324                  "Conn", "DisassocInd"},
3325                 {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3326                  "Conn", "Disassoc"}
3327         };
3328
3329         const char *name = "";
3330         const char *cause = NULL;
3331         int i;
3332
3333         for (i = 0; i < sizeof(event_map) / sizeof(event_map[0]); i++) {
3334                 const conn_fail_event_map_t *row = &event_map[i];
3335                 if (row->inEvent == event_type &&
3336                     (row->inStatus == status
3337                      || row->inStatus == WL_IW_DONT_CARE)
3338                     && (row->inReason == reason
3339                         || row->inReason == WL_IW_DONT_CARE)) {
3340                         name = row->outName;
3341                         cause = row->outCause;
3342                         break;
3343                 }
3344         }
3345
3346         if (cause) {
3347                 memset(stringBuf, 0, buflen);
3348                 snprintf(stringBuf, buflen, "%s %s %02d %02d",
3349                          name, cause, status, reason);
3350                 WL_INFORM("Connection status: %s\n", stringBuf);
3351                 return true;
3352         } else {
3353                 return false;
3354         }
3355 }
3356
3357 #if WIRELESS_EXT > 14
3358
3359 static bool
3360 wl_iw_check_conn_fail(wl_event_msg_t *e, char *stringBuf, uint buflen)
3361 {
3362         u32 event = be32_to_cpu(e->event_type);
3363         u32 status = be32_to_cpu(e->status);
3364         u32 reason = be32_to_cpu(e->reason);
3365
3366         if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
3367                 return true;
3368         } else
3369                 return false;
3370 }
3371 #endif
3372
3373 #ifndef IW_CUSTOM_MAX
3374 #define IW_CUSTOM_MAX 256
3375 #endif
3376
3377 void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
3378 {
3379 #if WIRELESS_EXT > 13
3380         union iwreq_data wrqu;
3381         char extra[IW_CUSTOM_MAX + 1];
3382         int cmd = 0;
3383         u32 event_type = be32_to_cpu(e->event_type);
3384         u16 flags = be16_to_cpu(e->flags);
3385         u32 datalen = be32_to_cpu(e->datalen);
3386         u32 status = be32_to_cpu(e->status);
3387         wl_iw_t *iw;
3388         u32 toto;
3389         memset(&wrqu, 0, sizeof(wrqu));
3390         memset(extra, 0, sizeof(extra));
3391         iw = 0;
3392
3393         if (!dev) {
3394                 WL_ERROR("%s: dev is null\n", __func__);
3395                 return;
3396         }
3397
3398         iw = *(wl_iw_t **) netdev_priv(dev);
3399
3400         WL_TRACE("%s: dev=%s event=%d\n", __func__, dev->name, event_type);
3401
3402         switch (event_type) {
3403         case WLC_E_TXFAIL:
3404                 cmd = IWEVTXDROP;
3405                 memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3406                 wrqu.addr.sa_family = ARPHRD_ETHER;
3407                 break;
3408 #if WIRELESS_EXT > 14
3409         case WLC_E_JOIN:
3410         case WLC_E_ASSOC_IND:
3411         case WLC_E_REASSOC_IND:
3412                 memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3413                 wrqu.addr.sa_family = ARPHRD_ETHER;
3414                 cmd = IWEVREGISTERED;
3415                 break;
3416         case WLC_E_DEAUTH_IND:
3417         case WLC_E_DISASSOC_IND:
3418                 cmd = SIOCGIWAP;
3419                 memset(wrqu.addr.sa_data, 0, ETH_ALEN);
3420                 wrqu.addr.sa_family = ARPHRD_ETHER;
3421                 memset(&extra, 0, ETH_ALEN);
3422                 break;
3423         case WLC_E_LINK:
3424         case WLC_E_NDIS_LINK:
3425                 cmd = SIOCGIWAP;
3426                 if (!(flags & WLC_EVENT_MSG_LINK)) {
3427                         memset(wrqu.addr.sa_data, 0, ETH_ALEN);
3428                         memset(&extra, 0, ETH_ALEN);
3429                 } else {
3430                         memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3431                         WL_TRACE("Link UP\n");
3432
3433                 }
3434                 wrqu.addr.sa_family = ARPHRD_ETHER;
3435                 break;
3436         case WLC_E_ACTION_FRAME:
3437                 cmd = IWEVCUSTOM;
3438                 if (datalen + 1 <= sizeof(extra)) {
3439                         wrqu.data.length = datalen + 1;
3440                         extra[0] = WLC_E_ACTION_FRAME;
3441                         memcpy(&extra[1], data, datalen);
3442                         WL_TRACE("WLC_E_ACTION_FRAME len %d\n",
3443                                  wrqu.data.length);
3444                 }
3445                 break;
3446
3447         case WLC_E_ACTION_FRAME_COMPLETE:
3448                 cmd = IWEVCUSTOM;
3449                 memcpy(&toto, data, 4);
3450                 if (sizeof(status) + 1 <= sizeof(extra)) {
3451                         wrqu.data.length = sizeof(status) + 1;
3452                         extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
3453                         memcpy(&extra[1], &status, sizeof(status));
3454                         WL_TRACE("wl_iw_event status %d PacketId %d\n", status,
3455                                  toto);
3456                         WL_TRACE("WLC_E_ACTION_FRAME_COMPLETE len %d\n",
3457                                  wrqu.data.length);
3458                 }
3459                 break;
3460 #endif                          /* WIRELESS_EXT > 14 */
3461 #if WIRELESS_EXT > 17
3462         case WLC_E_MIC_ERROR:
3463                 {
3464                         struct iw_michaelmicfailure *micerrevt =
3465                             (struct iw_michaelmicfailure *)&extra;
3466                         cmd = IWEVMICHAELMICFAILURE;
3467                         wrqu.data.length = sizeof(struct iw_michaelmicfailure);
3468                         if (flags & WLC_EVENT_MSG_GROUP)
3469                                 micerrevt->flags |= IW_MICFAILURE_GROUP;
3470                         else
3471                                 micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
3472                         memcpy(micerrevt->src_addr.sa_data, &e->addr,
3473                                ETH_ALEN);
3474                         micerrevt->src_addr.sa_family = ARPHRD_ETHER;
3475
3476                         break;
3477                 }
3478         case WLC_E_PMKID_CACHE:
3479                 {
3480                         if (data) {
3481                                 struct iw_pmkid_cand *iwpmkidcand =
3482                                     (struct iw_pmkid_cand *)&extra;
3483                                 pmkid_cand_list_t *pmkcandlist;
3484                                 pmkid_cand_t *pmkidcand;
3485                                 int count;
3486
3487                                 cmd = IWEVPMKIDCAND;
3488                                 pmkcandlist = data;
3489                                 count = get_unaligned_be32(&pmkcandlist->
3490                                                            npmkid_cand);
3491                                 ASSERT(count >= 0);
3492                                 wrqu.data.length = sizeof(struct iw_pmkid_cand);
3493                                 pmkidcand = pmkcandlist->pmkid_cand;
3494                                 while (count) {
3495                                         memset(iwpmkidcand, 0,
3496                                               sizeof(struct iw_pmkid_cand));
3497                                         if (pmkidcand->preauth)
3498                                                 iwpmkidcand->flags |=
3499                                                     IW_PMKID_CAND_PREAUTH;
3500                                         memcpy(&iwpmkidcand->bssid.sa_data,
3501                                                &pmkidcand->BSSID,
3502                                                ETH_ALEN);
3503 #ifndef SANDGATE2G
3504                                         wireless_send_event(dev, cmd, &wrqu,
3505                                                             extra);
3506 #endif
3507                                         pmkidcand++;
3508                                         count--;
3509                                 }
3510                         }
3511                         return;
3512                 }
3513 #endif                          /* WIRELESS_EXT > 17 */
3514
3515         case WLC_E_SCAN_COMPLETE:
3516 #if defined(WL_IW_USE_ISCAN)
3517                 if ((g_iscan) && (g_iscan->sysioc_tsk) &&
3518                     (g_iscan->iscan_state != ISCAN_STATE_IDLE)) {
3519                         up(&g_iscan->sysioc_sem);
3520                 } else {
3521                         cmd = SIOCGIWSCAN;
3522                         wrqu.data.length = strlen(extra);
3523                         WL_TRACE("Event WLC_E_SCAN_COMPLETE from specific scan %d\n",
3524                                  g_iscan->iscan_state);
3525                 }
3526 #else
3527                 cmd = SIOCGIWSCAN;
3528                 wrqu.data.length = strlen(extra);
3529                 WL_TRACE("Event WLC_E_SCAN_COMPLETE\n");
3530 #endif
3531                 break;
3532
3533         case WLC_E_PFN_NET_FOUND:
3534                 {
3535                         wlc_ssid_t *ssid;
3536                         ssid = (wlc_ssid_t *) data;
3537                         WL_ERROR("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n",
3538                                  __func__, PNO_EVENT_UP,
3539                                  ssid->SSID, ssid->SSID_len);
3540                         cmd = IWEVCUSTOM;
3541                         memset(&wrqu, 0, sizeof(wrqu));
3542                         strcpy(extra, PNO_EVENT_UP);
3543                         wrqu.data.length = strlen(extra);
3544                 }
3545                 break;
3546
3547         default:
3548                 WL_TRACE("Unknown Event %d: ignoring\n", event_type);
3549                 break;
3550         }
3551 #ifndef SANDGATE2G
3552         if (cmd) {
3553                 if (cmd == SIOCGIWSCAN)
3554                         wireless_send_event(dev, cmd, &wrqu, NULL);
3555                 else
3556                         wireless_send_event(dev, cmd, &wrqu, extra);
3557         }
3558 #endif
3559
3560 #if WIRELESS_EXT > 14
3561         memset(extra, 0, sizeof(extra));
3562         if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
3563                 cmd = IWEVCUSTOM;
3564                 wrqu.data.length = strlen(extra);
3565 #ifndef SANDGATE2G
3566                 wireless_send_event(dev, cmd, &wrqu, extra);
3567 #endif
3568         }
3569 #endif                          /* WIRELESS_EXT > 14 */
3570 #endif                          /* WIRELESS_EXT > 13 */
3571 }
3572
3573 int wl_iw_attach(struct net_device *dev, void *dhdp)
3574 {
3575         int params_size;
3576         wl_iw_t *iw;
3577 #if defined(WL_IW_USE_ISCAN)
3578         iscan_info_t *iscan = NULL;
3579
3580         if (!dev)
3581                 return 0;
3582
3583         memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
3584
3585 #ifdef CSCAN
3586         params_size =
3587             (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)) +
3588             (WL_NUMCHANNELS * sizeof(u16)) +
3589             WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
3590 #else
3591         params_size =
3592             (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
3593 #endif
3594         iscan = kzalloc(sizeof(iscan_info_t), GFP_KERNEL);
3595
3596         if (!iscan)
3597                 return -ENOMEM;
3598
3599         iscan->iscan_ex_params_p = kmalloc(params_size, GFP_KERNEL);
3600         if (!iscan->iscan_ex_params_p) {
3601                 kfree(iscan);
3602                 return -ENOMEM;
3603         }
3604         iscan->iscan_ex_param_size = params_size;
3605         iscan->sysioc_tsk = NULL;
3606
3607         g_iscan = iscan;
3608         iscan->dev = dev;
3609         iscan->iscan_state = ISCAN_STATE_IDLE;
3610
3611         iscan->timer_ms = 3000;
3612         init_timer(&iscan->timer);
3613         iscan->timer.data = (unsigned long) iscan;
3614         iscan->timer.function = wl_iw_timerfunc;
3615
3616         sema_init(&iscan->sysioc_sem, 0);
3617         iscan->sysioc_tsk = kthread_run(_iscan_sysioc_thread, iscan,
3618                                         "_iscan_sysioc");
3619         if (IS_ERR(iscan->sysioc_tsk)) {
3620                 iscan->sysioc_tsk = NULL;
3621                 return -ENOMEM;
3622         }
3623 #endif                          /* defined(WL_IW_USE_ISCAN) */
3624
3625         iw = *(wl_iw_t **) netdev_priv(dev);
3626         iw->pub = (dhd_pub_t *) dhdp;
3627         MUTEX_LOCK_INIT(iw->pub);
3628         MUTEX_LOCK_WL_SCAN_SET_INIT();
3629 #ifdef SOFTAP
3630         priv_dev = dev;
3631         MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub);
3632 #endif
3633         g_scan = kzalloc(G_SCAN_RESULTS, GFP_KERNEL);
3634         if (!g_scan)
3635                 return -ENOMEM;
3636
3637         g_scan_specified_ssid = 0;
3638
3639         return 0;
3640 }
3641
3642 void wl_iw_detach(void)
3643 {
3644 #if defined(WL_IW_USE_ISCAN)
3645         iscan_buf_t *buf;
3646         iscan_info_t *iscan = g_iscan;
3647
3648         if (!iscan)
3649                 return;
3650         if (iscan->sysioc_tsk) {
3651                 send_sig(SIGTERM, iscan->sysioc_tsk, 1);
3652                 kthread_stop(iscan->sysioc_tsk);
3653                 iscan->sysioc_tsk = NULL;
3654         }
3655
3656         MUTEX_LOCK_WL_SCAN_SET();
3657         while (iscan->list_hdr) {
3658                 buf = iscan->list_hdr->next;
3659                 kfree(iscan->list_hdr);
3660                 iscan->list_hdr = buf;
3661         }
3662         MUTEX_UNLOCK_WL_SCAN_SET();
3663         kfree(iscan->iscan_ex_params_p);
3664         kfree(iscan);
3665         g_iscan = NULL;
3666 #endif                          /* WL_IW_USE_ISCAN */
3667
3668         kfree(g_scan);
3669
3670         g_scan = NULL;
3671 }
3672
3673 #if defined(BCMDBG)
3674 void osl_assert(char *exp, char *file, int line)
3675 {
3676         char tempbuf[256];
3677         char *basename;
3678
3679         basename = strrchr(file, '/');
3680         /* skip the '/' */
3681         if (basename)
3682                 basename++;
3683
3684         if (!basename)
3685                 basename = file;
3686
3687         snprintf(tempbuf, 256,
3688                  "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
3689                  basename, line);
3690
3691         /*
3692          * Print assert message and give it time to
3693          * be written to /var/log/messages
3694          */
3695         if (!in_interrupt()) {
3696                 const int delay = 3;
3697                 printk(KERN_ERR "%s", tempbuf);
3698                 printk(KERN_ERR "panic in %d seconds\n", delay);
3699                 set_current_state(TASK_INTERRUPTIBLE);
3700                 schedule_timeout(delay * HZ);
3701         }
3702
3703         switch (g_assert_type) {
3704         case 0:
3705                 panic(KERN_ERR "%s", tempbuf);
3706                 break;
3707         case 1:
3708                 printk(KERN_ERR "%s", tempbuf);
3709                 BUG();
3710                 break;
3711         case 2:
3712                 printk(KERN_ERR "%s", tempbuf);
3713                 break;
3714         default:
3715                 break;
3716         }
3717 }
3718 #endif                          /* defined(BCMDBG) */