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