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