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