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