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