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