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