2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/kthread.h>
18 #include <linux/semaphore.h>
20 #include <linux/netdevice.h>
26 #include <linux/if_arp.h>
27 #include <asm/uaccess.h>
29 #include <dngl_stats.h>
32 #include <linux/ieee80211.h>
33 typedef const struct si_pub si_t;
36 #include <dngl_stats.h>
39 #define WL_ERROR(fmt, args...) printk(fmt, ##args)
40 #define WL_TRACE(fmt, args...) no_printk(fmt, ##args)
41 #define WL_INFORM(fmt, args...) no_printk(fmt, ##args)
42 #define WL_WSEC(fmt, args...) no_printk(fmt, ##args)
43 #define WL_SCAN(fmt, args...) no_printk(fmt, ##args)
47 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | \
48 TKIP_ENABLED | AES_ENABLED))
50 #include <linux/rtnetlink.h>
52 #define WL_IW_USE_ISCAN 1
53 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1
55 bool g_set_essid_before_scan = true;
57 #define WL_IW_IOCTL_CALL(func_call) \
62 static int g_onoff = G_WLAN_SET_ON;
63 wl_iw_extra_params_t g_wl_iw_params;
65 extern bool wl_iw_conn_status_str(u32 event_type, u32 status,
66 u32 reason, char *stringBuf, uint buflen);
68 uint wl_msg_level = WL_ERROR_VAL;
70 #define MAX_WLIW_IOCTL_LEN 1024
72 #ifdef CONFIG_WIRELESS_EXT
74 extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
75 extern int dhd_wait_pend8021x(struct net_device *dev);
79 #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
80 #define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
84 static volatile uint g_scan_specified_ssid;
85 static wlc_ssid_t g_specific_ssid;
87 static wlc_ssid_t g_ssid;
89 #if defined(WL_IW_USE_ISCAN)
90 #define ISCAN_STATE_IDLE 0
91 #define ISCAN_STATE_SCANING 1
93 #define WLC_IW_ISCAN_MAXLEN 2048
94 typedef struct iscan_buf {
95 struct iscan_buf *next;
96 char iscan_buf[WLC_IW_ISCAN_MAXLEN];
99 typedef struct iscan_info {
100 struct net_device *dev;
101 struct timer_list timer;
105 iscan_buf_t *list_hdr;
106 iscan_buf_t *list_cur;
108 struct task_struct *sysioc_tsk;
109 struct semaphore sysioc_sem;
112 char ioctlbuf[WLC_IOCTL_MEDLEN];
114 char ioctlbuf[WLC_IOCTL_SMLEN];
116 wl_iscan_params_t *iscan_ex_params_p;
117 int iscan_ex_param_size;
119 iscan_info_t *g_iscan;
121 static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
123 static void wl_iw_timerfunc(unsigned long data);
124 static void wl_iw_set_event_mask(struct net_device *dev);
125 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action);
126 #endif /* defined(WL_IW_USE_ISCAN) */
129 wl_iw_set_scan(struct net_device *dev,
130 struct iw_request_info *info,
131 union iwreq_data *wrqu, char *extra);
134 wl_iw_get_scan(struct net_device *dev,
135 struct iw_request_info *info,
136 struct iw_point *dwrq, char *extra);
139 wl_iw_get_scan_prep(wl_scan_results_t *list,
140 struct iw_request_info *info, char *extra, short max_size);
142 static void swap_key_from_BE(wl_wsec_key_t *key)
144 key->index = cpu_to_le32(key->index);
145 key->len = cpu_to_le32(key->len);
146 key->algo = cpu_to_le32(key->algo);
147 key->flags = cpu_to_le32(key->flags);
148 key->rxiv.hi = cpu_to_le32(key->rxiv.hi);
149 key->rxiv.lo = cpu_to_le16(key->rxiv.lo);
150 key->iv_initialized = cpu_to_le32(key->iv_initialized);
153 static void swap_key_to_BE(wl_wsec_key_t *key)
155 key->index = le32_to_cpu(key->index);
156 key->len = le32_to_cpu(key->len);
157 key->algo = le32_to_cpu(key->algo);
158 key->flags = le32_to_cpu(key->flags);
159 key->rxiv.hi = le32_to_cpu(key->rxiv.hi);
160 key->rxiv.lo = le16_to_cpu(key->rxiv.lo);
161 key->iv_initialized = le32_to_cpu(key->iv_initialized);
164 static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
172 WL_ERROR("%s: dev is null\n", __func__);
176 WL_INFORM("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d\n",
177 __func__, current->pid, cmd, arg, len);
179 if (g_onoff == G_WLAN_SET_ON) {
180 memset(&ioc, 0, sizeof(ioc));
185 strcpy(ifr.ifr_name, dev->name);
186 ifr.ifr_data = (caddr_t)&ioc;
190 WL_ERROR("%s: Error dev_open: %d\n", __func__, ret);
196 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
199 WL_TRACE("%s: call after driver stop : ignored\n", __func__);
204 static int dev_wlc_intvar_set(struct net_device *dev, char *name, int val)
206 char buf[WLC_IOCTL_SMLEN];
209 val = cpu_to_le32(val);
210 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
213 return dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len);
216 #if defined(WL_IW_USE_ISCAN)
218 dev_iw_iovar_setbuf(struct net_device *dev,
220 void *param, int paramlen, void *bufptr, int buflen)
224 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
230 return dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
234 dev_iw_iovar_getbuf(struct net_device *dev,
236 void *param, int paramlen, void *bufptr, int buflen)
240 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
243 return dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen);
245 #endif /* defined(WL_IW_USE_ISCAN) */
247 #if WIRELESS_EXT > 17
249 dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
251 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
254 buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
257 return dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen);
259 #endif /* WIRELESS_EXT > 17 */
262 dev_wlc_bufvar_get(struct net_device *dev, char *name, char *buf, int buflen)
264 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
268 len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
271 dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf,
274 memcpy(buf, ioctlbuf, buflen);
279 static int dev_wlc_intvar_get(struct net_device *dev, char *name, int *retval)
282 char buf[WLC_IOCTL_SMLEN];
291 bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
294 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
296 *retval = le32_to_cpu(var.val);
301 #if WIRELESS_EXT < 13
302 struct iw_request_info {
307 typedef int (*iw_handler) (struct net_device *dev,
308 struct iw_request_info *info,
309 void *wrqu, char *extra);
313 wl_iw_config_commit(struct net_device *dev,
314 struct iw_request_info *info, void *zwrq, char *extra)
318 struct sockaddr bssid;
320 WL_TRACE("%s: SIOCSIWCOMMIT\n", dev->name);
322 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
326 ssid.SSID_len = le32_to_cpu(ssid.SSID_len);
331 memset(&bssid, 0, sizeof(struct sockaddr));
332 error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETH_ALEN);
334 WL_ERROR("%s: WLC_REASSOC to %s failed\n",
335 __func__, ssid.SSID);
343 wl_iw_get_name(struct net_device *dev,
344 struct iw_request_info *info, char *cwrq, char *extra)
346 WL_TRACE("%s: SIOCGIWNAME\n", dev->name);
348 strcpy(cwrq, "IEEE 802.11-DS");
354 wl_iw_set_freq(struct net_device *dev,
355 struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
360 WL_TRACE("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name);
362 if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
369 } else if (fwrq->e < 6) {
370 while (fwrq->e++ < 6)
373 if (fwrq->m > 4000 && fwrq->m < 5000)
374 sf = WF_CHAN_FACTOR_4_G;
376 chan = wf_mhz2channel(fwrq->m, sf);
378 chan = cpu_to_le32(chan);
380 error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan));
384 g_wl_iw_params.target_channel = chan;
389 wl_iw_get_freq(struct net_device *dev,
390 struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
395 WL_TRACE("%s: SIOCGIWFREQ\n", dev->name);
397 error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
401 fwrq->m = le32_to_cpu(ci.hw_channel);
402 fwrq->e = le32_to_cpu(0);
407 wl_iw_set_mode(struct net_device *dev,
408 struct iw_request_info *info, __u32 *uwrq, char *extra)
410 int infra = 0, ap = 0, error = 0;
412 WL_TRACE("%s: SIOCSIWMODE\n", dev->name);
427 infra = cpu_to_le32(infra);
428 ap = cpu_to_le32(ap);
430 error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra));
434 error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap));
442 wl_iw_get_mode(struct net_device *dev,
443 struct iw_request_info *info, __u32 *uwrq, char *extra)
445 int error, infra = 0, ap = 0;
447 WL_TRACE("%s: SIOCGIWMODE\n", dev->name);
449 error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra));
453 error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap));
457 infra = le32_to_cpu(infra);
458 ap = le32_to_cpu(ap);
459 *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
465 wl_iw_get_range(struct net_device *dev,
466 struct iw_request_info *info,
467 struct iw_point *dwrq, char *extra)
469 struct iw_range *range = (struct iw_range *)extra;
471 wl_rateset_t rateset;
477 int bw_cap = 0, sgi_tx = 0, nmode = 0;
479 u8 nrate_list2copy = 0;
480 u16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
481 {14, 29, 43, 58, 87, 116, 130, 144},
482 {27, 54, 81, 108, 162, 216, 243, 270},
483 {30, 60, 90, 120, 180, 240, 270, 300}
486 WL_TRACE("%s: SIOCGIWRANGE\n", dev->name);
491 channels = kmalloc((MAXCHANNEL + 1) * 4, GFP_KERNEL);
493 WL_ERROR("Could not alloc channels\n");
496 list = (wl_u32_list_t *) channels;
498 dwrq->length = sizeof(struct iw_range);
499 memset(range, 0, sizeof(range));
501 range->min_nwid = range->max_nwid = 0;
503 list->count = cpu_to_le32(MAXCHANNEL);
504 error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels,
505 (MAXCHANNEL + 1) * 4);
510 for (i = 0; i < le32_to_cpu(list->count) && i < IW_MAX_FREQUENCIES;
512 range->freq[i].i = le32_to_cpu(list->element[i]);
514 ch = le32_to_cpu(list->element[i]);
515 if (ch <= CH_MAX_2G_CHANNEL) {
516 range->freq[i].m = ieee80211_dsss_chan_to_freq(ch);
518 range->freq[i].m = ieee80211_ofdm_chan_to_freq(
519 WF_CHAN_FACTOR_5_G/2, ch);
521 range->freq[i].e = 6;
523 range->num_frequency = range->num_channels = i;
525 range->max_qual.qual = 5;
526 range->max_qual.level = 0x100 - 200;
527 range->max_qual.noise = 0x100 - 200;
528 range->sensitivity = 65535;
530 #if WIRELESS_EXT > 11
531 range->avg_qual.qual = 3;
532 range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
533 range->avg_qual.noise = 0x100 - 75;
536 error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
542 rateset.count = le32_to_cpu(rateset.count);
543 range->num_bitrates = rateset.count;
544 for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
545 range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000;
546 dev_wlc_intvar_get(dev, "nmode", &nmode);
547 dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
549 if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
550 dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
551 dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
552 dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci,
553 sizeof(channel_info_t));
554 ci.hw_channel = le32_to_cpu(ci.hw_channel);
556 if (bw_cap == 0 || (bw_cap == 2 && ci.hw_channel <= 14)) {
562 if (bw_cap == 1 || (bw_cap == 2 && ci.hw_channel >= 36)) {
568 range->num_bitrates += 8;
569 for (k = 0; i < range->num_bitrates; k++, i++) {
571 (nrate_list[nrate_list2copy][k]) * 500000;
575 error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i));
581 if (i == WLC_PHY_TYPE_A)
582 range->throughput = 24000000;
584 range->throughput = 1500000;
587 range->max_rts = 2347;
588 range->min_frag = 256;
589 range->max_frag = 2346;
591 range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
592 range->num_encoding_sizes = 4;
593 range->encoding_size[0] = WLAN_KEY_LEN_WEP40;
594 range->encoding_size[1] = WLAN_KEY_LEN_WEP104;
595 #if WIRELESS_EXT > 17
596 range->encoding_size[2] = WLAN_KEY_LEN_TKIP;
598 range->encoding_size[2] = 0;
600 range->encoding_size[3] = WLAN_KEY_LEN_AES_CMAC;
606 range->pmp_flags = 0;
609 range->num_txpower = 2;
610 range->txpower[0] = 1;
611 range->txpower[1] = 255;
612 range->txpower_capa = IW_TXPOW_MWATT;
614 #if WIRELESS_EXT > 10
615 range->we_version_compiled = WIRELESS_EXT;
616 range->we_version_source = 19;
618 range->retry_capa = IW_RETRY_LIMIT;
619 range->retry_flags = IW_RETRY_LIMIT;
620 range->r_time_flags = 0;
621 range->min_retry = 1;
622 range->max_retry = 255;
623 range->min_r_time = 0;
624 range->max_r_time = 0;
627 #if WIRELESS_EXT > 17
628 range->enc_capa = IW_ENC_CAPA_WPA;
629 range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
630 range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
631 range->enc_capa |= IW_ENC_CAPA_WPA2;
633 IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
634 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
635 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
636 IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
637 IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
638 IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
639 #endif /* WIRELESS_EXT > 17 */
646 static int rssi_to_qual(int rssi)
648 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
650 else if (rssi <= WL_IW_RSSI_VERY_LOW)
652 else if (rssi <= WL_IW_RSSI_LOW)
654 else if (rssi <= WL_IW_RSSI_GOOD)
656 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
663 wl_iw_set_spy(struct net_device *dev,
664 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
666 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
667 struct sockaddr *addr = (struct sockaddr *)extra;
670 WL_TRACE("%s: SIOCSIWSPY\n", dev->name);
675 iw->spy_num = min_t(int, ARRAY_SIZE(iw->spy_addr), dwrq->length);
676 for (i = 0; i < iw->spy_num; i++)
677 memcpy(iw->spy_addr[i], addr[i].sa_data, ETH_ALEN);
678 memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
684 wl_iw_get_spy(struct net_device *dev,
685 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
687 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
688 struct sockaddr *addr = (struct sockaddr *)extra;
689 struct iw_quality *qual = (struct iw_quality *)&addr[iw->spy_num];
692 WL_TRACE("%s: SIOCGIWSPY\n", dev->name);
697 dwrq->length = iw->spy_num;
698 for (i = 0; i < iw->spy_num; i++) {
699 memcpy(addr[i].sa_data, iw->spy_addr[i], ETH_ALEN);
700 addr[i].sa_family = AF_UNIX;
701 memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
702 iw->spy_qual[i].updated = 0;
709 wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params,
710 int *join_params_size)
712 chanspec_t chanspec = 0;
715 join_params->params.chanspec_num = 1;
716 join_params->params.chanspec_list[0] = ch;
718 if (join_params->params.chanspec_list[0])
719 chanspec |= WL_CHANSPEC_BAND_2G;
721 chanspec |= WL_CHANSPEC_BAND_5G;
723 chanspec |= WL_CHANSPEC_BW_20;
724 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
726 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
727 join_params->params.chanspec_num * sizeof(chanspec_t);
729 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
730 join_params->params.chanspec_list[0] |= chanspec;
731 join_params->params.chanspec_list[0] =
732 cpu_to_le16(join_params->params.chanspec_list[0]);
734 join_params->params.chanspec_num =
735 cpu_to_le32(join_params->params.chanspec_num);
737 WL_TRACE("%s join_params->params.chanspec_list[0]= %X\n",
738 __func__, join_params->params.chanspec_list[0]);
744 wl_iw_set_wap(struct net_device *dev,
745 struct iw_request_info *info, struct sockaddr *awrq, char *extra)
748 wl_join_params_t join_params;
749 int join_params_size;
751 WL_TRACE("%s: SIOCSIWAP\n", dev->name);
753 if (awrq->sa_family != ARPHRD_ETHER) {
754 WL_ERROR("Invalid Header...sa_family\n");
758 if (is_broadcast_ether_addr(awrq->sa_data) ||
759 is_zero_ether_addr(awrq->sa_data)) {
761 memset(&scbval, 0, sizeof(scb_val_t));
762 (void)dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
767 memset(&join_params, 0, sizeof(join_params));
768 join_params_size = sizeof(join_params.ssid);
770 memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
771 join_params.ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
772 memcpy(&join_params.params.bssid, awrq->sa_data, ETH_ALEN);
774 WL_TRACE("%s target_channel=%d\n",
775 __func__, g_wl_iw_params.target_channel);
776 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
779 error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
782 WL_ERROR("%s Invalid ioctl data=%d\n", __func__, error);
785 if (g_ssid.SSID_len) {
786 WL_TRACE("%s: join SSID=%s BSSID=%pM ch=%d\n",
787 __func__, g_ssid.SSID, awrq->sa_data,
788 g_wl_iw_params.target_channel);
791 memset(&g_ssid, 0, sizeof(g_ssid));
796 wl_iw_get_wap(struct net_device *dev,
797 struct iw_request_info *info, struct sockaddr *awrq, char *extra)
799 WL_TRACE("%s: SIOCGIWAP\n", dev->name);
801 awrq->sa_family = ARPHRD_ETHER;
802 memset(awrq->sa_data, 0, ETH_ALEN);
804 (void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETH_ALEN);
809 #if WIRELESS_EXT > 17
811 wl_iw_mlme(struct net_device *dev,
812 struct iw_request_info *info, struct sockaddr *awrq, char *extra)
814 struct iw_mlme *mlme;
818 WL_TRACE("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name);
820 mlme = (struct iw_mlme *)extra;
822 WL_ERROR("Invalid ioctl data\n");
826 scbval.val = mlme->reason_code;
827 memcpy(&scbval.ea, &mlme->addr.sa_data, ETH_ALEN);
829 if (mlme->cmd == IW_MLME_DISASSOC) {
830 scbval.val = cpu_to_le32(scbval.val);
832 dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
834 } else if (mlme->cmd == IW_MLME_DEAUTH) {
835 scbval.val = cpu_to_le32(scbval.val);
837 dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
838 &scbval, sizeof(scb_val_t));
840 WL_ERROR("Invalid ioctl data\n");
846 #endif /* WIRELESS_EXT > 17 */
848 #ifndef WL_IW_USE_ISCAN
850 wl_iw_get_aplist(struct net_device *dev,
851 struct iw_request_info *info,
852 struct iw_point *dwrq, char *extra)
854 wl_scan_results_t *list;
855 struct sockaddr *addr = (struct sockaddr *)extra;
856 struct iw_quality qual[IW_MAX_AP];
857 wl_bss_info_t *bi = NULL;
859 uint buflen = dwrq->length;
861 WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
866 list = kmalloc(buflen, GFP_KERNEL);
869 memset(list, 0, buflen);
870 list->buflen = cpu_to_le32(buflen);
871 error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen);
873 WL_ERROR("%d: Scan results error %d\n", __LINE__, error);
877 list->buflen = le32_to_cpu(list->buflen);
878 list->version = le32_to_cpu(list->version);
879 list->count = le32_to_cpu(list->count);
880 if (list->version != WL_BSS_INFO_VERSION) {
881 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
882 __func__, list->version);
887 for (i = 0, dwrq->length = 0;
888 i < list->count && dwrq->length < IW_MAX_AP; i++) {
889 bi = bi ? (wl_bss_info_t *) ((unsigned long)bi +
890 le32_to_cpu(bi->length)) : list->
892 ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
893 ((unsigned long)list + buflen));
895 if (!(le16_to_cpu(bi->capability) & WLAN_CAPABILITY_ESS))
898 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETH_ALEN);
899 addr[dwrq->length].sa_family = ARPHRD_ETHER;
900 qual[dwrq->length].qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
901 qual[dwrq->length].level = 0x100 + le16_to_cpu(bi->RSSI);
902 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
904 #if WIRELESS_EXT > 18
905 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
907 qual[dwrq->length].updated = 7;
915 memcpy(&addr[dwrq->length], qual,
916 sizeof(struct iw_quality) * dwrq->length);
922 #endif /* WL_IW_USE_ISCAN */
924 #ifdef WL_IW_USE_ISCAN
926 wl_iw_iscan_get_aplist(struct net_device *dev,
927 struct iw_request_info *info,
928 struct iw_point *dwrq, char *extra)
930 wl_scan_results_t *list;
932 iscan_info_t *iscan = g_iscan;
934 struct sockaddr *addr = (struct sockaddr *)extra;
935 struct iw_quality qual[IW_MAX_AP];
936 wl_bss_info_t *bi = NULL;
939 WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
944 if ((!iscan) || (!iscan->sysioc_tsk)) {
945 WL_ERROR("%s error\n", __func__);
949 buf = iscan->list_hdr;
951 list = &((wl_iscan_results_t *) buf->iscan_buf)->results;
952 if (list->version != WL_BSS_INFO_VERSION) {
953 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
954 __func__, list->version);
959 for (i = 0, dwrq->length = 0;
960 i < list->count && dwrq->length < IW_MAX_AP; i++) {
961 bi = bi ? (wl_bss_info_t *) ((unsigned long)bi +
962 le32_to_cpu(bi->length)) :
964 ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
965 ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
967 if (!(le16_to_cpu(bi->capability) &
968 WLAN_CAPABILITY_ESS))
971 memcpy(addr[dwrq->length].sa_data, &bi->BSSID,
973 addr[dwrq->length].sa_family = ARPHRD_ETHER;
974 qual[dwrq->length].qual =
975 rssi_to_qual(le16_to_cpu(bi->RSSI));
976 qual[dwrq->length].level = 0x100 +
977 le16_to_cpu(bi->RSSI);
978 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
980 #if WIRELESS_EXT > 18
981 qual[dwrq->length].updated =
982 IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
984 qual[dwrq->length].updated = 7;
992 memcpy(&addr[dwrq->length], qual,
993 sizeof(struct iw_quality) * dwrq->length);
1000 static int wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
1004 memcpy(params->bssid, ether_bcast, ETH_ALEN);
1005 params->bss_type = DOT11_BSSTYPE_ANY;
1006 params->scan_type = 0;
1007 params->nprobes = -1;
1008 params->active_time = -1;
1009 params->passive_time = -1;
1010 params->home_time = -1;
1011 params->channel_num = 0;
1013 params->nprobes = cpu_to_le32(params->nprobes);
1014 params->active_time = cpu_to_le32(params->active_time);
1015 params->passive_time = cpu_to_le32(params->passive_time);
1016 params->home_time = cpu_to_le32(params->home_time);
1017 if (ssid && ssid->SSID_len)
1018 memcpy(¶ms->ssid, ssid, sizeof(wlc_ssid_t));
1023 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action)
1027 iscan->iscan_ex_params_p->version = cpu_to_le32(ISCAN_REQ_VERSION);
1028 iscan->iscan_ex_params_p->action = cpu_to_le16(action);
1029 iscan->iscan_ex_params_p->scan_duration = cpu_to_le16(0);
1031 WL_SCAN("%s : nprobes=%d\n",
1032 __func__, iscan->iscan_ex_params_p->params.nprobes);
1033 WL_SCAN("active_time=%d\n",
1034 iscan->iscan_ex_params_p->params.active_time);
1035 WL_SCAN("passive_time=%d\n",
1036 iscan->iscan_ex_params_p->params.passive_time);
1037 WL_SCAN("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time);
1038 WL_SCAN("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type);
1039 WL_SCAN("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type);
1041 (void)dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p,
1042 iscan->iscan_ex_param_size, iscan->ioctlbuf,
1043 sizeof(iscan->ioctlbuf));
1048 static void wl_iw_timerfunc(unsigned long data)
1050 iscan_info_t *iscan = (iscan_info_t *) data;
1052 iscan->timer_on = 0;
1053 if (iscan->iscan_state != ISCAN_STATE_IDLE) {
1054 WL_TRACE("timer trigger\n");
1055 up(&iscan->sysioc_sem);
1060 static void wl_iw_set_event_mask(struct net_device *dev)
1062 char eventmask[WL_EVENTING_MASK_LEN];
1063 char iovbuf[WL_EVENTING_MASK_LEN + 12];
1065 dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
1066 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
1067 setbit(eventmask, WLC_E_SCAN_COMPLETE);
1068 dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
1069 iovbuf, sizeof(iovbuf));
1072 static u32 wl_iw_iscan_get(iscan_info_t *iscan)
1076 wl_iscan_results_t *list_buf;
1077 wl_iscan_results_t list;
1078 wl_scan_results_t *results;
1082 MUTEX_LOCK_WL_SCAN_SET();
1083 if (iscan->list_cur) {
1084 buf = iscan->list_cur;
1085 iscan->list_cur = buf->next;
1087 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
1089 WL_ERROR("%s can't alloc iscan_buf_t : going to abort current iscan\n",
1091 MUTEX_UNLOCK_WL_SCAN_SET();
1092 return WL_SCAN_RESULTS_NO_MEM;
1095 if (!iscan->list_hdr)
1096 iscan->list_hdr = buf;
1098 ptr = iscan->list_hdr;
1105 memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1106 list_buf = (wl_iscan_results_t *) buf->iscan_buf;
1107 results = &list_buf->results;
1108 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1109 results->version = 0;
1112 memset(&list, 0, sizeof(list));
1113 list.results.buflen = cpu_to_le32(WLC_IW_ISCAN_MAXLEN);
1114 res = dev_iw_iovar_getbuf(iscan->dev,
1117 WL_ISCAN_RESULTS_FIXED_SIZE,
1118 buf->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1120 results->buflen = le32_to_cpu(results->buflen);
1121 results->version = le32_to_cpu(results->version);
1122 results->count = le32_to_cpu(results->count);
1123 WL_TRACE("results->count = %d\n", results->count);
1124 WL_TRACE("results->buflen = %d\n", results->buflen);
1125 status = le32_to_cpu(list_buf->status);
1127 WL_ERROR("%s returns error %d\n", __func__, res);
1128 status = WL_SCAN_RESULTS_NO_MEM;
1130 MUTEX_UNLOCK_WL_SCAN_SET();
1134 static void wl_iw_force_specific_scan(iscan_info_t *iscan)
1136 WL_TRACE("%s force Specific SCAN for %s\n",
1137 __func__, g_specific_ssid.SSID);
1140 (void)dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid,
1141 sizeof(g_specific_ssid));
1146 static void wl_iw_send_scan_complete(iscan_info_t *iscan)
1149 union iwreq_data wrqu;
1151 memset(&wrqu, 0, sizeof(wrqu));
1153 wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
1154 WL_TRACE("Send Event ISCAN complete\n");
1158 static int _iscan_sysioc_thread(void *data)
1161 iscan_info_t *iscan = (iscan_info_t *) data;
1162 static bool iscan_pass_abort = false;
1164 allow_signal(SIGTERM);
1165 status = WL_SCAN_RESULTS_PARTIAL;
1166 while (down_interruptible(&iscan->sysioc_sem) == 0) {
1167 if (kthread_should_stop())
1170 if (iscan->timer_on) {
1171 del_timer_sync(&iscan->timer);
1172 iscan->timer_on = 0;
1175 status = wl_iw_iscan_get(iscan);
1177 if (g_scan_specified_ssid && (iscan_pass_abort == true)) {
1178 WL_TRACE("%s Get results from specific scan status = %d\n",
1180 wl_iw_send_scan_complete(iscan);
1181 iscan_pass_abort = false;
1186 case WL_SCAN_RESULTS_PARTIAL:
1187 WL_TRACE("iscanresults incomplete\n");
1189 wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
1191 mod_timer(&iscan->timer,
1192 jiffies + iscan->timer_ms * HZ / 1000);
1193 iscan->timer_on = 1;
1195 case WL_SCAN_RESULTS_SUCCESS:
1196 WL_TRACE("iscanresults complete\n");
1197 iscan->iscan_state = ISCAN_STATE_IDLE;
1198 wl_iw_send_scan_complete(iscan);
1200 case WL_SCAN_RESULTS_PENDING:
1201 WL_TRACE("iscanresults pending\n");
1202 mod_timer(&iscan->timer,
1203 jiffies + iscan->timer_ms * HZ / 1000);
1204 iscan->timer_on = 1;
1206 case WL_SCAN_RESULTS_ABORTED:
1207 WL_TRACE("iscanresults aborted\n");
1208 iscan->iscan_state = ISCAN_STATE_IDLE;
1209 if (g_scan_specified_ssid == 0)
1210 wl_iw_send_scan_complete(iscan);
1212 iscan_pass_abort = true;
1213 wl_iw_force_specific_scan(iscan);
1216 case WL_SCAN_RESULTS_NO_MEM:
1217 WL_TRACE("iscanresults can't alloc memory: skip\n");
1218 iscan->iscan_state = ISCAN_STATE_IDLE;
1221 WL_TRACE("iscanresults returned unknown status %d\n",
1227 if (iscan->timer_on) {
1228 del_timer_sync(&iscan->timer);
1229 iscan->timer_on = 0;
1233 #endif /* WL_IW_USE_ISCAN */
1236 wl_iw_set_scan(struct net_device *dev,
1237 struct iw_request_info *info,
1238 union iwreq_data *wrqu, char *extra)
1241 WL_TRACE("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name);
1243 g_set_essid_before_scan = false;
1245 WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1249 if (g_onoff == G_WLAN_SET_OFF)
1252 memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
1253 #ifndef WL_IW_USE_ISCAN
1254 g_scan_specified_ssid = 0;
1257 #if WIRELESS_EXT > 17
1258 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1259 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1260 struct iw_scan_req *req = (struct iw_scan_req *)extra;
1261 if (g_scan_specified_ssid) {
1262 WL_TRACE("%s Specific SCAN is not done ignore scan for = %s\n",
1263 __func__, req->essid);
1266 g_specific_ssid.SSID_len = min_t(size_t,
1267 sizeof(g_specific_ssid.SSID),
1269 memcpy(g_specific_ssid.SSID, req->essid,
1270 g_specific_ssid.SSID_len);
1271 g_specific_ssid.SSID_len =
1272 cpu_to_le32(g_specific_ssid.SSID_len);
1273 g_scan_specified_ssid = 1;
1274 WL_TRACE("### Specific scan ssid=%s len=%d\n",
1275 g_specific_ssid.SSID,
1276 g_specific_ssid.SSID_len);
1280 #endif /* WIRELESS_EXT > 17 */
1281 error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid,
1282 sizeof(g_specific_ssid));
1284 WL_TRACE("#### Set SCAN for %s failed with %d\n",
1285 g_specific_ssid.SSID, error);
1286 g_scan_specified_ssid = 0;
1293 #ifdef WL_IW_USE_ISCAN
1294 int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
1297 iscan_info_t *iscan = g_iscan;
1302 wl_iw_set_event_mask(dev);
1304 WL_TRACE("+++: Set Broadcast ISCAN\n");
1305 memset(&ssid, 0, sizeof(ssid));
1307 iscan->list_cur = iscan->list_hdr;
1308 iscan->iscan_state = ISCAN_STATE_SCANING;
1310 memset(&iscan->iscan_ex_params_p->params, 0,
1311 iscan->iscan_ex_param_size);
1312 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
1313 wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
1318 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
1320 iscan->timer_on = 1;
1326 wl_iw_iscan_set_scan(struct net_device *dev,
1327 struct iw_request_info *info,
1328 union iwreq_data *wrqu, char *extra)
1331 iscan_info_t *iscan = g_iscan;
1333 WL_TRACE("%s: SIOCSIWSCAN : ISCAN\n", dev->name);
1336 WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1340 if (g_onoff == G_WLAN_SET_OFF) {
1341 WL_TRACE("%s: driver is not up yet after START\n", __func__);
1345 if (dhd_dev_get_pno_status(dev)) {
1346 WL_ERROR("%s: Scan called when PNO is active\n", __func__);
1350 if ((!iscan) || (!iscan->sysioc_tsk))
1351 return wl_iw_set_scan(dev, info, wrqu, extra);
1353 if (g_scan_specified_ssid) {
1354 WL_TRACE("%s Specific SCAN already running ignoring BC scan\n",
1359 memset(&ssid, 0, sizeof(ssid));
1361 #if WIRELESS_EXT > 17
1362 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1363 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1364 struct iw_scan_req *req = (struct iw_scan_req *)extra;
1365 ssid.SSID_len = min_t(size_t, sizeof(ssid.SSID),
1367 memcpy(ssid.SSID, req->essid, ssid.SSID_len);
1368 ssid.SSID_len = cpu_to_le32(ssid.SSID_len);
1370 g_scan_specified_ssid = 0;
1372 if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1373 WL_TRACE("%s ISCAN already in progress\n",
1379 #endif /* WIRELESS_EXT > 17 */
1380 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1384 #endif /* WL_IW_USE_ISCAN */
1386 #if WIRELESS_EXT > 17
1387 static bool ie_is_wpa_ie(u8 **wpaie, u8 **tlvs, int *tlvs_len)
1393 !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
1398 *tlvs_len -= (int)(ie - *tlvs);
1403 static bool ie_is_wps_ie(u8 **wpsie, u8 **tlvs, int *tlvs_len)
1409 !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
1414 *tlvs_len -= (int)(ie - *tlvs);
1418 #endif /* WIRELESS_EXT > 17 */
1421 wl_iw_handle_scanresults_ies(char **event_p, char *end,
1422 struct iw_request_info *info, wl_bss_info_t *bi)
1424 #if WIRELESS_EXT > 17
1425 struct iw_event iwe;
1429 if (bi->ie_length) {
1431 u8 *ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1432 int ptr_len = bi->ie_length;
1434 ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID);
1436 iwe.cmd = IWEVGENIE;
1437 iwe.u.data.length = ie->len + 2;
1439 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1442 ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1444 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
1445 if (ie_is_wps_ie(((u8 **)&ie), &ptr, &ptr_len)) {
1446 iwe.cmd = IWEVGENIE;
1447 iwe.u.data.length = ie->len + 2;
1449 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1455 ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1456 ptr_len = bi->ie_length;
1457 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
1458 if (ie_is_wpa_ie(((u8 **)&ie), &ptr, &ptr_len)) {
1459 iwe.cmd = IWEVGENIE;
1460 iwe.u.data.length = ie->len + 2;
1462 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1470 #endif /* WIRELESS_EXT > 17 */
1475 wl_iw_get_scan_prep(wl_scan_results_t *list,
1476 struct iw_request_info *info, char *extra, short max_size)
1479 struct iw_event iwe;
1480 wl_bss_info_t *bi = NULL;
1481 char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
1486 for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
1487 if (list->version != WL_BSS_INFO_VERSION) {
1488 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1489 __func__, list->version);
1493 bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1494 le32_to_cpu(bi->length)) : list->
1497 WL_TRACE("%s : %s\n", __func__, bi->SSID);
1499 iwe.cmd = SIOCGIWAP;
1500 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1501 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETH_ALEN);
1503 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1505 iwe.u.data.length = le32_to_cpu(bi->SSID_len);
1506 iwe.cmd = SIOCGIWESSID;
1507 iwe.u.data.flags = 1;
1508 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
1510 if (le16_to_cpu(bi->capability) & (WLAN_CAPABILITY_ESS |
1511 WLAN_CAPABILITY_IBSS)) {
1512 iwe.cmd = SIOCGIWMODE;
1513 if (le16_to_cpu(bi->capability) & WLAN_CAPABILITY_ESS)
1514 iwe.u.mode = IW_MODE_INFRA;
1516 iwe.u.mode = IW_MODE_ADHOC;
1518 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1522 iwe.cmd = SIOCGIWFREQ;
1524 if (CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL)
1525 iwe.u.freq.m = ieee80211_dsss_chan_to_freq(
1526 CHSPEC_CHANNEL(bi->chanspec));
1528 iwe.u.freq.m = ieee80211_ofdm_chan_to_freq(
1529 WF_CHAN_FACTOR_5_G/2,
1530 CHSPEC_CHANNEL(bi->chanspec));
1534 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1538 iwe.u.qual.qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
1539 iwe.u.qual.level = 0x100 + le16_to_cpu(bi->RSSI);
1540 iwe.u.qual.noise = 0x100 + bi->phy_noise;
1542 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1545 wl_iw_handle_scanresults_ies(&event, end, info, bi);
1547 iwe.cmd = SIOCGIWENCODE;
1548 if (le16_to_cpu(bi->capability) & WLAN_CAPABILITY_PRIVACY)
1549 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1551 iwe.u.data.flags = IW_ENCODE_DISABLED;
1552 iwe.u.data.length = 0;
1554 IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
1556 if (bi->rateset.count) {
1557 if (((event - extra) +
1558 IW_EV_LCP_LEN) <= (unsigned long)end) {
1559 value = event + IW_EV_LCP_LEN;
1560 iwe.cmd = SIOCGIWRATE;
1561 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled =
1564 j < bi->rateset.count
1565 && j < IW_MAX_BITRATES; j++) {
1566 iwe.u.bitrate.value =
1567 (bi->rateset.rates[j] & 0x7f) *
1570 IWE_STREAM_ADD_VALUE(info, event,
1579 ret = event - extra;
1581 WL_ERROR("==> Wrong size\n");
1584 WL_TRACE("%s: size=%d bytes prepared\n",
1585 __func__, (unsigned int)(event - extra));
1590 wl_iw_get_scan(struct net_device *dev,
1591 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1594 wl_scan_results_t *list_merge;
1595 wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
1597 uint buflen_from_user = dwrq->length;
1598 uint len = G_SCAN_RESULTS;
1600 #if defined(WL_IW_USE_ISCAN)
1601 iscan_info_t *iscan = g_iscan;
1605 WL_TRACE("%s: buflen_from_user %d:\n", dev->name, buflen_from_user);
1608 WL_TRACE("%s: wl_iw_get_scan return -EINVAL\n", dev->name);
1612 error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
1615 ci.scan_channel = le32_to_cpu(ci.scan_channel);
1616 if (ci.scan_channel)
1619 if (g_scan_specified_ssid) {
1620 list = kmalloc(len, GFP_KERNEL);
1622 WL_TRACE("%s: wl_iw_get_scan return -ENOMEM\n",
1624 g_scan_specified_ssid = 0;
1629 memset(list, 0, len);
1630 list->buflen = cpu_to_le32(len);
1631 error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len);
1633 WL_ERROR("%s: %s : Scan_results ERROR %d\n",
1634 dev->name, __func__, error);
1636 if (g_scan_specified_ssid) {
1637 g_scan_specified_ssid = 0;
1642 list->buflen = le32_to_cpu(list->buflen);
1643 list->version = le32_to_cpu(list->version);
1644 list->count = le32_to_cpu(list->count);
1646 if (list->version != WL_BSS_INFO_VERSION) {
1647 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1648 __func__, list->version);
1649 if (g_scan_specified_ssid) {
1650 g_scan_specified_ssid = 0;
1656 if (g_scan_specified_ssid) {
1657 WL_TRACE("%s: Specified scan APs in the list =%d\n",
1658 __func__, list->count);
1660 (__u16) wl_iw_get_scan_prep(list, info, extra,
1664 #if defined(WL_IW_USE_ISCAN)
1665 p_buf = iscan->list_hdr;
1666 while (p_buf != iscan->list_cur) {
1668 &((wl_iscan_results_t *) p_buf->iscan_buf)->results;
1669 WL_TRACE("%s: Bcast APs list=%d\n",
1670 __func__, list_merge->count);
1671 if (list_merge->count > 0)
1673 (__u16) wl_iw_get_scan_prep(list_merge,
1674 info, extra + len_ret,
1675 buflen_from_user - len_ret);
1676 p_buf = p_buf->next;
1679 list_merge = (wl_scan_results_t *) g_scan;
1680 WL_TRACE("%s: Bcast APs list=%d\n",
1681 __func__, list_merge->count);
1682 if (list_merge->count > 0)
1684 (__u16) wl_iw_get_scan_prep(list_merge, info,
1688 #endif /* defined(WL_IW_USE_ISCAN) */
1690 list = (wl_scan_results_t *) g_scan;
1692 (__u16) wl_iw_get_scan_prep(list, info, extra,
1696 #if defined(WL_IW_USE_ISCAN)
1697 g_scan_specified_ssid = 0;
1699 if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
1705 WL_TRACE("%s return to WE %d bytes APs=%d\n",
1706 __func__, dwrq->length, list->count);
1710 #if defined(WL_IW_USE_ISCAN)
1712 wl_iw_iscan_get_scan(struct net_device *dev,
1713 struct iw_request_info *info,
1714 struct iw_point *dwrq, char *extra)
1716 wl_scan_results_t *list;
1717 struct iw_event iwe;
1718 wl_bss_info_t *bi = NULL;
1721 char *event = extra, *end = extra + dwrq->length, *value;
1722 iscan_info_t *iscan = g_iscan;
1727 WL_TRACE("%s %s buflen_from_user %d:\n",
1728 dev->name, __func__, dwrq->length);
1731 WL_TRACE("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
1736 if ((!iscan) || (!iscan->sysioc_tsk)) {
1737 WL_ERROR("%ssysioc_tsk\n", __func__);
1738 return wl_iw_get_scan(dev, info, dwrq, extra);
1741 if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1742 WL_TRACE("%s: SIOCGIWSCAN GET still scanning\n", dev->name);
1746 WL_TRACE("%s: SIOCGIWSCAN GET broadcast results\n", dev->name);
1748 p_buf = iscan->list_hdr;
1749 while (p_buf != iscan->list_cur) {
1750 list = &((wl_iscan_results_t *) p_buf->iscan_buf)->results;
1752 counter += list->count;
1754 if (list->version != WL_BSS_INFO_VERSION) {
1755 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1756 __func__, list->version);
1761 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP;
1763 bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1764 le32_to_cpu(bi->length)) :
1766 ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
1767 ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
1769 if (event + ETH_ALEN + bi->SSID_len +
1770 IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >=
1773 iwe.cmd = SIOCGIWAP;
1774 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1775 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID,
1778 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1781 iwe.u.data.length = le32_to_cpu(bi->SSID_len);
1782 iwe.cmd = SIOCGIWESSID;
1783 iwe.u.data.flags = 1;
1785 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1788 if (le16_to_cpu(bi->capability) &
1789 (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
1790 iwe.cmd = SIOCGIWMODE;
1791 if (le16_to_cpu(bi->capability) &
1792 WLAN_CAPABILITY_ESS)
1793 iwe.u.mode = IW_MODE_INFRA;
1795 iwe.u.mode = IW_MODE_ADHOC;
1797 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1801 iwe.cmd = SIOCGIWFREQ;
1804 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
1806 if (channel <= CH_MAX_2G_CHANNEL)
1808 ieee80211_dsss_chan_to_freq(channel);
1810 iwe.u.freq.m = ieee80211_ofdm_chan_to_freq(
1811 WF_CHAN_FACTOR_5_G/2,
1816 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1820 iwe.u.qual.qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
1821 iwe.u.qual.level = 0x100 + le16_to_cpu(bi->RSSI);
1822 iwe.u.qual.noise = 0x100 + bi->phy_noise;
1824 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1827 wl_iw_handle_scanresults_ies(&event, end, info, bi);
1829 iwe.cmd = SIOCGIWENCODE;
1830 if (le16_to_cpu(bi->capability) &
1831 WLAN_CAPABILITY_PRIVACY)
1833 IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1835 iwe.u.data.flags = IW_ENCODE_DISABLED;
1836 iwe.u.data.length = 0;
1838 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1841 if (bi->rateset.count) {
1842 if (event + IW_MAX_BITRATES * IW_EV_PARAM_LEN >=
1846 value = event + IW_EV_LCP_LEN;
1847 iwe.cmd = SIOCGIWRATE;
1848 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled =
1851 j < bi->rateset.count
1852 && j < IW_MAX_BITRATES; j++) {
1853 iwe.u.bitrate.value =
1854 (bi->rateset.rates[j] & 0x7f) *
1857 IWE_STREAM_ADD_VALUE(info, event,
1865 p_buf = p_buf->next;
1868 dwrq->length = event - extra;
1871 WL_TRACE("%s return to WE %d bytes APs=%d\n",
1872 __func__, dwrq->length, counter);
1879 #endif /* defined(WL_IW_USE_ISCAN) */
1882 wl_iw_set_essid(struct net_device *dev,
1883 struct iw_request_info *info,
1884 struct iw_point *dwrq, char *extra)
1887 wl_join_params_t join_params;
1888 int join_params_size;
1890 WL_TRACE("%s: SIOCSIWESSID\n", dev->name);
1892 if (g_set_essid_before_scan)
1895 memset(&g_ssid, 0, sizeof(g_ssid));
1897 CHECK_EXTRA_FOR_NULL(extra);
1899 if (dwrq->length && extra) {
1900 #if WIRELESS_EXT > 20
1901 g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1904 g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1907 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
1909 g_ssid.SSID_len = 0;
1911 g_ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
1913 memset(&join_params, 0, sizeof(join_params));
1914 join_params_size = sizeof(join_params.ssid);
1916 memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
1917 join_params.ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
1918 memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
1920 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
1923 error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
1926 WL_ERROR("Invalid ioctl data=%d\n", error);
1928 if (g_ssid.SSID_len) {
1929 WL_TRACE("%s: join SSID=%s ch=%d\n",
1930 __func__, g_ssid.SSID, g_wl_iw_params.target_channel);
1936 wl_iw_get_essid(struct net_device *dev,
1937 struct iw_request_info *info,
1938 struct iw_point *dwrq, char *extra)
1943 WL_TRACE("%s: SIOCGIWESSID\n", dev->name);
1948 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1950 WL_ERROR("Error getting the SSID\n");
1954 ssid.SSID_len = le32_to_cpu(ssid.SSID_len);
1956 memcpy(extra, ssid.SSID, ssid.SSID_len);
1958 dwrq->length = ssid.SSID_len;
1966 wl_iw_set_nick(struct net_device *dev,
1967 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1969 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
1971 WL_TRACE("%s: SIOCSIWNICKN\n", dev->name);
1976 if (dwrq->length > sizeof(iw->nickname))
1979 memcpy(iw->nickname, extra, dwrq->length);
1980 iw->nickname[dwrq->length - 1] = '\0';
1986 wl_iw_get_nick(struct net_device *dev,
1987 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1989 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
1991 WL_TRACE("%s: SIOCGIWNICKN\n", dev->name);
1996 strcpy(extra, iw->nickname);
1997 dwrq->length = strlen(extra) + 1;
2003 wl_iw_set_rate(struct net_device *dev,
2004 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2006 wl_rateset_t rateset;
2007 int error, rate, i, error_bg, error_a;
2009 WL_TRACE("%s: SIOCSIWRATE\n", dev->name);
2011 error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
2016 rateset.count = le32_to_cpu(rateset.count);
2018 if (vwrq->value < 0)
2019 rate = rateset.rates[rateset.count - 1] & 0x7f;
2020 else if (vwrq->value < rateset.count)
2021 rate = rateset.rates[vwrq->value] & 0x7f;
2023 rate = vwrq->value / 500000;
2026 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
2027 error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
2029 if (error_bg && error_a)
2030 return error_bg | error_a;
2032 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
2033 error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
2035 if (error_bg && error_a)
2036 return error_bg | error_a;
2038 for (i = 0; i < rateset.count; i++)
2039 if ((rateset.rates[i] & 0x7f) > rate)
2041 rateset.count = cpu_to_le32(i);
2043 error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset,
2053 wl_iw_get_rate(struct net_device *dev,
2054 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2058 WL_TRACE("%s: SIOCGIWRATE\n", dev->name);
2060 error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate));
2063 rate = le32_to_cpu(rate);
2064 vwrq->value = rate * 500000;
2070 wl_iw_set_rts(struct net_device *dev,
2071 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2075 WL_TRACE("%s: SIOCSIWRTS\n", dev->name);
2078 rts = DOT11_DEFAULT_RTS_LEN;
2079 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
2084 error = dev_wlc_intvar_set(dev, "rtsthresh", rts);
2092 wl_iw_get_rts(struct net_device *dev,
2093 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2097 WL_TRACE("%s: SIOCGIWRTS\n", dev->name);
2099 error = dev_wlc_intvar_get(dev, "rtsthresh", &rts);
2104 vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
2111 wl_iw_set_frag(struct net_device *dev,
2112 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2116 WL_TRACE("%s: SIOCSIWFRAG\n", dev->name);
2119 frag = DOT11_DEFAULT_FRAG_LEN;
2120 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
2125 error = dev_wlc_intvar_set(dev, "fragthresh", frag);
2133 wl_iw_get_frag(struct net_device *dev,
2134 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2136 int error, fragthreshold;
2138 WL_TRACE("%s: SIOCGIWFRAG\n", dev->name);
2140 error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold);
2144 vwrq->value = fragthreshold;
2145 vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
2152 wl_iw_set_txpow(struct net_device *dev,
2153 struct iw_request_info *info,
2154 struct iw_param *vwrq, char *extra)
2158 WL_TRACE("%s: SIOCSIWTXPOW\n", dev->name);
2160 disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
2161 disable += WL_RADIO_SW_DISABLE << 16;
2163 disable = cpu_to_le32(disable);
2164 error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable));
2168 if (disable & WL_RADIO_SW_DISABLE)
2171 if (!(vwrq->flags & IW_TXPOW_MWATT))
2174 if (vwrq->value < 0)
2177 if (vwrq->value > 0xffff)
2180 txpwrmw = (u16) vwrq->value;
2183 dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
2188 wl_iw_get_txpow(struct net_device *dev,
2189 struct iw_request_info *info,
2190 struct iw_param *vwrq, char *extra)
2192 int error, disable, txpwrdbm;
2195 WL_TRACE("%s: SIOCGIWTXPOW\n", dev->name);
2197 error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable));
2201 error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm);
2205 disable = le32_to_cpu(disable);
2206 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
2207 vwrq->value = (s32) bcm_qdbm_to_mw(result);
2210 (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
2211 vwrq->flags = IW_TXPOW_MWATT;
2216 #if WIRELESS_EXT > 10
2218 wl_iw_set_retry(struct net_device *dev,
2219 struct iw_request_info *info,
2220 struct iw_param *vwrq, char *extra)
2222 int error, lrl, srl;
2224 WL_TRACE("%s: SIOCSIWRETRY\n", dev->name);
2226 if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
2229 if (vwrq->flags & IW_RETRY_LIMIT) {
2231 #if WIRELESS_EXT > 20
2232 if ((vwrq->flags & IW_RETRY_LONG)
2233 || (vwrq->flags & IW_RETRY_MAX)
2234 || !((vwrq->flags & IW_RETRY_SHORT)
2235 || (vwrq->flags & IW_RETRY_MIN))) {
2237 if ((vwrq->flags & IW_RETRY_MAX)
2238 || !(vwrq->flags & IW_RETRY_MIN)) {
2240 lrl = cpu_to_le32(vwrq->value);
2241 error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl,
2246 #if WIRELESS_EXT > 20
2247 if ((vwrq->flags & IW_RETRY_SHORT)
2248 || (vwrq->flags & IW_RETRY_MIN)
2249 || !((vwrq->flags & IW_RETRY_LONG)
2250 || (vwrq->flags & IW_RETRY_MAX))) {
2252 if ((vwrq->flags & IW_RETRY_MIN)
2253 || !(vwrq->flags & IW_RETRY_MAX)) {
2255 srl = cpu_to_le32(vwrq->value);
2256 error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl,
2266 wl_iw_get_retry(struct net_device *dev,
2267 struct iw_request_info *info,
2268 struct iw_param *vwrq, char *extra)
2270 int error, lrl, srl;
2272 WL_TRACE("%s: SIOCGIWRETRY\n", dev->name);
2276 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
2279 error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl));
2283 error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl));
2287 lrl = le32_to_cpu(lrl);
2288 srl = le32_to_cpu(srl);
2290 if (vwrq->flags & IW_RETRY_MAX) {
2291 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
2294 vwrq->flags = IW_RETRY_LIMIT;
2297 vwrq->flags |= IW_RETRY_MIN;
2302 #endif /* WIRELESS_EXT > 10 */
2305 wl_iw_set_encode(struct net_device *dev,
2306 struct iw_request_info *info,
2307 struct iw_point *dwrq, char *extra)
2310 int error, val, wsec;
2312 WL_TRACE("%s: SIOCSIWENCODE\n", dev->name);
2314 memset(&key, 0, sizeof(key));
2316 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2317 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2319 val = cpu_to_le32(key.index);
2320 error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2324 val = le32_to_cpu(val);
2328 if (key.index == DOT11_MAX_DEFAULT_KEYS)
2331 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2332 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2336 if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
2337 val = cpu_to_le32(key.index);
2338 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val,
2343 key.len = dwrq->length;
2345 if (dwrq->length > sizeof(key.data))
2348 memcpy(key.data, extra, dwrq->length);
2350 key.flags = WL_PRIMARY_KEY;
2352 case WLAN_KEY_LEN_WEP40:
2353 key.algo = CRYPTO_ALGO_WEP1;
2355 case WLAN_KEY_LEN_WEP104:
2356 key.algo = CRYPTO_ALGO_WEP128;
2358 case WLAN_KEY_LEN_TKIP:
2359 key.algo = CRYPTO_ALGO_TKIP;
2361 case WLAN_KEY_LEN_AES_CMAC:
2362 key.algo = CRYPTO_ALGO_AES_CCM;
2368 swap_key_from_BE(&key);
2369 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2374 val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
2376 error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2380 wsec &= ~(WEP_ENABLED);
2383 error = dev_wlc_intvar_set(dev, "wsec", wsec);
2387 val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
2388 val = cpu_to_le32(val);
2389 error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
2397 wl_iw_get_encode(struct net_device *dev,
2398 struct iw_request_info *info,
2399 struct iw_point *dwrq, char *extra)
2402 int error, val, wsec, auth;
2404 WL_TRACE("%s: SIOCGIWENCODE\n", dev->name);
2406 memset(&key, 0, sizeof(wl_wsec_key_t));
2408 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2409 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2412 error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2416 val = le32_to_cpu(val);
2421 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2423 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2426 error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
2430 error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth));
2434 swap_key_to_BE(&key);
2436 wsec = le32_to_cpu(wsec);
2437 auth = le32_to_cpu(auth);
2438 dwrq->length = min_t(u16, DOT11_MAX_KEY_SIZE, key.len);
2440 dwrq->flags = key.index + 1;
2441 if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)))
2442 dwrq->flags |= IW_ENCODE_DISABLED;
2445 dwrq->flags |= IW_ENCODE_RESTRICTED;
2447 if (dwrq->length && extra)
2448 memcpy(extra, key.data, dwrq->length);
2454 wl_iw_set_power(struct net_device *dev,
2455 struct iw_request_info *info,
2456 struct iw_param *vwrq, char *extra)
2460 WL_TRACE("%s: SIOCSIWPOWER\n", dev->name);
2462 pm = vwrq->disabled ? PM_OFF : PM_MAX;
2464 pm = cpu_to_le32(pm);
2465 error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
2473 wl_iw_get_power(struct net_device *dev,
2474 struct iw_request_info *info,
2475 struct iw_param *vwrq, char *extra)
2479 WL_TRACE("%s: SIOCGIWPOWER\n", dev->name);
2481 error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
2485 pm = le32_to_cpu(pm);
2486 vwrq->disabled = pm ? 0 : 1;
2487 vwrq->flags = IW_POWER_ALL_R;
2492 #if WIRELESS_EXT > 17
2494 wl_iw_set_wpaie(struct net_device *dev,
2495 struct iw_request_info *info, struct iw_point *iwp, char *extra)
2498 WL_TRACE("%s: SIOCSIWGENIE\n", dev->name);
2500 CHECK_EXTRA_FOR_NULL(extra);
2502 dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
2508 wl_iw_get_wpaie(struct net_device *dev,
2509 struct iw_request_info *info, struct iw_point *iwp, char *extra)
2511 WL_TRACE("%s: SIOCGIWGENIE\n", dev->name);
2513 dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
2518 wl_iw_set_encodeext(struct net_device *dev,
2519 struct iw_request_info *info,
2520 struct iw_point *dwrq, char *extra)
2524 struct iw_encode_ext *iwe;
2526 WL_TRACE("%s: SIOCSIWENCODEEXT\n", dev->name);
2528 CHECK_EXTRA_FOR_NULL(extra);
2530 memset(&key, 0, sizeof(key));
2531 iwe = (struct iw_encode_ext *)extra;
2533 if (dwrq->flags & IW_ENCODE_DISABLED) {
2538 if (dwrq->flags & IW_ENCODE_INDEX)
2539 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2541 key.len = iwe->key_len;
2543 if (!is_multicast_ether_addr(iwe->addr.sa_data))
2544 memcpy(&key.ea, &iwe->addr.sa_data, ETH_ALEN);
2547 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
2548 WL_WSEC("Changing the the primary Key to %d\n",
2550 key.index = cpu_to_le32(key.index);
2551 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
2552 &key.index, sizeof(key.index));
2556 swap_key_from_BE(&key);
2557 dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2560 if (iwe->key_len > sizeof(key.data))
2563 WL_WSEC("Setting the key index %d\n", key.index);
2564 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
2565 WL_WSEC("key is a Primary Key\n");
2566 key.flags = WL_PRIMARY_KEY;
2569 memcpy(key.data, iwe->key, iwe->key_len);
2571 if (iwe->alg == IW_ENCODE_ALG_TKIP) {
2573 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2574 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2575 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2578 if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
2579 unsigned char *ivptr;
2580 ivptr = (unsigned char *) iwe->rx_seq;
2581 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2582 (ivptr[3] << 8) | ivptr[2];
2583 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2584 key.iv_initialized = true;
2588 case IW_ENCODE_ALG_NONE:
2589 key.algo = CRYPTO_ALGO_OFF;
2591 case IW_ENCODE_ALG_WEP:
2592 if (iwe->key_len == WLAN_KEY_LEN_WEP40)
2593 key.algo = CRYPTO_ALGO_WEP1;
2595 key.algo = CRYPTO_ALGO_WEP128;
2597 case IW_ENCODE_ALG_TKIP:
2598 key.algo = CRYPTO_ALGO_TKIP;
2600 case IW_ENCODE_ALG_CCMP:
2601 key.algo = CRYPTO_ALGO_AES_CCM;
2606 swap_key_from_BE(&key);
2608 dhd_wait_pend8021x(dev);
2610 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2617 #if WIRELESS_EXT > 17
2619 pmkid_list_t pmkids;
2620 pmkid_t foo[MAXPMKID - 1];
2624 wl_iw_set_pmksa(struct net_device *dev,
2625 struct iw_request_info *info,
2626 struct iw_param *vwrq, char *extra)
2628 struct iw_pmksa *iwpmksa;
2632 WL_WSEC("%s: SIOCSIWPMKSA\n", dev->name);
2634 CHECK_EXTRA_FOR_NULL(extra);
2636 iwpmksa = (struct iw_pmksa *)extra;
2638 if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
2639 WL_WSEC("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n");
2640 memset((char *)&pmkid_list, 0, sizeof(pmkid_list));
2643 else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
2645 pmkid_list_t pmkid, *pmkidptr;
2649 memcpy(&pmkidptr->pmkid[0].BSSID,
2650 &iwpmksa->bssid.sa_data[0],
2652 memcpy(&pmkidptr->pmkid[0].PMKID,
2656 WL_WSEC("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: "
2657 "%pM = ", &pmkidptr->pmkid[0].BSSID);
2658 for (j = 0; j < WLAN_PMKID_LEN; j++)
2659 WL_WSEC("%02x ", pmkidptr->pmkid[0].PMKID[j]);
2663 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2665 (&iwpmksa->bssid.sa_data[0],
2666 &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
2669 if ((pmkid_list.pmkids.npmkid > 0)
2670 && (i < pmkid_list.pmkids.npmkid)) {
2671 memset(&pmkid_list.pmkids.pmkid[i], 0, sizeof(pmkid_t));
2672 for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
2673 memcpy(&pmkid_list.pmkids.pmkid[i].BSSID,
2674 &pmkid_list.pmkids.pmkid[i + 1].BSSID,
2676 memcpy(&pmkid_list.pmkids.pmkid[i].PMKID,
2677 &pmkid_list.pmkids.pmkid[i + 1].PMKID,
2680 pmkid_list.pmkids.npmkid--;
2685 else if (iwpmksa->cmd == IW_PMKSA_ADD) {
2686 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2688 (&iwpmksa->bssid.sa_data[0],
2689 &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
2692 memcpy(&pmkid_list.pmkids.pmkid[i].BSSID,
2693 &iwpmksa->bssid.sa_data[0],
2695 memcpy(&pmkid_list.pmkids.pmkid[i].PMKID,
2698 if (i == pmkid_list.pmkids.npmkid)
2699 pmkid_list.pmkids.npmkid++;
2705 k = pmkid_list.pmkids.npmkid;
2706 WL_WSEC("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %pM = ",
2707 &pmkid_list.pmkids.pmkid[k].BSSID);
2708 for (j = 0; j < WLAN_PMKID_LEN; j++)
2710 pmkid_list.pmkids.pmkid[k].PMKID[j]);
2714 WL_WSEC("PRINTING pmkid LIST - No of elements %d\n",
2715 pmkid_list.pmkids.npmkid);
2716 for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
2718 WL_WSEC("PMKID[%d]: %pM = ",
2719 i, &pmkid_list.pmkids.pmkid[i].BSSID);
2720 for (j = 0; j < WLAN_PMKID_LEN; j++)
2721 WL_WSEC("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]);
2727 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
2728 sizeof(pmkid_list));
2731 #endif /* WIRELESS_EXT > 17 */
2734 wl_iw_get_encodeext(struct net_device *dev,
2735 struct iw_request_info *info,
2736 struct iw_param *vwrq, char *extra)
2738 WL_TRACE("%s: SIOCGIWENCODEEXT\n", dev->name);
2743 wl_iw_set_wpaauth(struct net_device *dev,
2744 struct iw_request_info *info,
2745 struct iw_param *vwrq, char *extra)
2751 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2753 WL_TRACE("%s: SIOCSIWAUTH\n", dev->name);
2755 paramid = vwrq->flags & IW_AUTH_INDEX;
2756 paramval = vwrq->value;
2758 WL_TRACE("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
2759 dev->name, paramid, paramval);
2762 case IW_AUTH_WPA_VERSION:
2763 if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
2764 val = WPA_AUTH_DISABLED;
2765 else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
2766 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
2767 else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
2768 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
2769 WL_INFORM("%s: %d: setting wpa_auth to 0x%0x\n",
2770 __func__, __LINE__, val);
2771 error = dev_wlc_intvar_set(dev, "wpa_auth", val);
2775 case IW_AUTH_CIPHER_PAIRWISE:
2776 case IW_AUTH_CIPHER_GROUP:
2777 if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
2779 if (paramval & IW_AUTH_CIPHER_TKIP)
2781 if (paramval & IW_AUTH_CIPHER_CCMP)
2784 if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
2792 if (iw->privacy_invoked && !val) {
2793 WL_WSEC("%s: %s: 'Privacy invoked' true but clearing wsec, assuming we're a WPS enrollee\n",
2794 dev->name, __func__);
2795 error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
2798 WL_WSEC("Failed to set is_WPS_enrollee\n");
2802 error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
2805 WL_WSEC("Failed to clear is_WPS_enrollee\n");
2810 error = dev_wlc_intvar_set(dev, "wsec", val);
2816 case IW_AUTH_KEY_MGMT:
2817 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2821 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
2822 if (paramval & IW_AUTH_KEY_MGMT_PSK)
2825 val = WPA_AUTH_UNSPECIFIED;
2826 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
2827 if (paramval & IW_AUTH_KEY_MGMT_PSK)
2828 val = WPA2_AUTH_PSK;
2830 val = WPA2_AUTH_UNSPECIFIED;
2832 WL_INFORM("%s: %d: setting wpa_auth to %d\n",
2833 __func__, __LINE__, val);
2834 error = dev_wlc_intvar_set(dev, "wpa_auth", val);
2839 case IW_AUTH_TKIP_COUNTERMEASURES:
2840 dev_wlc_bufvar_set(dev, "tkip_countermeasures",
2841 (char *)¶mval, 1);
2844 case IW_AUTH_80211_AUTH_ALG:
2845 WL_INFORM("Setting the D11auth %d\n", paramval);
2846 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
2848 else if (paramval == IW_AUTH_ALG_SHARED_KEY)
2850 else if (paramval ==
2851 (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
2856 error = dev_wlc_intvar_set(dev, "auth", val);
2862 case IW_AUTH_WPA_ENABLED:
2863 if (paramval == 0) {
2866 error = dev_wlc_intvar_get(dev, "wsec", &val);
2869 if (val & (TKIP_ENABLED | AES_ENABLED)) {
2870 val &= ~(TKIP_ENABLED | AES_ENABLED);
2871 dev_wlc_intvar_set(dev, "wsec", val);
2874 WL_INFORM("%s: %d: setting wpa_auth to %d\n",
2875 __func__, __LINE__, val);
2876 dev_wlc_intvar_set(dev, "wpa_auth", 0);
2881 case IW_AUTH_DROP_UNENCRYPTED:
2882 dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1);
2885 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
2886 dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol",
2887 (char *)¶mval, 1);
2890 #if WIRELESS_EXT > 17
2891 case IW_AUTH_ROAMING_CONTROL:
2892 WL_INFORM("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
2894 case IW_AUTH_PRIVACY_INVOKED:
2898 if (paramval == 0) {
2899 iw->privacy_invoked = false;
2900 error = dev_wlc_intvar_set(dev,
2901 "is_WPS_enrollee", false);
2903 WL_WSEC("Failed to clear iovar is_WPS_enrollee\n");
2907 iw->privacy_invoked = true;
2908 error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2912 if (!(IW_WSEC_ENABLED(wsec))) {
2913 error = dev_wlc_intvar_set(dev,
2917 WL_WSEC("Failed to set iovar is_WPS_enrollee\n");
2921 error = dev_wlc_intvar_set(dev,
2925 WL_WSEC("Failed to clear is_WPS_enrollee\n");
2932 #endif /* WIRELESS_EXT > 17 */
2939 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
2942 wl_iw_get_wpaauth(struct net_device *dev,
2943 struct iw_request_info *info,
2944 struct iw_param *vwrq, char *extra)
2950 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2952 WL_TRACE("%s: SIOCGIWAUTH\n", dev->name);
2954 paramid = vwrq->flags & IW_AUTH_INDEX;
2957 case IW_AUTH_WPA_VERSION:
2958 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2961 if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
2962 paramval = IW_AUTH_WPA_VERSION_DISABLED;
2963 else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
2964 paramval = IW_AUTH_WPA_VERSION_WPA;
2965 else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
2966 paramval = IW_AUTH_WPA_VERSION_WPA2;
2968 case IW_AUTH_CIPHER_PAIRWISE:
2969 case IW_AUTH_CIPHER_GROUP:
2970 if (paramid == IW_AUTH_CIPHER_PAIRWISE)
2977 if (val & WEP_ENABLED)
2979 (IW_AUTH_CIPHER_WEP40 |
2980 IW_AUTH_CIPHER_WEP104);
2981 if (val & TKIP_ENABLED)
2982 paramval |= (IW_AUTH_CIPHER_TKIP);
2983 if (val & AES_ENABLED)
2984 paramval |= (IW_AUTH_CIPHER_CCMP);
2986 paramval = IW_AUTH_CIPHER_NONE;
2988 case IW_AUTH_KEY_MGMT:
2989 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2993 paramval = IW_AUTH_KEY_MGMT_PSK;
2995 paramval = IW_AUTH_KEY_MGMT_802_1X;
2998 case IW_AUTH_TKIP_COUNTERMEASURES:
2999 dev_wlc_bufvar_get(dev, "tkip_countermeasures",
3000 (char *)¶mval, 1);
3003 case IW_AUTH_DROP_UNENCRYPTED:
3004 dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1);
3007 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
3008 dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol",
3009 (char *)¶mval, 1);
3012 case IW_AUTH_80211_AUTH_ALG:
3013 error = dev_wlc_intvar_get(dev, "auth", &val);
3017 paramval = IW_AUTH_ALG_OPEN_SYSTEM;
3019 paramval = IW_AUTH_ALG_SHARED_KEY;
3021 case IW_AUTH_WPA_ENABLED:
3022 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
3030 #if WIRELESS_EXT > 17
3031 case IW_AUTH_ROAMING_CONTROL:
3032 WL_ERROR("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
3034 case IW_AUTH_PRIVACY_INVOKED:
3035 paramval = iw->privacy_invoked;
3040 vwrq->value = paramval;
3043 #endif /* WIRELESS_EXT > 17 */
3045 static const iw_handler wl_iw_handler[] = {
3046 (iw_handler) wl_iw_config_commit,
3047 (iw_handler) wl_iw_get_name,
3050 (iw_handler) wl_iw_set_freq,
3051 (iw_handler) wl_iw_get_freq,
3052 (iw_handler) wl_iw_set_mode,
3053 (iw_handler) wl_iw_get_mode,
3057 (iw_handler) wl_iw_get_range,
3062 (iw_handler) wl_iw_set_spy,
3063 (iw_handler) wl_iw_get_spy,
3066 (iw_handler) wl_iw_set_wap,
3067 (iw_handler) wl_iw_get_wap,
3068 #if WIRELESS_EXT > 17
3069 (iw_handler) wl_iw_mlme,
3073 #if defined(WL_IW_USE_ISCAN)
3074 (iw_handler) wl_iw_iscan_get_aplist,
3076 (iw_handler) wl_iw_get_aplist,
3078 #if WIRELESS_EXT > 13
3079 #if defined(WL_IW_USE_ISCAN)
3080 (iw_handler) wl_iw_iscan_set_scan,
3081 (iw_handler) wl_iw_iscan_get_scan,
3083 (iw_handler) wl_iw_set_scan,
3084 (iw_handler) wl_iw_get_scan,
3089 #endif /* WIRELESS_EXT > 13 */
3090 (iw_handler) wl_iw_set_essid,
3091 (iw_handler) wl_iw_get_essid,
3092 (iw_handler) wl_iw_set_nick,
3093 (iw_handler) wl_iw_get_nick,
3096 (iw_handler) wl_iw_set_rate,
3097 (iw_handler) wl_iw_get_rate,
3098 (iw_handler) wl_iw_set_rts,
3099 (iw_handler) wl_iw_get_rts,
3100 (iw_handler) wl_iw_set_frag,
3101 (iw_handler) wl_iw_get_frag,
3102 (iw_handler) wl_iw_set_txpow,
3103 (iw_handler) wl_iw_get_txpow,
3104 #if WIRELESS_EXT > 10
3105 (iw_handler) wl_iw_set_retry,
3106 (iw_handler) wl_iw_get_retry,
3108 (iw_handler) wl_iw_set_encode,
3109 (iw_handler) wl_iw_get_encode,
3110 (iw_handler) wl_iw_set_power,
3111 (iw_handler) wl_iw_get_power,
3112 #if WIRELESS_EXT > 17
3115 (iw_handler) wl_iw_set_wpaie,
3116 (iw_handler) wl_iw_get_wpaie,
3117 (iw_handler) wl_iw_set_wpaauth,
3118 (iw_handler) wl_iw_get_wpaauth,
3119 (iw_handler) wl_iw_set_encodeext,
3120 (iw_handler) wl_iw_get_encodeext,
3121 (iw_handler) wl_iw_set_pmksa,
3122 #endif /* WIRELESS_EXT > 17 */
3125 #if WIRELESS_EXT > 12
3127 const struct iw_handler_def wl_iw_handler_def = {
3128 .num_standard = ARRAY_SIZE(wl_iw_handler),
3129 .standard = (iw_handler *) wl_iw_handler,
3131 .num_private_args = 0,
3135 #if WIRELESS_EXT >= 19
3136 .get_wireless_stats = dhd_get_wireless_stats,
3139 #endif /* WIRELESS_EXT > 12 */
3141 int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
3143 struct iwreq *wrq = (struct iwreq *)rq;
3144 struct iw_request_info info;
3147 int token_size = 1, max_tokens = 0, ret = 0;
3149 WL_TRACE("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
3151 if (cmd < SIOCIWFIRST ||
3152 IW_IOCTL_IDX(cmd) >= ARRAY_SIZE(wl_iw_handler)) {
3153 WL_ERROR("%s: error in cmd=%x : out of range\n",
3158 handler = wl_iw_handler[IW_IOCTL_IDX(cmd)];
3160 WL_ERROR("%s: error in cmd=%x : not supported\n",
3171 max_tokens = IW_ESSID_MAX_SIZE + 1;
3176 #if WIRELESS_EXT > 17
3177 case SIOCSIWENCODEEXT:
3178 case SIOCGIWENCODEEXT:
3180 max_tokens = wrq->u.data.length;
3184 max_tokens = sizeof(struct iw_range) + 500;
3189 sizeof(struct sockaddr) + sizeof(struct iw_quality);
3190 max_tokens = IW_MAX_AP;
3193 #if WIRELESS_EXT > 13
3195 #if defined(WL_IW_USE_ISCAN)
3197 max_tokens = wrq->u.data.length;
3200 max_tokens = IW_SCAN_MAX_DATA;
3202 #endif /* WIRELESS_EXT > 13 */
3205 token_size = sizeof(struct sockaddr);
3206 max_tokens = IW_MAX_SPY;
3211 sizeof(struct sockaddr) + sizeof(struct iw_quality);
3212 max_tokens = IW_MAX_SPY;
3215 #if WIRELESS_EXT > 17
3220 max_tokens = wrq->u.data.length;
3224 if (max_tokens && wrq->u.data.pointer) {
3225 if (wrq->u.data.length > max_tokens) {
3226 WL_ERROR("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n",
3227 __func__, cmd, wrq->u.data.length, max_tokens);
3230 extra = kmalloc(max_tokens * token_size, GFP_KERNEL);
3235 (extra, wrq->u.data.pointer,
3236 wrq->u.data.length * token_size)) {
3245 ret = handler(dev, &info, &wrq->u, extra);
3249 (wrq->u.data.pointer, extra,
3250 wrq->u.data.length * token_size)) {
3262 wl_iw_conn_status_str(u32 event_type, u32 status, u32 reason,
3263 char *stringBuf, uint buflen)
3265 typedef struct conn_fail_event_map_t {
3269 const char *outName;
3270 const char *outCause;
3271 } conn_fail_event_map_t;
3273 #define WL_IW_DONT_CARE 9999
3274 const conn_fail_event_map_t event_map[] = {
3275 {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE,
3277 {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
3278 "Conn", "NoNetworks"},
3279 {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3280 "Conn", "ConfigMismatch"},
3281 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH,
3282 "Conn", "EncrypMismatch"},
3283 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH,
3284 "Conn", "RsnMismatch"},
3285 {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
3286 "Conn", "AuthTimeout"},
3287 {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3288 "Conn", "AuthFail"},
3289 {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE,
3290 "Conn", "AuthNoAck"},
3291 {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3292 "Conn", "ReassocFail"},
3293 {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
3294 "Conn", "ReassocTimeout"},
3295 {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE,
3296 "Conn", "ReassocAbort"},
3297 {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE,
3298 "Sup", "ConnSuccess"},
3299 {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3300 "Sup", "WpaHandshakeFail"},
3301 {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3303 {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3304 "Conn", "DisassocInd"},
3305 {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3309 const char *name = "";
3310 const char *cause = NULL;
3313 for (i = 0; i < sizeof(event_map) / sizeof(event_map[0]); i++) {
3314 const conn_fail_event_map_t *row = &event_map[i];
3315 if (row->inEvent == event_type &&
3316 (row->inStatus == status
3317 || row->inStatus == WL_IW_DONT_CARE)
3318 && (row->inReason == reason
3319 || row->inReason == WL_IW_DONT_CARE)) {
3320 name = row->outName;
3321 cause = row->outCause;
3327 memset(stringBuf, 0, buflen);
3328 snprintf(stringBuf, buflen, "%s %s %02d %02d",
3329 name, cause, status, reason);
3330 WL_INFORM("Connection status: %s\n", stringBuf);
3337 #if WIRELESS_EXT > 14
3340 wl_iw_check_conn_fail(wl_event_msg_t *e, char *stringBuf, uint buflen)
3342 u32 event = be32_to_cpu(e->event_type);
3343 u32 status = be32_to_cpu(e->status);
3344 u32 reason = be32_to_cpu(e->reason);
3346 if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
3353 #ifndef IW_CUSTOM_MAX
3354 #define IW_CUSTOM_MAX 256
3357 void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
3359 #if WIRELESS_EXT > 13
3360 union iwreq_data wrqu;
3361 char extra[IW_CUSTOM_MAX + 1];
3363 u32 event_type = be32_to_cpu(e->event_type);
3364 u16 flags = be16_to_cpu(e->flags);
3365 u32 datalen = be32_to_cpu(e->datalen);
3366 u32 status = be32_to_cpu(e->status);
3369 memset(&wrqu, 0, sizeof(wrqu));
3370 memset(extra, 0, sizeof(extra));
3374 WL_ERROR("%s: dev is null\n", __func__);
3378 iw = *(wl_iw_t **) netdev_priv(dev);
3380 WL_TRACE("%s: dev=%s event=%d\n", __func__, dev->name, event_type);
3382 switch (event_type) {
3385 memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3386 wrqu.addr.sa_family = ARPHRD_ETHER;
3388 #if WIRELESS_EXT > 14
3390 case WLC_E_ASSOC_IND:
3391 case WLC_E_REASSOC_IND:
3392 memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3393 wrqu.addr.sa_family = ARPHRD_ETHER;
3394 cmd = IWEVREGISTERED;
3396 case WLC_E_DEAUTH_IND:
3397 case WLC_E_DISASSOC_IND:
3399 memset(wrqu.addr.sa_data, 0, ETH_ALEN);
3400 wrqu.addr.sa_family = ARPHRD_ETHER;
3401 memset(&extra, 0, ETH_ALEN);
3404 case WLC_E_NDIS_LINK:
3406 if (!(flags & WLC_EVENT_MSG_LINK)) {
3407 memset(wrqu.addr.sa_data, 0, ETH_ALEN);
3408 memset(&extra, 0, ETH_ALEN);
3410 memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3411 WL_TRACE("Link UP\n");
3414 wrqu.addr.sa_family = ARPHRD_ETHER;
3416 case WLC_E_ACTION_FRAME:
3418 if (datalen + 1 <= sizeof(extra)) {
3419 wrqu.data.length = datalen + 1;
3420 extra[0] = WLC_E_ACTION_FRAME;
3421 memcpy(&extra[1], data, datalen);
3422 WL_TRACE("WLC_E_ACTION_FRAME len %d\n",
3427 case WLC_E_ACTION_FRAME_COMPLETE:
3429 memcpy(&toto, data, 4);
3430 if (sizeof(status) + 1 <= sizeof(extra)) {
3431 wrqu.data.length = sizeof(status) + 1;
3432 extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
3433 memcpy(&extra[1], &status, sizeof(status));
3434 WL_TRACE("wl_iw_event status %d PacketId %d\n", status,
3436 WL_TRACE("WLC_E_ACTION_FRAME_COMPLETE len %d\n",
3440 #endif /* WIRELESS_EXT > 14 */
3441 #if WIRELESS_EXT > 17
3442 case WLC_E_MIC_ERROR:
3444 struct iw_michaelmicfailure *micerrevt =
3445 (struct iw_michaelmicfailure *)&extra;
3446 cmd = IWEVMICHAELMICFAILURE;
3447 wrqu.data.length = sizeof(struct iw_michaelmicfailure);
3448 if (flags & WLC_EVENT_MSG_GROUP)
3449 micerrevt->flags |= IW_MICFAILURE_GROUP;
3451 micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
3452 memcpy(micerrevt->src_addr.sa_data, &e->addr,
3454 micerrevt->src_addr.sa_family = ARPHRD_ETHER;
3458 case WLC_E_PMKID_CACHE:
3461 struct iw_pmkid_cand *iwpmkidcand =
3462 (struct iw_pmkid_cand *)&extra;
3463 pmkid_cand_list_t *pmkcandlist;
3464 pmkid_cand_t *pmkidcand;
3467 cmd = IWEVPMKIDCAND;
3469 count = get_unaligned_be32(&pmkcandlist->
3472 wrqu.data.length = sizeof(struct iw_pmkid_cand);
3473 pmkidcand = pmkcandlist->pmkid_cand;
3475 memset(iwpmkidcand, 0,
3476 sizeof(struct iw_pmkid_cand));
3477 if (pmkidcand->preauth)
3478 iwpmkidcand->flags |=
3479 IW_PMKID_CAND_PREAUTH;
3480 memcpy(&iwpmkidcand->bssid.sa_data,
3484 wireless_send_event(dev, cmd, &wrqu,
3493 #endif /* WIRELESS_EXT > 17 */
3495 case WLC_E_SCAN_COMPLETE:
3496 #if defined(WL_IW_USE_ISCAN)
3497 if ((g_iscan) && (g_iscan->sysioc_tsk) &&
3498 (g_iscan->iscan_state != ISCAN_STATE_IDLE)) {
3499 up(&g_iscan->sysioc_sem);
3502 wrqu.data.length = strlen(extra);
3503 WL_TRACE("Event WLC_E_SCAN_COMPLETE from specific scan %d\n",
3504 g_iscan->iscan_state);
3508 wrqu.data.length = strlen(extra);
3509 WL_TRACE("Event WLC_E_SCAN_COMPLETE\n");
3513 case WLC_E_PFN_NET_FOUND:
3516 ssid = (wlc_ssid_t *) data;
3517 WL_ERROR("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n",
3518 __func__, PNO_EVENT_UP,
3519 ssid->SSID, ssid->SSID_len);
3521 memset(&wrqu, 0, sizeof(wrqu));
3522 strcpy(extra, PNO_EVENT_UP);
3523 wrqu.data.length = strlen(extra);
3528 WL_TRACE("Unknown Event %d: ignoring\n", event_type);
3533 if (cmd == SIOCGIWSCAN)
3534 wireless_send_event(dev, cmd, &wrqu, NULL);
3536 wireless_send_event(dev, cmd, &wrqu, extra);
3540 #if WIRELESS_EXT > 14
3541 memset(extra, 0, sizeof(extra));
3542 if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
3544 wrqu.data.length = strlen(extra);
3546 wireless_send_event(dev, cmd, &wrqu, extra);
3549 #endif /* WIRELESS_EXT > 14 */
3550 #endif /* WIRELESS_EXT > 13 */
3554 wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
3563 res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise,
3568 phy_noise = le32_to_cpu(phy_noise);
3569 WL_TRACE("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise);
3571 memset(&scb_val, 0, sizeof(scb_val_t));
3572 res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
3576 rssi = le32_to_cpu(scb_val.val);
3577 WL_TRACE("wl_iw_get_wireless_stats rssi=%d\n", rssi);
3578 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
3579 wstats->qual.qual = 0;
3580 else if (rssi <= WL_IW_RSSI_VERY_LOW)
3581 wstats->qual.qual = 1;
3582 else if (rssi <= WL_IW_RSSI_LOW)
3583 wstats->qual.qual = 2;
3584 else if (rssi <= WL_IW_RSSI_GOOD)
3585 wstats->qual.qual = 3;
3586 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
3587 wstats->qual.qual = 4;
3589 wstats->qual.qual = 5;
3591 wstats->qual.level = 0x100 + rssi;
3592 wstats->qual.noise = 0x100 + phy_noise;
3593 #if WIRELESS_EXT > 18
3594 wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
3596 wstats->qual.updated |= 7;
3599 #if WIRELESS_EXT > 11
3600 WL_TRACE("wl_iw_get_wireless_stats counters=%zu\n",
3601 sizeof(struct wl_cnt));
3603 memset(&cnt, 0, sizeof(struct wl_cnt));
3605 dev_wlc_bufvar_get(dev, "counters", (char *)&cnt,
3606 sizeof(struct wl_cnt));
3608 WL_ERROR("wl_iw_get_wireless_stats counters failed error=%d\n",
3613 cnt.version = le16_to_cpu(cnt.version);
3614 if (cnt.version != WL_CNT_T_VERSION) {
3615 WL_TRACE("\tIncorrect counter version: expected %d; got %d\n",
3616 WL_CNT_T_VERSION, cnt.version);
3620 wstats->discard.nwid = 0;
3621 wstats->discard.code = le32_to_cpu(cnt.rxundec);
3622 wstats->discard.fragment = le32_to_cpu(cnt.rxfragerr);
3623 wstats->discard.retries = le32_to_cpu(cnt.txfail);
3624 wstats->discard.misc = le32_to_cpu(cnt.rxrunt) +
3625 le32_to_cpu(cnt.rxgiant);
3626 wstats->miss.beacon = 0;
3628 WL_TRACE("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
3629 le32_to_cpu(cnt.txframe), le32_to_cpu(cnt.txbyte));
3630 WL_TRACE("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n",
3631 le32_to_cpu(cnt.rxfrmtoolong));
3632 WL_TRACE("wl_iw_get_wireless_stats counters rxbadplcp=%d\n",
3633 le32_to_cpu(cnt.rxbadplcp));
3634 WL_TRACE("wl_iw_get_wireless_stats counters rxundec=%d\n",
3635 le32_to_cpu(cnt.rxundec));
3636 WL_TRACE("wl_iw_get_wireless_stats counters rxfragerr=%d\n",
3637 le32_to_cpu(cnt.rxfragerr));
3638 WL_TRACE("wl_iw_get_wireless_stats counters txfail=%d\n",
3639 le32_to_cpu(cnt.txfail));
3640 WL_TRACE("wl_iw_get_wireless_stats counters rxrunt=%d\n",
3641 le32_to_cpu(cnt.rxrunt));
3642 WL_TRACE("wl_iw_get_wireless_stats counters rxgiant=%d\n",
3643 le32_to_cpu(cnt.rxgiant));
3644 #endif /* WIRELESS_EXT > 11 */
3650 int wl_iw_attach(struct net_device *dev, void *dhdp)
3654 #if defined(WL_IW_USE_ISCAN)
3655 iscan_info_t *iscan = NULL;
3660 memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
3664 (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)) +
3665 (WL_NUMCHANNELS * sizeof(u16)) +
3666 WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
3669 (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
3671 iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
3675 memset(iscan, 0, sizeof(iscan_info_t));
3677 iscan->iscan_ex_params_p = kmalloc(params_size, GFP_KERNEL);
3678 if (!iscan->iscan_ex_params_p)
3680 iscan->iscan_ex_param_size = params_size;
3681 iscan->sysioc_tsk = NULL;
3685 iscan->iscan_state = ISCAN_STATE_IDLE;
3687 iscan->timer_ms = 3000;
3688 init_timer(&iscan->timer);
3689 iscan->timer.data = (unsigned long) iscan;
3690 iscan->timer.function = wl_iw_timerfunc;
3692 sema_init(&iscan->sysioc_sem, 0);
3693 iscan->sysioc_tsk = kthread_run(_iscan_sysioc_thread, iscan,
3695 if (IS_ERR(iscan->sysioc_tsk)) {
3696 iscan->sysioc_tsk = NULL;
3699 #endif /* defined(WL_IW_USE_ISCAN) */
3701 iw = *(wl_iw_t **) netdev_priv(dev);
3702 iw->pub = (dhd_pub_t *) dhdp;
3703 MUTEX_LOCK_INIT(iw->pub);
3704 MUTEX_LOCK_WL_SCAN_SET_INIT();
3707 MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub);
3709 g_scan = kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
3713 memset(g_scan, 0, G_SCAN_RESULTS);
3714 g_scan_specified_ssid = 0;
3719 void wl_iw_detach(void)
3721 #if defined(WL_IW_USE_ISCAN)
3723 iscan_info_t *iscan = g_iscan;
3727 if (iscan->sysioc_tsk) {
3728 send_sig(SIGTERM, iscan->sysioc_tsk, 1);
3729 kthread_stop(iscan->sysioc_tsk);
3730 iscan->sysioc_tsk = NULL;
3733 MUTEX_LOCK_WL_SCAN_SET();
3734 while (iscan->list_hdr) {
3735 buf = iscan->list_hdr->next;
3736 kfree(iscan->list_hdr);
3737 iscan->list_hdr = buf;
3739 MUTEX_UNLOCK_WL_SCAN_SET();
3740 kfree(iscan->iscan_ex_params_p);
3743 #endif /* WL_IW_USE_ISCAN */