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