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