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>
25 #include <bcmendian.h>
26 #include <proto/ethernet.h>
28 #include <linux/if_arp.h>
29 #include <asm/uaccess.h>
31 #include <dngl_stats.h>
35 typedef const struct si_pub si_t;
38 #include <proto/ethernet.h>
39 #include <dngl_stats.h>
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)
50 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | \
51 TKIP_ENABLED | AES_ENABLED))
53 #include <linux/rtnetlink.h>
55 #define WL_IW_USE_ISCAN 1
56 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1
58 bool g_set_essid_before_scan = true;
60 #define WL_IW_IOCTL_CALL(func_call) \
65 static int g_onoff = G_WLAN_SET_ON;
66 wl_iw_extra_params_t g_wl_iw_params;
68 extern bool wl_iw_conn_status_str(u32 event_type, u32 status,
69 u32 reason, char *stringBuf, uint buflen);
71 uint wl_msg_level = WL_ERROR_VAL;
73 #define MAX_WLIW_IOCTL_LEN 1024
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)
88 #define htodchanspec(i) i
89 #define dtohchanspec(i) i
92 #ifdef CONFIG_WIRELESS_EXT
94 extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
95 extern int dhd_wait_pend8021x(struct net_device *dev);
99 #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
100 #define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
104 static volatile uint g_scan_specified_ssid;
105 static wlc_ssid_t g_specific_ssid;
107 static wlc_ssid_t g_ssid;
109 #if defined(WL_IW_USE_ISCAN)
110 #define ISCAN_STATE_IDLE 0
111 #define ISCAN_STATE_SCANING 1
113 #define WLC_IW_ISCAN_MAXLEN 2048
114 typedef struct iscan_buf {
115 struct iscan_buf *next;
116 char iscan_buf[WLC_IW_ISCAN_MAXLEN];
119 typedef struct iscan_info {
120 struct net_device *dev;
121 struct timer_list timer;
125 iscan_buf_t *list_hdr;
126 iscan_buf_t *list_cur;
128 struct task_struct *sysioc_tsk;
129 struct semaphore sysioc_sem;
132 char ioctlbuf[WLC_IOCTL_MEDLEN];
134 char ioctlbuf[WLC_IOCTL_SMLEN];
136 wl_iscan_params_t *iscan_ex_params_p;
137 int iscan_ex_param_size;
139 iscan_info_t *g_iscan;
140 static void wl_iw_timerfunc(unsigned long data);
141 static void wl_iw_set_event_mask(struct net_device *dev);
142 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action);
143 #endif /* defined(WL_IW_USE_ISCAN) */
146 wl_iw_set_scan(struct net_device *dev,
147 struct iw_request_info *info,
148 union iwreq_data *wrqu, char *extra);
151 wl_iw_get_scan(struct net_device *dev,
152 struct iw_request_info *info,
153 struct iw_point *dwrq, char *extra);
156 wl_iw_get_scan_prep(wl_scan_results_t *list,
157 struct iw_request_info *info, char *extra, short max_size);
159 static void swap_key_from_BE(wl_wsec_key_t *key)
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);
170 static void swap_key_to_BE(wl_wsec_key_t *key)
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);
181 static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
189 WL_ERROR("%s: dev is null\n", __func__);
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);
196 if (g_onoff == G_WLAN_SET_ON) {
197 memset(&ioc, 0, sizeof(ioc));
202 strcpy(ifr.ifr_name, dev->name);
203 ifr.ifr_data = (caddr_t)&ioc;
207 WL_ERROR("%s: Error dev_open: %d\n", __func__, ret);
213 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
216 WL_TRACE("%s: call after driver stop : ignored\n", __func__);
221 static int dev_wlc_intvar_set(struct net_device *dev, char *name, int val)
223 char buf[WLC_IOCTL_SMLEN];
227 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
230 return dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len);
233 #if defined(WL_IW_USE_ISCAN)
235 dev_iw_iovar_setbuf(struct net_device *dev,
237 void *param, int paramlen, void *bufptr, int buflen)
241 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
247 return dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
251 dev_iw_iovar_getbuf(struct net_device *dev,
253 void *param, int paramlen, void *bufptr, int buflen)
257 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
260 return dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen);
262 #endif /* defined(WL_IW_USE_ISCAN) */
264 #if WIRELESS_EXT > 17
266 dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
268 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
271 buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
274 return dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen);
276 #endif /* WIRELESS_EXT > 17 */
279 dev_wlc_bufvar_get(struct net_device *dev, char *name, char *buf, int buflen)
281 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
285 len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
288 dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf,
291 bcopy(ioctlbuf, buf, buflen);
296 static int dev_wlc_intvar_get(struct net_device *dev, char *name, int *retval)
299 char buf[WLC_IOCTL_SMLEN];
308 bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
311 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
313 *retval = dtoh32(var.val);
318 #if WIRELESS_EXT < 13
319 struct iw_request_info {
324 typedef int (*iw_handler) (struct net_device *dev,
325 struct iw_request_info *info,
326 void *wrqu, char *extra);
330 wl_iw_config_commit(struct net_device *dev,
331 struct iw_request_info *info, void *zwrq, char *extra)
335 struct sockaddr bssid;
337 WL_TRACE("%s: SIOCSIWCOMMIT\n", dev->name);
339 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
343 ssid.SSID_len = dtoh32(ssid.SSID_len);
348 memset(&bssid, 0, sizeof(struct sockaddr));
349 error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETH_ALEN);
351 WL_ERROR("%s: WLC_REASSOC to %s failed\n",
352 __func__, ssid.SSID);
360 wl_iw_get_name(struct net_device *dev,
361 struct iw_request_info *info, char *cwrq, char *extra)
363 WL_TRACE("%s: SIOCGIWNAME\n", dev->name);
365 strcpy(cwrq, "IEEE 802.11-DS");
371 wl_iw_set_freq(struct net_device *dev,
372 struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
377 WL_TRACE("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name);
379 if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
386 } else if (fwrq->e < 6) {
387 while (fwrq->e++ < 6)
390 if (fwrq->m > 4000 && fwrq->m < 5000)
391 sf = WF_CHAN_FACTOR_4_G;
393 chan = wf_mhz2channel(fwrq->m, sf);
397 error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan));
401 g_wl_iw_params.target_channel = chan;
406 wl_iw_get_freq(struct net_device *dev,
407 struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
412 WL_TRACE("%s: SIOCGIWFREQ\n", dev->name);
414 error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
418 fwrq->m = dtoh32(ci.hw_channel);
424 wl_iw_set_mode(struct net_device *dev,
425 struct iw_request_info *info, __u32 *uwrq, char *extra)
427 int infra = 0, ap = 0, error = 0;
429 WL_TRACE("%s: SIOCSIWMODE\n", dev->name);
444 infra = htod32(infra);
447 error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra));
451 error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap));
459 wl_iw_get_mode(struct net_device *dev,
460 struct iw_request_info *info, __u32 *uwrq, char *extra)
462 int error, infra = 0, ap = 0;
464 WL_TRACE("%s: SIOCGIWMODE\n", dev->name);
466 error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra));
470 error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap));
474 infra = dtoh32(infra);
476 *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
482 wl_iw_get_range(struct net_device *dev,
483 struct iw_request_info *info,
484 struct iw_point *dwrq, char *extra)
486 struct iw_range *range = (struct iw_range *)extra;
488 wl_rateset_t rateset;
494 int bw_cap = 0, sgi_tx = 0, nmode = 0;
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}
503 WL_TRACE("%s: SIOCGIWRANGE\n", dev->name);
508 channels = kmalloc((MAXCHANNEL + 1) * 4, GFP_KERNEL);
510 WL_ERROR("Could not alloc channels\n");
513 list = (wl_u32_list_t *) channels;
515 dwrq->length = sizeof(struct iw_range);
516 memset(range, 0, sizeof(range));
518 range->min_nwid = range->max_nwid = 0;
520 list->count = htod32(MAXCHANNEL);
521 error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels,
522 (MAXCHANNEL + 1) * 4);
527 for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
528 range->freq[i].i = dtoh32(list->element[i]);
530 ch = dtoh32(list->element[i]);
531 if (ch <= CH_MAX_2G_CHANNEL)
532 sf = WF_CHAN_FACTOR_2_4_G;
534 sf = WF_CHAN_FACTOR_5_G;
536 range->freq[i].m = wf_channel2mhz(ch, sf);
537 range->freq[i].e = 6;
539 range->num_frequency = range->num_channels = i;
541 range->max_qual.qual = 5;
542 range->max_qual.level = 0x100 - 200;
543 range->max_qual.noise = 0x100 - 200;
544 range->sensitivity = 65535;
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;
552 error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
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));
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);
572 if (bw_cap == 0 || (bw_cap == 2 && ci.hw_channel <= 14)) {
578 if (bw_cap == 1 || (bw_cap == 2 && ci.hw_channel >= 36)) {
584 range->num_bitrates += 8;
585 for (k = 0; i < range->num_bitrates; k++, i++) {
587 (nrate_list[nrate_list2copy][k]) * 500000;
591 error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i));
597 if (i == WLC_PHY_TYPE_A)
598 range->throughput = 24000000;
600 range->throughput = 1500000;
603 range->max_rts = 2347;
604 range->min_frag = 256;
605 range->max_frag = 2346;
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;
614 range->encoding_size[2] = 0;
616 range->encoding_size[3] = AES_KEY_SIZE;
622 range->pmp_flags = 0;
625 range->num_txpower = 2;
626 range->txpower[0] = 1;
627 range->txpower[1] = 255;
628 range->txpower_capa = IW_TXPOW_MWATT;
630 #if WIRELESS_EXT > 10
631 range->we_version_compiled = WIRELESS_EXT;
632 range->we_version_source = 19;
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;
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;
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 /* WIRELESS_EXT > 17 */
662 static int rssi_to_qual(int rssi)
664 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
666 else if (rssi <= WL_IW_RSSI_VERY_LOW)
668 else if (rssi <= WL_IW_RSSI_LOW)
670 else if (rssi <= WL_IW_RSSI_GOOD)
672 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
679 wl_iw_set_spy(struct net_device *dev,
680 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
682 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
683 struct sockaddr *addr = (struct sockaddr *)extra;
686 WL_TRACE("%s: SIOCSIWSPY\n", dev->name);
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));
700 wl_iw_get_spy(struct net_device *dev,
701 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
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];
708 WL_TRACE("%s: SIOCGIWSPY\n", dev->name);
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;
725 wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params,
726 int *join_params_size)
728 chanspec_t chanspec = 0;
731 join_params->params.chanspec_num = 1;
732 join_params->params.chanspec_list[0] = ch;
734 if (join_params->params.chanspec_list[0])
735 chanspec |= WL_CHANSPEC_BAND_2G;
737 chanspec |= WL_CHANSPEC_BAND_5G;
739 chanspec |= WL_CHANSPEC_BW_20;
740 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
742 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
743 join_params->params.chanspec_num * sizeof(chanspec_t);
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]);
750 join_params->params.chanspec_num =
751 htod32(join_params->params.chanspec_num);
753 WL_TRACE("%s join_params->params.chanspec_list[0]= %X\n",
754 __func__, join_params->params.chanspec_list[0]);
760 wl_iw_set_wap(struct net_device *dev,
761 struct iw_request_info *info, struct sockaddr *awrq, char *extra)
764 wl_join_params_t join_params;
765 int join_params_size;
767 WL_TRACE("%s: SIOCSIWAP\n", dev->name);
769 if (awrq->sa_family != ARPHRD_ETHER) {
770 WL_ERROR("Invalid Header...sa_family\n");
774 if (is_broadcast_ether_addr(awrq->sa_data) ||
775 is_zero_ether_addr(awrq->sa_data)) {
777 memset(&scbval, 0, sizeof(scb_val_t));
778 (void)dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
783 memset(&join_params, 0, sizeof(join_params));
784 join_params_size = sizeof(join_params.ssid);
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);
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,
795 error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
798 WL_ERROR("%s Invalid ioctl data=%d\n", __func__, error);
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);
807 memset(&g_ssid, 0, sizeof(g_ssid));
812 wl_iw_get_wap(struct net_device *dev,
813 struct iw_request_info *info, struct sockaddr *awrq, char *extra)
815 WL_TRACE("%s: SIOCGIWAP\n", dev->name);
817 awrq->sa_family = ARPHRD_ETHER;
818 memset(awrq->sa_data, 0, ETH_ALEN);
820 (void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETH_ALEN);
825 #if WIRELESS_EXT > 17
827 wl_iw_mlme(struct net_device *dev,
828 struct iw_request_info *info, struct sockaddr *awrq, char *extra)
830 struct iw_mlme *mlme;
834 WL_TRACE("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name);
836 mlme = (struct iw_mlme *)extra;
838 WL_ERROR("Invalid ioctl data\n");
842 scbval.val = mlme->reason_code;
843 bcopy(&mlme->addr.sa_data, &scbval.ea, ETH_ALEN);
845 if (mlme->cmd == IW_MLME_DISASSOC) {
846 scbval.val = htod32(scbval.val);
848 dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
850 } else if (mlme->cmd == IW_MLME_DEAUTH) {
851 scbval.val = htod32(scbval.val);
853 dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
854 &scbval, sizeof(scb_val_t));
856 WL_ERROR("Invalid ioctl data\n");
862 #endif /* WIRELESS_EXT > 17 */
864 #ifndef WL_IW_USE_ISCAN
866 wl_iw_get_aplist(struct net_device *dev,
867 struct iw_request_info *info,
868 struct iw_point *dwrq, char *extra)
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;
875 uint buflen = dwrq->length;
877 WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
882 list = kmalloc(buflen, GFP_KERNEL);
885 memset(list, 0, buflen);
886 list->buflen = htod32(buflen);
887 error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen);
889 WL_ERROR("%d: Scan results error %d\n", __LINE__, error);
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);
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->
908 ASSERT(((unsigned long)bi + dtoh32(bi->length)) <=
909 ((unsigned long)list + buflen));
911 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
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;
920 #if WIRELESS_EXT > 18
921 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
923 qual[dwrq->length].updated = 7;
931 memcpy(&addr[dwrq->length], qual,
932 sizeof(struct iw_quality) * dwrq->length);
938 #endif /* WL_IW_USE_ISCAN */
940 #ifdef WL_IW_USE_ISCAN
942 wl_iw_iscan_get_aplist(struct net_device *dev,
943 struct iw_request_info *info,
944 struct iw_point *dwrq, char *extra)
946 wl_scan_results_t *list;
948 iscan_info_t *iscan = g_iscan;
950 struct sockaddr *addr = (struct sockaddr *)extra;
951 struct iw_quality qual[IW_MAX_AP];
952 wl_bss_info_t *bi = NULL;
955 WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
960 if ((!iscan) || (!iscan->sysioc_tsk)) {
961 WL_ERROR("%s error\n", __func__);
965 buf = iscan->list_hdr;
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);
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)) :
980 ASSERT(((unsigned long)bi + dtoh32(bi->length)) <=
981 ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
983 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
986 memcpy(addr[dwrq->length].sa_data, &bi->BSSID,
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;
994 #if WIRELESS_EXT > 18
995 qual[dwrq->length].updated =
996 IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
998 qual[dwrq->length].updated = 7;
1006 memcpy(&addr[dwrq->length], qual,
1007 sizeof(struct iw_quality) * dwrq->length);
1014 static int wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
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;
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));
1037 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action)
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);
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);
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));
1062 static void wl_iw_timerfunc(unsigned long data)
1064 iscan_info_t *iscan = (iscan_info_t *) data;
1066 iscan->timer_on = 0;
1067 if (iscan->iscan_state != ISCAN_STATE_IDLE) {
1068 WL_TRACE("timer trigger\n");
1069 up(&iscan->sysioc_sem);
1074 static void wl_iw_set_event_mask(struct net_device *dev)
1076 char eventmask[WL_EVENTING_MASK_LEN];
1077 char iovbuf[WL_EVENTING_MASK_LEN + 12];
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));
1086 static u32 wl_iw_iscan_get(iscan_info_t *iscan)
1090 wl_iscan_results_t *list_buf;
1091 wl_iscan_results_t list;
1092 wl_scan_results_t *results;
1096 MUTEX_LOCK_WL_SCAN_SET();
1097 if (iscan->list_cur) {
1098 buf = iscan->list_cur;
1099 iscan->list_cur = buf->next;
1101 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
1103 WL_ERROR("%s can't alloc iscan_buf_t : going to abort current iscan\n",
1105 MUTEX_UNLOCK_WL_SCAN_SET();
1106 return WL_SCAN_RESULTS_NO_MEM;
1109 if (!iscan->list_hdr)
1110 iscan->list_hdr = buf;
1112 ptr = iscan->list_hdr;
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;
1126 memset(&list, 0, sizeof(list));
1127 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
1128 res = dev_iw_iovar_getbuf(iscan->dev,
1131 WL_ISCAN_RESULTS_FIXED_SIZE,
1132 buf->iscan_buf, WLC_IW_ISCAN_MAXLEN);
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);
1141 WL_ERROR("%s returns error %d\n", __func__, res);
1142 status = WL_SCAN_RESULTS_NO_MEM;
1144 MUTEX_UNLOCK_WL_SCAN_SET();
1148 static void wl_iw_force_specific_scan(iscan_info_t *iscan)
1150 WL_TRACE("%s force Specific SCAN for %s\n",
1151 __func__, g_specific_ssid.SSID);
1154 (void)dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid,
1155 sizeof(g_specific_ssid));
1160 static void wl_iw_send_scan_complete(iscan_info_t *iscan)
1163 union iwreq_data wrqu;
1165 memset(&wrqu, 0, sizeof(wrqu));
1167 wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
1168 WL_TRACE("Send Event ISCAN complete\n");
1172 static int _iscan_sysioc_thread(void *data)
1175 iscan_info_t *iscan = (iscan_info_t *) data;
1176 static bool iscan_pass_abort = false;
1178 allow_signal(SIGTERM);
1179 status = WL_SCAN_RESULTS_PARTIAL;
1180 while (down_interruptible(&iscan->sysioc_sem) == 0) {
1181 if (kthread_should_stop())
1184 if (iscan->timer_on) {
1185 del_timer_sync(&iscan->timer);
1186 iscan->timer_on = 0;
1189 status = wl_iw_iscan_get(iscan);
1191 if (g_scan_specified_ssid && (iscan_pass_abort == true)) {
1192 WL_TRACE("%s Get results from specific scan status = %d\n",
1194 wl_iw_send_scan_complete(iscan);
1195 iscan_pass_abort = false;
1200 case WL_SCAN_RESULTS_PARTIAL:
1201 WL_TRACE("iscanresults incomplete\n");
1203 wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
1205 mod_timer(&iscan->timer,
1206 jiffies + iscan->timer_ms * HZ / 1000);
1207 iscan->timer_on = 1;
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);
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;
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);
1226 iscan_pass_abort = true;
1227 wl_iw_force_specific_scan(iscan);
1230 case WL_SCAN_RESULTS_NO_MEM:
1231 WL_TRACE("iscanresults can't alloc memory: skip\n");
1232 iscan->iscan_state = ISCAN_STATE_IDLE;
1235 WL_TRACE("iscanresults returned unknown status %d\n",
1241 if (iscan->timer_on) {
1242 del_timer_sync(&iscan->timer);
1243 iscan->timer_on = 0;
1247 #endif /* WL_IW_USE_ISCAN */
1250 wl_iw_set_scan(struct net_device *dev,
1251 struct iw_request_info *info,
1252 union iwreq_data *wrqu, char *extra)
1255 WL_TRACE("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name);
1257 g_set_essid_before_scan = false;
1259 WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1263 if (g_onoff == G_WLAN_SET_OFF)
1266 memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
1267 #ifndef WL_IW_USE_ISCAN
1268 g_scan_specified_ssid = 0;
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);
1280 g_specific_ssid.SSID_len = min_t(size_t,
1281 sizeof(g_specific_ssid.SSID),
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);
1294 #endif /* WIRELESS_EXT > 17 */
1295 error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid,
1296 sizeof(g_specific_ssid));
1298 WL_TRACE("#### Set SCAN for %s failed with %d\n",
1299 g_specific_ssid.SSID, error);
1300 g_scan_specified_ssid = 0;
1307 #ifdef WL_IW_USE_ISCAN
1308 int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
1311 iscan_info_t *iscan = g_iscan;
1316 wl_iw_set_event_mask(dev);
1318 WL_TRACE("+++: Set Broadcast ISCAN\n");
1319 memset(&ssid, 0, sizeof(ssid));
1321 iscan->list_cur = iscan->list_hdr;
1322 iscan->iscan_state = ISCAN_STATE_SCANING;
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);
1332 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
1334 iscan->timer_on = 1;
1340 wl_iw_iscan_set_scan(struct net_device *dev,
1341 struct iw_request_info *info,
1342 union iwreq_data *wrqu, char *extra)
1345 iscan_info_t *iscan = g_iscan;
1347 WL_TRACE("%s: SIOCSIWSCAN : ISCAN\n", dev->name);
1350 WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1354 if (g_onoff == G_WLAN_SET_OFF) {
1355 WL_TRACE("%s: driver is not up yet after START\n", __func__);
1359 if (dhd_dev_get_pno_status(dev)) {
1360 WL_ERROR("%s: Scan called when PNO is active\n", __func__);
1364 if ((!iscan) || (!iscan->sysioc_tsk))
1365 return wl_iw_set_scan(dev, info, wrqu, extra);
1367 if (g_scan_specified_ssid) {
1368 WL_TRACE("%s Specific SCAN already running ignoring BC scan\n",
1373 memset(&ssid, 0, sizeof(ssid));
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),
1381 memcpy(ssid.SSID, req->essid, ssid.SSID_len);
1382 ssid.SSID_len = htod32(ssid.SSID_len);
1384 g_scan_specified_ssid = 0;
1386 if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1387 WL_TRACE("%s ISCAN already in progress\n",
1393 #endif /* WIRELESS_EXT > 17 */
1394 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1398 #endif /* WL_IW_USE_ISCAN */
1400 #if WIRELESS_EXT > 17
1401 static bool ie_is_wpa_ie(u8 **wpaie, u8 **tlvs, int *tlvs_len)
1407 !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
1412 *tlvs_len -= (int)(ie - *tlvs);
1417 static bool ie_is_wps_ie(u8 **wpsie, u8 **tlvs, int *tlvs_len)
1423 !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
1428 *tlvs_len -= (int)(ie - *tlvs);
1432 #endif /* WIRELESS_EXT > 17 */
1435 wl_iw_handle_scanresults_ies(char **event_p, char *end,
1436 struct iw_request_info *info, wl_bss_info_t *bi)
1438 #if WIRELESS_EXT > 17
1439 struct iw_event iwe;
1443 if (bi->ie_length) {
1445 u8 *ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1446 int ptr_len = bi->ie_length;
1448 ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID);
1450 iwe.cmd = IWEVGENIE;
1451 iwe.u.data.length = ie->len + 2;
1453 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1456 ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
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;
1463 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
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;
1476 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1484 #endif /* WIRELESS_EXT > 17 */
1489 wl_iw_get_scan_prep(wl_scan_results_t *list,
1490 struct iw_request_info *info, char *extra, short max_size)
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;
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);
1507 bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1508 dtoh32(bi->length)) : list->
1511 WL_TRACE("%s : %s\n", __func__, bi->SSID);
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);
1517 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
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);
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;
1529 iwe.u.mode = IW_MODE_ADHOC;
1531 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1535 iwe.cmd = SIOCGIWFREQ;
1536 iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
1537 CHSPEC_CHANNEL(bi->chanspec) <=
1539 WF_CHAN_FACTOR_2_4_G :
1540 WF_CHAN_FACTOR_5_G);
1543 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
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;
1551 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1554 wl_iw_handle_scanresults_ies(&event, end, info, bi);
1556 iwe.cmd = SIOCGIWENCODE;
1557 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
1558 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1560 iwe.u.data.flags = IW_ENCODE_DISABLED;
1561 iwe.u.data.length = 0;
1563 IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
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 =
1573 j < bi->rateset.count
1574 && j < IW_MAX_BITRATES; j++) {
1575 iwe.u.bitrate.value =
1576 (bi->rateset.rates[j] & 0x7f) *
1579 IWE_STREAM_ADD_VALUE(info, event,
1588 ret = event - extra;
1590 WL_ERROR("==> Wrong size\n");
1593 WL_TRACE("%s: size=%d bytes prepared\n",
1594 __func__, (unsigned int)(event - extra));
1599 wl_iw_get_scan(struct net_device *dev,
1600 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1603 wl_scan_results_t *list_merge;
1604 wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
1606 uint buflen_from_user = dwrq->length;
1607 uint len = G_SCAN_RESULTS;
1609 #if defined(WL_IW_USE_ISCAN)
1610 iscan_info_t *iscan = g_iscan;
1614 WL_TRACE("%s: buflen_from_user %d:\n", dev->name, buflen_from_user);
1617 WL_TRACE("%s: wl_iw_get_scan return -EINVAL\n", dev->name);
1621 error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
1624 ci.scan_channel = dtoh32(ci.scan_channel);
1625 if (ci.scan_channel)
1628 if (g_scan_specified_ssid) {
1629 list = kmalloc(len, GFP_KERNEL);
1631 WL_TRACE("%s: wl_iw_get_scan return -ENOMEM\n",
1633 g_scan_specified_ssid = 0;
1638 memset(list, 0, len);
1639 list->buflen = htod32(len);
1640 error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len);
1642 WL_ERROR("%s: %s : Scan_results ERROR %d\n",
1643 dev->name, __func__, error);
1645 if (g_scan_specified_ssid) {
1646 g_scan_specified_ssid = 0;
1651 list->buflen = dtoh32(list->buflen);
1652 list->version = dtoh32(list->version);
1653 list->count = dtoh32(list->count);
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;
1665 if (g_scan_specified_ssid) {
1666 WL_TRACE("%s: Specified scan APs in the list =%d\n",
1667 __func__, list->count);
1669 (__u16) wl_iw_get_scan_prep(list, info, extra,
1673 #if defined(WL_IW_USE_ISCAN)
1674 p_buf = iscan->list_hdr;
1675 while (p_buf != iscan->list_cur) {
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)
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;
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)
1693 (__u16) wl_iw_get_scan_prep(list_merge, info,
1697 #endif /* defined(WL_IW_USE_ISCAN) */
1699 list = (wl_scan_results_t *) g_scan;
1701 (__u16) wl_iw_get_scan_prep(list, info, extra,
1705 #if defined(WL_IW_USE_ISCAN)
1706 g_scan_specified_ssid = 0;
1708 if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
1714 WL_TRACE("%s return to WE %d bytes APs=%d\n",
1715 __func__, dwrq->length, list->count);
1719 #if defined(WL_IW_USE_ISCAN)
1721 wl_iw_iscan_get_scan(struct net_device *dev,
1722 struct iw_request_info *info,
1723 struct iw_point *dwrq, char *extra)
1725 wl_scan_results_t *list;
1726 struct iw_event iwe;
1727 wl_bss_info_t *bi = NULL;
1730 char *event = extra, *end = extra + dwrq->length, *value;
1731 iscan_info_t *iscan = g_iscan;
1736 WL_TRACE("%s %s buflen_from_user %d:\n",
1737 dev->name, __func__, dwrq->length);
1740 WL_TRACE("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
1745 if ((!iscan) || (!iscan->sysioc_tsk)) {
1746 WL_ERROR("%ssysioc_tsk\n", __func__);
1747 return wl_iw_get_scan(dev, info, dwrq, extra);
1750 if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1751 WL_TRACE("%s: SIOCGIWSCAN GET still scanning\n", dev->name);
1755 WL_TRACE("%s: SIOCGIWSCAN GET broadcast results\n", dev->name);
1757 p_buf = iscan->list_hdr;
1758 while (p_buf != iscan->list_cur) {
1759 list = &((wl_iscan_results_t *) p_buf->iscan_buf)->results;
1761 counter += list->count;
1763 if (list->version != WL_BSS_INFO_VERSION) {
1764 WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1765 __func__, list->version);
1770 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP;
1772 bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1773 dtoh32(bi->length)) :
1775 ASSERT(((unsigned long)bi + dtoh32(bi->length)) <=
1776 ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
1778 if (event + ETH_ALEN + bi->SSID_len +
1779 IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >=
1782 iwe.cmd = SIOCGIWAP;
1783 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1784 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID,
1787 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1790 iwe.u.data.length = dtoh32(bi->SSID_len);
1791 iwe.cmd = SIOCGIWESSID;
1792 iwe.u.data.flags = 1;
1794 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
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;
1803 iwe.u.mode = IW_MODE_ADHOC;
1805 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1809 iwe.cmd = SIOCGIWFREQ;
1812 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
1814 wf_channel2mhz(channel,
1817 WF_CHAN_FACTOR_2_4_G :
1818 WF_CHAN_FACTOR_5_G);
1821 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
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;
1829 IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1832 wl_iw_handle_scanresults_ies(&event, end, info, bi);
1834 iwe.cmd = SIOCGIWENCODE;
1835 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
1837 IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1839 iwe.u.data.flags = IW_ENCODE_DISABLED;
1840 iwe.u.data.length = 0;
1842 IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1845 if (bi->rateset.count) {
1846 if (event + IW_MAX_BITRATES * IW_EV_PARAM_LEN >=
1850 value = event + IW_EV_LCP_LEN;
1851 iwe.cmd = SIOCGIWRATE;
1852 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled =
1855 j < bi->rateset.count
1856 && j < IW_MAX_BITRATES; j++) {
1857 iwe.u.bitrate.value =
1858 (bi->rateset.rates[j] & 0x7f) *
1861 IWE_STREAM_ADD_VALUE(info, event,
1869 p_buf = p_buf->next;
1872 dwrq->length = event - extra;
1875 WL_TRACE("%s return to WE %d bytes APs=%d\n",
1876 __func__, dwrq->length, counter);
1883 #endif /* defined(WL_IW_USE_ISCAN) */
1886 wl_iw_set_essid(struct net_device *dev,
1887 struct iw_request_info *info,
1888 struct iw_point *dwrq, char *extra)
1891 wl_join_params_t join_params;
1892 int join_params_size;
1894 WL_TRACE("%s: SIOCSIWESSID\n", dev->name);
1896 if (g_set_essid_before_scan)
1899 memset(&g_ssid, 0, sizeof(g_ssid));
1901 CHECK_EXTRA_FOR_NULL(extra);
1903 if (dwrq->length && extra) {
1904 #if WIRELESS_EXT > 20
1905 g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1908 g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1911 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
1913 g_ssid.SSID_len = 0;
1915 g_ssid.SSID_len = htod32(g_ssid.SSID_len);
1917 memset(&join_params, 0, sizeof(join_params));
1918 join_params_size = sizeof(join_params.ssid);
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);
1924 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
1927 error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
1930 WL_ERROR("Invalid ioctl data=%d\n", error);
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);
1940 wl_iw_get_essid(struct net_device *dev,
1941 struct iw_request_info *info,
1942 struct iw_point *dwrq, char *extra)
1947 WL_TRACE("%s: SIOCGIWESSID\n", dev->name);
1952 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1954 WL_ERROR("Error getting the SSID\n");
1958 ssid.SSID_len = dtoh32(ssid.SSID_len);
1960 memcpy(extra, ssid.SSID, ssid.SSID_len);
1962 dwrq->length = ssid.SSID_len;
1970 wl_iw_set_nick(struct net_device *dev,
1971 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1973 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
1975 WL_TRACE("%s: SIOCSIWNICKN\n", dev->name);
1980 if (dwrq->length > sizeof(iw->nickname))
1983 memcpy(iw->nickname, extra, dwrq->length);
1984 iw->nickname[dwrq->length - 1] = '\0';
1990 wl_iw_get_nick(struct net_device *dev,
1991 struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1993 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
1995 WL_TRACE("%s: SIOCGIWNICKN\n", dev->name);
2000 strcpy(extra, iw->nickname);
2001 dwrq->length = strlen(extra) + 1;
2007 wl_iw_set_rate(struct net_device *dev,
2008 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2010 wl_rateset_t rateset;
2011 int error, rate, i, error_bg, error_a;
2013 WL_TRACE("%s: SIOCSIWRATE\n", dev->name);
2015 error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
2020 rateset.count = dtoh32(rateset.count);
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;
2027 rate = vwrq->value / 500000;
2030 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
2031 error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
2033 if (error_bg && error_a)
2034 return error_bg | error_a;
2036 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
2037 error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
2039 if (error_bg && error_a)
2040 return error_bg | error_a;
2042 for (i = 0; i < rateset.count; i++)
2043 if ((rateset.rates[i] & 0x7f) > rate)
2045 rateset.count = htod32(i);
2047 error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset,
2057 wl_iw_get_rate(struct net_device *dev,
2058 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2062 WL_TRACE("%s: SIOCGIWRATE\n", dev->name);
2064 error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate));
2067 rate = dtoh32(rate);
2068 vwrq->value = rate * 500000;
2074 wl_iw_set_rts(struct net_device *dev,
2075 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2079 WL_TRACE("%s: SIOCSIWRTS\n", dev->name);
2082 rts = DOT11_DEFAULT_RTS_LEN;
2083 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
2088 error = dev_wlc_intvar_set(dev, "rtsthresh", rts);
2096 wl_iw_get_rts(struct net_device *dev,
2097 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2101 WL_TRACE("%s: SIOCGIWRTS\n", dev->name);
2103 error = dev_wlc_intvar_get(dev, "rtsthresh", &rts);
2108 vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
2115 wl_iw_set_frag(struct net_device *dev,
2116 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2120 WL_TRACE("%s: SIOCSIWFRAG\n", dev->name);
2123 frag = DOT11_DEFAULT_FRAG_LEN;
2124 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
2129 error = dev_wlc_intvar_set(dev, "fragthresh", frag);
2137 wl_iw_get_frag(struct net_device *dev,
2138 struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2140 int error, fragthreshold;
2142 WL_TRACE("%s: SIOCGIWFRAG\n", dev->name);
2144 error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold);
2148 vwrq->value = fragthreshold;
2149 vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
2156 wl_iw_set_txpow(struct net_device *dev,
2157 struct iw_request_info *info,
2158 struct iw_param *vwrq, char *extra)
2162 WL_TRACE("%s: SIOCSIWTXPOW\n", dev->name);
2164 disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
2165 disable += WL_RADIO_SW_DISABLE << 16;
2167 disable = htod32(disable);
2168 error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable));
2172 if (disable & WL_RADIO_SW_DISABLE)
2175 if (!(vwrq->flags & IW_TXPOW_MWATT))
2178 if (vwrq->value < 0)
2181 if (vwrq->value > 0xffff)
2184 txpwrmw = (u16) vwrq->value;
2187 dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
2192 wl_iw_get_txpow(struct net_device *dev,
2193 struct iw_request_info *info,
2194 struct iw_param *vwrq, char *extra)
2196 int error, disable, txpwrdbm;
2199 WL_TRACE("%s: SIOCGIWTXPOW\n", dev->name);
2201 error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable));
2205 error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm);
2209 disable = dtoh32(disable);
2210 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
2211 vwrq->value = (s32) bcm_qdbm_to_mw(result);
2214 (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
2215 vwrq->flags = IW_TXPOW_MWATT;
2220 #if WIRELESS_EXT > 10
2222 wl_iw_set_retry(struct net_device *dev,
2223 struct iw_request_info *info,
2224 struct iw_param *vwrq, char *extra)
2226 int error, lrl, srl;
2228 WL_TRACE("%s: SIOCSIWRETRY\n", dev->name);
2230 if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
2233 if (vwrq->flags & IW_RETRY_LIMIT) {
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))) {
2241 if ((vwrq->flags & IW_RETRY_MAX)
2242 || !(vwrq->flags & IW_RETRY_MIN)) {
2244 lrl = htod32(vwrq->value);
2245 error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl,
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))) {
2256 if ((vwrq->flags & IW_RETRY_MIN)
2257 || !(vwrq->flags & IW_RETRY_MAX)) {
2259 srl = htod32(vwrq->value);
2260 error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl,
2270 wl_iw_get_retry(struct net_device *dev,
2271 struct iw_request_info *info,
2272 struct iw_param *vwrq, char *extra)
2274 int error, lrl, srl;
2276 WL_TRACE("%s: SIOCGIWRETRY\n", dev->name);
2280 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
2283 error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl));
2287 error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl));
2294 if (vwrq->flags & IW_RETRY_MAX) {
2295 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
2298 vwrq->flags = IW_RETRY_LIMIT;
2301 vwrq->flags |= IW_RETRY_MIN;
2306 #endif /* WIRELESS_EXT > 10 */
2309 wl_iw_set_encode(struct net_device *dev,
2310 struct iw_request_info *info,
2311 struct iw_point *dwrq, char *extra)
2314 int error, val, wsec;
2316 WL_TRACE("%s: SIOCSIWENCODE\n", dev->name);
2318 memset(&key, 0, sizeof(key));
2320 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2321 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2323 val = htod32(key.index);
2324 error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2332 if (key.index == DOT11_MAX_DEFAULT_KEYS)
2335 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2336 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
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,
2347 key.len = dwrq->length;
2349 if (dwrq->length > sizeof(key.data))
2352 memcpy(key.data, extra, dwrq->length);
2354 key.flags = WL_PRIMARY_KEY;
2357 key.algo = CRYPTO_ALGO_WEP1;
2359 case WEP128_KEY_SIZE:
2360 key.algo = CRYPTO_ALGO_WEP128;
2363 key.algo = CRYPTO_ALGO_TKIP;
2366 key.algo = CRYPTO_ALGO_AES_CCM;
2372 swap_key_from_BE(&key);
2373 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2378 val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
2380 error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2384 wsec &= ~(WEP_ENABLED);
2387 error = dev_wlc_intvar_set(dev, "wsec", wsec);
2391 val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
2393 error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
2401 wl_iw_get_encode(struct net_device *dev,
2402 struct iw_request_info *info,
2403 struct iw_point *dwrq, char *extra)
2406 int error, val, wsec, auth;
2408 WL_TRACE("%s: SIOCGIWENCODE\n", dev->name);
2410 memset(&key, 0, sizeof(wl_wsec_key_t));
2412 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2413 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2416 error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2425 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2427 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2430 error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
2434 error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth));
2438 swap_key_to_BE(&key);
2440 wsec = dtoh32(wsec);
2441 auth = dtoh32(auth);
2442 dwrq->length = min_t(u16, DOT11_MAX_KEY_SIZE, key.len);
2444 dwrq->flags = key.index + 1;
2445 if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)))
2446 dwrq->flags |= IW_ENCODE_DISABLED;
2449 dwrq->flags |= IW_ENCODE_RESTRICTED;
2451 if (dwrq->length && extra)
2452 memcpy(extra, key.data, dwrq->length);
2458 wl_iw_set_power(struct net_device *dev,
2459 struct iw_request_info *info,
2460 struct iw_param *vwrq, char *extra)
2464 WL_TRACE("%s: SIOCSIWPOWER\n", dev->name);
2466 pm = vwrq->disabled ? PM_OFF : PM_MAX;
2469 error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
2477 wl_iw_get_power(struct net_device *dev,
2478 struct iw_request_info *info,
2479 struct iw_param *vwrq, char *extra)
2483 WL_TRACE("%s: SIOCGIWPOWER\n", dev->name);
2485 error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
2490 vwrq->disabled = pm ? 0 : 1;
2491 vwrq->flags = IW_POWER_ALL_R;
2496 #if WIRELESS_EXT > 17
2498 wl_iw_set_wpaie(struct net_device *dev,
2499 struct iw_request_info *info, struct iw_point *iwp, char *extra)
2502 WL_TRACE("%s: SIOCSIWGENIE\n", dev->name);
2504 CHECK_EXTRA_FOR_NULL(extra);
2506 dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
2512 wl_iw_get_wpaie(struct net_device *dev,
2513 struct iw_request_info *info, struct iw_point *iwp, char *extra)
2515 WL_TRACE("%s: SIOCGIWGENIE\n", dev->name);
2517 dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
2522 wl_iw_set_encodeext(struct net_device *dev,
2523 struct iw_request_info *info,
2524 struct iw_point *dwrq, char *extra)
2528 struct iw_encode_ext *iwe;
2530 WL_TRACE("%s: SIOCSIWENCODEEXT\n", dev->name);
2532 CHECK_EXTRA_FOR_NULL(extra);
2534 memset(&key, 0, sizeof(key));
2535 iwe = (struct iw_encode_ext *)extra;
2537 if (dwrq->flags & IW_ENCODE_DISABLED) {
2542 if (dwrq->flags & IW_ENCODE_INDEX)
2543 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2545 key.len = iwe->key_len;
2547 if (!is_multicast_ether_addr(iwe->addr.sa_data))
2548 bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea,
2552 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
2553 WL_WSEC("Changing the the primary Key to %d\n",
2555 key.index = htod32(key.index);
2556 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
2557 &key.index, sizeof(key.index));
2561 swap_key_from_BE(&key);
2562 dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2565 if (iwe->key_len > sizeof(key.data))
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;
2574 bcopy((void *)iwe->key, key.data, iwe->key_len);
2576 if (iwe->alg == IW_ENCODE_ALG_TKIP) {
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));
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;
2593 case IW_ENCODE_ALG_NONE:
2594 key.algo = CRYPTO_ALGO_OFF;
2596 case IW_ENCODE_ALG_WEP:
2597 if (iwe->key_len == WEP1_KEY_SIZE)
2598 key.algo = CRYPTO_ALGO_WEP1;
2600 key.algo = CRYPTO_ALGO_WEP128;
2602 case IW_ENCODE_ALG_TKIP:
2603 key.algo = CRYPTO_ALGO_TKIP;
2605 case IW_ENCODE_ALG_CCMP:
2606 key.algo = CRYPTO_ALGO_AES_CCM;
2611 swap_key_from_BE(&key);
2613 dhd_wait_pend8021x(dev);
2615 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2622 #if WIRELESS_EXT > 17
2624 pmkid_list_t pmkids;
2625 pmkid_t foo[MAXPMKID - 1];
2629 wl_iw_set_pmksa(struct net_device *dev,
2630 struct iw_request_info *info,
2631 struct iw_param *vwrq, char *extra)
2633 struct iw_pmksa *iwpmksa;
2637 WL_WSEC("%s: SIOCSIWPMKSA\n", dev->name);
2639 CHECK_EXTRA_FOR_NULL(extra);
2641 iwpmksa = (struct iw_pmksa *)extra;
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));
2648 else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
2650 pmkid_list_t pmkid, *pmkidptr;
2654 bcopy(&iwpmksa->bssid.sa_data[0],
2655 &pmkidptr->pmkid[0].BSSID, ETH_ALEN);
2656 bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID,
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]);
2666 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2668 (&iwpmksa->bssid.sa_data[0],
2669 &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
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,
2679 bcopy(&pmkid_list.pmkids.pmkid[i + 1].PMKID,
2680 &pmkid_list.pmkids.pmkid[i].PMKID,
2683 pmkid_list.pmkids.npmkid--;
2688 else if (iwpmksa->cmd == IW_PMKSA_ADD) {
2689 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2691 (&iwpmksa->bssid.sa_data[0],
2692 &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
2695 bcopy(&iwpmksa->bssid.sa_data[0],
2696 &pmkid_list.pmkids.pmkid[i].BSSID,
2698 bcopy(&iwpmksa->pmkid[0],
2699 &pmkid_list.pmkids.pmkid[i].PMKID,
2701 if (i == pmkid_list.pmkids.npmkid)
2702 pmkid_list.pmkids.npmkid++;
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++)
2713 pmkid_list.pmkids.pmkid[k].PMKID[j]);
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++) {
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]);
2730 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
2731 sizeof(pmkid_list));
2734 #endif /* WIRELESS_EXT > 17 */
2737 wl_iw_get_encodeext(struct net_device *dev,
2738 struct iw_request_info *info,
2739 struct iw_param *vwrq, char *extra)
2741 WL_TRACE("%s: SIOCGIWENCODEEXT\n", dev->name);
2746 wl_iw_set_wpaauth(struct net_device *dev,
2747 struct iw_request_info *info,
2748 struct iw_param *vwrq, char *extra)
2754 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2756 WL_TRACE("%s: SIOCSIWAUTH\n", dev->name);
2758 paramid = vwrq->flags & IW_AUTH_INDEX;
2759 paramval = vwrq->value;
2761 WL_TRACE("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
2762 dev->name, paramid, paramval);
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);
2778 case IW_AUTH_CIPHER_PAIRWISE:
2779 case IW_AUTH_CIPHER_GROUP:
2780 if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
2782 if (paramval & IW_AUTH_CIPHER_TKIP)
2784 if (paramval & IW_AUTH_CIPHER_CCMP)
2787 if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
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",
2801 WL_WSEC("Failed to set is_WPS_enrollee\n");
2805 error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
2808 WL_WSEC("Failed to clear is_WPS_enrollee\n");
2813 error = dev_wlc_intvar_set(dev, "wsec", val);
2819 case IW_AUTH_KEY_MGMT:
2820 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2824 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
2825 if (paramval & IW_AUTH_KEY_MGMT_PSK)
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;
2833 val = WPA2_AUTH_UNSPECIFIED;
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);
2842 case IW_AUTH_TKIP_COUNTERMEASURES:
2843 dev_wlc_bufvar_set(dev, "tkip_countermeasures",
2844 (char *)¶mval, 1);
2847 case IW_AUTH_80211_AUTH_ALG:
2848 WL_INFORM("Setting the D11auth %d\n", paramval);
2849 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
2851 else if (paramval == IW_AUTH_ALG_SHARED_KEY)
2853 else if (paramval ==
2854 (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
2859 error = dev_wlc_intvar_set(dev, "auth", val);
2865 case IW_AUTH_WPA_ENABLED:
2866 if (paramval == 0) {
2869 error = dev_wlc_intvar_get(dev, "wsec", &val);
2872 if (val & (TKIP_ENABLED | AES_ENABLED)) {
2873 val &= ~(TKIP_ENABLED | AES_ENABLED);
2874 dev_wlc_intvar_set(dev, "wsec", val);
2877 WL_INFORM("%s: %d: setting wpa_auth to %d\n",
2878 __func__, __LINE__, val);
2879 dev_wlc_intvar_set(dev, "wpa_auth", 0);
2884 case IW_AUTH_DROP_UNENCRYPTED:
2885 dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1);
2888 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
2889 dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol",
2890 (char *)¶mval, 1);
2893 #if WIRELESS_EXT > 17
2894 case IW_AUTH_ROAMING_CONTROL:
2895 WL_INFORM("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
2897 case IW_AUTH_PRIVACY_INVOKED:
2901 if (paramval == 0) {
2902 iw->privacy_invoked = false;
2903 error = dev_wlc_intvar_set(dev,
2904 "is_WPS_enrollee", false);
2906 WL_WSEC("Failed to clear iovar is_WPS_enrollee\n");
2910 iw->privacy_invoked = true;
2911 error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2915 if (!(IW_WSEC_ENABLED(wsec))) {
2916 error = dev_wlc_intvar_set(dev,
2920 WL_WSEC("Failed to set iovar is_WPS_enrollee\n");
2924 error = dev_wlc_intvar_set(dev,
2928 WL_WSEC("Failed to clear is_WPS_enrollee\n");
2935 #endif /* WIRELESS_EXT > 17 */
2942 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
2945 wl_iw_get_wpaauth(struct net_device *dev,
2946 struct iw_request_info *info,
2947 struct iw_param *vwrq, char *extra)
2953 wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2955 WL_TRACE("%s: SIOCGIWAUTH\n", dev->name);
2957 paramid = vwrq->flags & IW_AUTH_INDEX;
2960 case IW_AUTH_WPA_VERSION:
2961 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
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;
2971 case IW_AUTH_CIPHER_PAIRWISE:
2972 case IW_AUTH_CIPHER_GROUP:
2973 if (paramid == IW_AUTH_CIPHER_PAIRWISE)
2980 if (val & WEP_ENABLED)
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);
2989 paramval = IW_AUTH_CIPHER_NONE;
2991 case IW_AUTH_KEY_MGMT:
2992 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2996 paramval = IW_AUTH_KEY_MGMT_PSK;
2998 paramval = IW_AUTH_KEY_MGMT_802_1X;
3001 case IW_AUTH_TKIP_COUNTERMEASURES:
3002 dev_wlc_bufvar_get(dev, "tkip_countermeasures",
3003 (char *)¶mval, 1);
3006 case IW_AUTH_DROP_UNENCRYPTED:
3007 dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1);
3010 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
3011 dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol",
3012 (char *)¶mval, 1);
3015 case IW_AUTH_80211_AUTH_ALG:
3016 error = dev_wlc_intvar_get(dev, "auth", &val);
3020 paramval = IW_AUTH_ALG_OPEN_SYSTEM;
3022 paramval = IW_AUTH_ALG_SHARED_KEY;
3024 case IW_AUTH_WPA_ENABLED:
3025 error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
3033 #if WIRELESS_EXT > 17
3034 case IW_AUTH_ROAMING_CONTROL:
3035 WL_ERROR("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
3037 case IW_AUTH_PRIVACY_INVOKED:
3038 paramval = iw->privacy_invoked;
3043 vwrq->value = paramval;
3046 #endif /* WIRELESS_EXT > 17 */
3048 static const iw_handler wl_iw_handler[] = {
3049 (iw_handler) wl_iw_config_commit,
3050 (iw_handler) wl_iw_get_name,
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,
3060 (iw_handler) wl_iw_get_range,
3065 (iw_handler) wl_iw_set_spy,
3066 (iw_handler) wl_iw_get_spy,
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,
3076 #if defined(WL_IW_USE_ISCAN)
3077 (iw_handler) wl_iw_iscan_get_aplist,
3079 (iw_handler) wl_iw_get_aplist,
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,
3086 (iw_handler) wl_iw_set_scan,
3087 (iw_handler) wl_iw_get_scan,
3092 #endif /* WIRELESS_EXT > 13 */
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,
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,
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
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 /* WIRELESS_EXT > 17 */
3128 #if WIRELESS_EXT > 12
3130 const struct iw_handler_def wl_iw_handler_def = {
3131 .num_standard = ARRAY_SIZE(wl_iw_handler),
3132 .standard = (iw_handler *) wl_iw_handler,
3134 .num_private_args = 0,
3138 #if WIRELESS_EXT >= 19
3139 .get_wireless_stats = dhd_get_wireless_stats,
3142 #endif /* WIRELESS_EXT > 12 */
3144 int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
3146 struct iwreq *wrq = (struct iwreq *)rq;
3147 struct iw_request_info info;
3150 int token_size = 1, max_tokens = 0, ret = 0;
3152 WL_TRACE("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
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",
3161 handler = wl_iw_handler[IW_IOCTL_IDX(cmd)];
3163 WL_ERROR("%s: error in cmd=%x : not supported\n",
3174 max_tokens = IW_ESSID_MAX_SIZE + 1;
3179 #if WIRELESS_EXT > 17
3180 case SIOCSIWENCODEEXT:
3181 case SIOCGIWENCODEEXT:
3183 max_tokens = wrq->u.data.length;
3187 max_tokens = sizeof(struct iw_range) + 500;
3192 sizeof(struct sockaddr) + sizeof(struct iw_quality);
3193 max_tokens = IW_MAX_AP;
3196 #if WIRELESS_EXT > 13
3198 #if defined(WL_IW_USE_ISCAN)
3200 max_tokens = wrq->u.data.length;
3203 max_tokens = IW_SCAN_MAX_DATA;
3205 #endif /* WIRELESS_EXT > 13 */
3208 token_size = sizeof(struct sockaddr);
3209 max_tokens = IW_MAX_SPY;
3214 sizeof(struct sockaddr) + sizeof(struct iw_quality);
3215 max_tokens = IW_MAX_SPY;
3218 #if WIRELESS_EXT > 17
3223 max_tokens = wrq->u.data.length;
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);
3233 extra = kmalloc(max_tokens * token_size, GFP_KERNEL);
3238 (extra, wrq->u.data.pointer,
3239 wrq->u.data.length * token_size)) {
3248 ret = handler(dev, &info, &wrq->u, extra);
3252 (wrq->u.data.pointer, extra,
3253 wrq->u.data.length * token_size)) {
3265 wl_iw_conn_status_str(u32 event_type, u32 status, u32 reason,
3266 char *stringBuf, uint buflen)
3268 typedef struct conn_fail_event_map_t {
3272 const char *outName;
3273 const char *outCause;
3274 } conn_fail_event_map_t;
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,
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,
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,
3312 const char *name = "";
3313 const char *cause = NULL;
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;
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);
3340 #if WIRELESS_EXT > 14
3343 wl_iw_check_conn_fail(wl_event_msg_t *e, char *stringBuf, uint buflen)
3345 u32 event = ntoh32(e->event_type);
3346 u32 status = ntoh32(e->status);
3347 u32 reason = ntoh32(e->reason);
3349 if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
3356 #ifndef IW_CUSTOM_MAX
3357 #define IW_CUSTOM_MAX 256
3360 void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
3362 #if WIRELESS_EXT > 13
3363 union iwreq_data wrqu;
3364 char extra[IW_CUSTOM_MAX + 1];
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);
3372 memset(&wrqu, 0, sizeof(wrqu));
3373 memset(extra, 0, sizeof(extra));
3377 WL_ERROR("%s: dev is null\n", __func__);
3381 iw = *(wl_iw_t **) netdev_priv(dev);
3383 WL_TRACE("%s: dev=%s event=%d\n", __func__, dev->name, event_type);
3385 switch (event_type) {
3388 memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3389 wrqu.addr.sa_family = ARPHRD_ETHER;
3391 #if WIRELESS_EXT > 14
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;
3399 case WLC_E_DEAUTH_IND:
3400 case WLC_E_DISASSOC_IND:
3402 memset(wrqu.addr.sa_data, 0, ETH_ALEN);
3403 wrqu.addr.sa_family = ARPHRD_ETHER;
3404 memset(&extra, 0, ETH_ALEN);
3407 case WLC_E_NDIS_LINK:
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,
3415 memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3416 WL_TRACE("Link UP\n");
3419 wrqu.addr.sa_family = ARPHRD_ETHER;
3421 case WLC_E_ACTION_FRAME:
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",
3432 case WLC_E_ACTION_FRAME_COMPLETE:
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,
3441 printf("WLC_E_ACTION_FRAME_COMPLETE len %d\n",
3445 #endif /* WIRELESS_EXT > 14 */
3446 #if WIRELESS_EXT > 17
3447 case WLC_E_MIC_ERROR:
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;
3456 micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
3457 memcpy(micerrevt->src_addr.sa_data, &e->addr,
3459 micerrevt->src_addr.sa_family = ARPHRD_ETHER;
3463 case WLC_E_PMKID_CACHE:
3466 struct iw_pmkid_cand *iwpmkidcand =
3467 (struct iw_pmkid_cand *)&extra;
3468 pmkid_cand_list_t *pmkcandlist;
3469 pmkid_cand_t *pmkidcand;
3472 cmd = IWEVPMKIDCAND;
3476 pmkcandlist->npmkid_cand);
3478 wrqu.data.length = sizeof(struct iw_pmkid_cand);
3479 pmkidcand = pmkcandlist->pmkid_cand;
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,
3490 wireless_send_event(dev, cmd, &wrqu,
3499 #endif /* WIRELESS_EXT > 17 */
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);
3508 wrqu.data.length = strlen(extra);
3509 WL_TRACE("Event WLC_E_SCAN_COMPLETE from specific scan %d\n",
3510 g_iscan->iscan_state);
3514 wrqu.data.length = strlen(extra);
3515 WL_TRACE("Event WLC_E_SCAN_COMPLETE\n");
3519 case WLC_E_PFN_NET_FOUND:
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,
3529 memset(&wrqu, 0, sizeof(wrqu));
3530 strcpy(extra, PNO_EVENT_UP);
3531 wrqu.data.length = strlen(extra);
3536 WL_TRACE("Unknown Event %d: ignoring\n", event_type);
3541 if (cmd == SIOCGIWSCAN)
3542 wireless_send_event(dev, cmd, &wrqu, NULL);
3544 wireless_send_event(dev, cmd, &wrqu, extra);
3548 #if WIRELESS_EXT > 14
3549 memset(extra, 0, sizeof(extra));
3550 if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
3552 wrqu.data.length = strlen(extra);
3554 wireless_send_event(dev, cmd, &wrqu, extra);
3557 #endif /* WIRELESS_EXT > 14 */
3558 #endif /* WIRELESS_EXT > 13 */
3562 wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
3571 res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise,
3576 phy_noise = dtoh32(phy_noise);
3577 WL_TRACE("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise);
3579 memset(&scb_val, 0, sizeof(scb_val_t));
3580 res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
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;
3597 wstats->qual.qual = 5;
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);
3604 wstats->qual.updated |= 7;
3607 #if WIRELESS_EXT > 11
3608 WL_TRACE("wl_iw_get_wireless_stats counters=%zu\n", sizeof(wl_cnt_t));
3610 memset(&cnt, 0, sizeof(wl_cnt_t));
3612 dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
3614 WL_ERROR("wl_iw_get_wireless_stats counters failed error=%d\n",
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);
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;
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 /* WIRELESS_EXT > 11 */
3655 int wl_iw_attach(struct net_device *dev, void *dhdp)
3659 #if defined(WL_IW_USE_ISCAN)
3660 iscan_info_t *iscan = NULL;
3665 memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
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);
3674 (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
3676 iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
3680 memset(iscan, 0, sizeof(iscan_info_t));
3682 iscan->iscan_ex_params_p = kmalloc(params_size, GFP_KERNEL);
3683 if (!iscan->iscan_ex_params_p)
3685 iscan->iscan_ex_param_size = params_size;
3686 iscan->sysioc_tsk = NULL;
3690 iscan->iscan_state = ISCAN_STATE_IDLE;
3692 iscan->timer_ms = 3000;
3693 init_timer(&iscan->timer);
3694 iscan->timer.data = (unsigned long) iscan;
3695 iscan->timer.function = wl_iw_timerfunc;
3697 sema_init(&iscan->sysioc_sem, 0);
3698 iscan->sysioc_tsk = kthread_run(_iscan_sysioc_thread, iscan,
3700 if (IS_ERR(iscan->sysioc_tsk)) {
3701 iscan->sysioc_tsk = NULL;
3704 #endif /* defined(WL_IW_USE_ISCAN) */
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();
3712 MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub);
3714 g_scan = kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
3718 memset(g_scan, 0, G_SCAN_RESULTS);
3719 g_scan_specified_ssid = 0;
3724 void wl_iw_detach(void)
3726 #if defined(WL_IW_USE_ISCAN)
3728 iscan_info_t *iscan = g_iscan;
3732 if (iscan->sysioc_tsk) {
3733 send_sig(SIGTERM, iscan->sysioc_tsk, 1);
3734 kthread_stop(iscan->sysioc_tsk);
3735 iscan->sysioc_tsk = NULL;
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;
3744 MUTEX_UNLOCK_WL_SCAN_SET();
3745 kfree(iscan->iscan_ex_params_p);
3748 #endif /* WL_IW_USE_ISCAN */