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