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