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