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