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