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