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.
24 #include <bcmendian.h>
25 #include <proto/ethernet.h>
27 #include <linux/if_arp.h>
28 #include <asm/uaccess.h>
30 #include <dngl_stats.h>
34 typedef void wlc_info_t
;
35 typedef void wl_info_t
;
36 typedef const struct si_pub si_t
;
39 #include <proto/ethernet.h>
40 #include <dngl_stats.h>
42 #define WL_ERROR(x) printf x
51 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | \
52 TKIP_ENABLED | AES_ENABLED))
54 #include <linux/rtnetlink.h>
56 #define WL_IW_USE_ISCAN 1
57 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1
59 bool g_set_essid_before_scan
= TRUE
;
61 #define WL_IW_IOCTL_CALL(func_call) \
66 static int g_onoff
= G_WLAN_SET_ON
;
67 wl_iw_extra_params_t g_wl_iw_params
;
69 extern bool wl_iw_conn_status_str(uint32 event_type
, uint32 status
,
70 uint32 reason
, char *stringBuf
, uint buflen
);
72 uint wl_msg_level
= WL_ERROR_VAL
;
74 #define MAX_WLIW_IOCTL_LEN 1024
76 #if defined(IL_BIGENDIAN)
77 #include <bcmendian.h>
78 #define htod32(i) (bcmswap32(i))
79 #define htod16(i) (bcmswap16(i))
80 #define dtoh32(i) (bcmswap32(i))
81 #define dtoh16(i) (bcmswap16(i))
82 #define htodchanspec(i) htod16(i)
83 #define dtohchanspec(i) dtoh16(i)
89 #define htodchanspec(i) i
90 #define dtohchanspec(i) i
93 #ifdef CONFIG_WIRELESS_EXT
95 extern struct iw_statistics
*dhd_get_wireless_stats(struct net_device
*dev
);
96 extern int dhd_wait_pend8021x(struct net_device
*dev
);
100 #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
101 #define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
104 static void *g_scan
= NULL
;
105 static volatile uint g_scan_specified_ssid
;
106 static wlc_ssid_t g_specific_ssid
;
108 static wlc_ssid_t g_ssid
;
110 #define DAEMONIZE(a) daemonize(a); \
111 allow_signal(SIGKILL); \
112 allow_signal(SIGTERM);
114 #if defined(WL_IW_USE_ISCAN)
115 #define ISCAN_STATE_IDLE 0
116 #define ISCAN_STATE_SCANING 1
118 #define WLC_IW_ISCAN_MAXLEN 2048
119 typedef struct iscan_buf
{
120 struct iscan_buf
*next
;
121 char iscan_buf
[WLC_IW_ISCAN_MAXLEN
];
124 typedef struct iscan_info
{
125 struct net_device
*dev
;
126 struct timer_list timer
;
130 iscan_buf_t
*list_hdr
;
131 iscan_buf_t
*list_cur
;
134 struct semaphore sysioc_sem
;
135 struct completion sysioc_exited
;
138 char ioctlbuf
[WLC_IOCTL_MEDLEN
];
140 char ioctlbuf
[WLC_IOCTL_SMLEN
];
142 wl_iscan_params_t
*iscan_ex_params_p
;
143 int iscan_ex_param_size
;
145 iscan_info_t
*g_iscan
= NULL
;
146 static void wl_iw_timerfunc(ulong data
);
147 static void wl_iw_set_event_mask(struct net_device
*dev
);
148 static int wl_iw_iscan(iscan_info_t
*iscan
, wlc_ssid_t
*ssid
, uint16 action
);
149 #endif /* defined(WL_IW_USE_ISCAN) */
152 wl_iw_set_scan(struct net_device
*dev
,
153 struct iw_request_info
*info
,
154 union iwreq_data
*wrqu
, char *extra
);
157 wl_iw_get_scan(struct net_device
*dev
,
158 struct iw_request_info
*info
,
159 struct iw_point
*dwrq
, char *extra
);
162 wl_iw_get_scan_prep(wl_scan_results_t
*list
,
163 struct iw_request_info
*info
, char *extra
, short max_size
);
165 static void swap_key_from_BE(wl_wsec_key_t
*key
)
167 key
->index
= htod32(key
->index
);
168 key
->len
= htod32(key
->len
);
169 key
->algo
= htod32(key
->algo
);
170 key
->flags
= htod32(key
->flags
);
171 key
->rxiv
.hi
= htod32(key
->rxiv
.hi
);
172 key
->rxiv
.lo
= htod16(key
->rxiv
.lo
);
173 key
->iv_initialized
= htod32(key
->iv_initialized
);
176 static void swap_key_to_BE(wl_wsec_key_t
*key
)
178 key
->index
= dtoh32(key
->index
);
179 key
->len
= dtoh32(key
->len
);
180 key
->algo
= dtoh32(key
->algo
);
181 key
->flags
= dtoh32(key
->flags
);
182 key
->rxiv
.hi
= dtoh32(key
->rxiv
.hi
);
183 key
->rxiv
.lo
= dtoh16(key
->rxiv
.lo
);
184 key
->iv_initialized
= dtoh32(key
->iv_initialized
);
187 static int dev_wlc_ioctl(struct net_device
*dev
, int cmd
, void *arg
, int len
)
195 WL_ERROR(("%s: dev is null\n", __func__
));
199 WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, "
200 "len:%d ,\n", __func__
, current
->pid
, cmd
, arg
, len
));
202 if (g_onoff
== G_WLAN_SET_ON
) {
203 memset(&ioc
, 0, sizeof(ioc
));
208 strcpy(ifr
.ifr_name
, dev
->name
);
209 ifr
.ifr_data
= (caddr_t
)&ioc
;
213 WL_ERROR(("%s: Error dev_open: %d\n", __func__
, ret
));
219 ret
= dev
->netdev_ops
->ndo_do_ioctl(dev
, &ifr
, SIOCDEVPRIVATE
);
222 WL_TRACE(("%s: call after driver stop : ignored\n", __func__
));
227 static int dev_wlc_intvar_set(struct net_device
*dev
, char *name
, int val
)
229 char buf
[WLC_IOCTL_SMLEN
];
233 len
= bcm_mkiovar(name
, (char *)(&val
), sizeof(val
), buf
, sizeof(buf
));
236 return dev_wlc_ioctl(dev
, WLC_SET_VAR
, buf
, len
);
239 #if defined(WL_IW_USE_ISCAN)
241 dev_iw_iovar_setbuf(struct net_device
*dev
,
243 void *param
, int paramlen
, void *bufptr
, int buflen
)
247 iolen
= bcm_mkiovar(iovar
, param
, paramlen
, bufptr
, buflen
);
253 return dev_wlc_ioctl(dev
, WLC_SET_VAR
, bufptr
, iolen
);
257 dev_iw_iovar_getbuf(struct net_device
*dev
,
259 void *param
, int paramlen
, void *bufptr
, int buflen
)
263 iolen
= bcm_mkiovar(iovar
, param
, paramlen
, bufptr
, buflen
);
266 return dev_wlc_ioctl(dev
, WLC_GET_VAR
, bufptr
, buflen
);
268 #endif /* defined(WL_IW_USE_ISCAN) */
270 #if WIRELESS_EXT > 17
272 dev_wlc_bufvar_set(struct net_device
*dev
, char *name
, char *buf
, int len
)
274 static char ioctlbuf
[MAX_WLIW_IOCTL_LEN
];
277 buflen
= bcm_mkiovar(name
, buf
, len
, ioctlbuf
, sizeof(ioctlbuf
));
280 return dev_wlc_ioctl(dev
, WLC_SET_VAR
, ioctlbuf
, buflen
);
282 #endif /* WIRELESS_EXT > 17 */
285 dev_wlc_bufvar_get(struct net_device
*dev
, char *name
, char *buf
, int buflen
)
287 static char ioctlbuf
[MAX_WLIW_IOCTL_LEN
];
291 len
= bcm_mkiovar(name
, NULL
, 0, ioctlbuf
, sizeof(ioctlbuf
));
294 dev_wlc_ioctl(dev
, WLC_GET_VAR
, (void *)ioctlbuf
,
297 bcopy(ioctlbuf
, buf
, buflen
);
302 static int dev_wlc_intvar_get(struct net_device
*dev
, char *name
, int *retval
)
305 char buf
[WLC_IOCTL_SMLEN
];
314 bcm_mkiovar(name
, (char *)(&data_null
), 0, (char *)(&var
),
317 error
= dev_wlc_ioctl(dev
, WLC_GET_VAR
, (void *)&var
, len
);
319 *retval
= dtoh32(var
.val
);
324 #if WIRELESS_EXT < 13
325 struct iw_request_info
{
330 typedef int (*iw_handler
) (struct net_device
*dev
,
331 struct iw_request_info
*info
,
332 void *wrqu
, char *extra
);
336 wl_iw_config_commit(struct net_device
*dev
,
337 struct iw_request_info
*info
, void *zwrq
, char *extra
)
341 struct sockaddr bssid
;
343 WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev
->name
));
345 error
= dev_wlc_ioctl(dev
, WLC_GET_SSID
, &ssid
, sizeof(ssid
));
349 ssid
.SSID_len
= dtoh32(ssid
.SSID_len
);
354 bzero(&bssid
, sizeof(struct sockaddr
));
355 error
= dev_wlc_ioctl(dev
, WLC_REASSOC
, &bssid
, ETHER_ADDR_LEN
);
357 WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __func__
,
366 wl_iw_get_name(struct net_device
*dev
,
367 struct iw_request_info
*info
, char *cwrq
, char *extra
)
369 WL_TRACE(("%s: SIOCGIWNAME\n", dev
->name
));
371 strcpy(cwrq
, "IEEE 802.11-DS");
377 wl_iw_set_freq(struct net_device
*dev
,
378 struct iw_request_info
*info
, struct iw_freq
*fwrq
, char *extra
)
383 WL_TRACE(("\n %s %s: SIOCSIWFREQ\n", __func__
, dev
->name
));
385 if (fwrq
->e
== 0 && fwrq
->m
< MAXCHANNEL
) {
392 } else if (fwrq
->e
< 6) {
393 while (fwrq
->e
++ < 6)
396 if (fwrq
->m
> 4000 && fwrq
->m
< 5000)
397 sf
= WF_CHAN_FACTOR_4_G
;
399 chan
= wf_mhz2channel(fwrq
->m
, sf
);
403 error
= dev_wlc_ioctl(dev
, WLC_SET_CHANNEL
, &chan
, sizeof(chan
));
407 g_wl_iw_params
.target_channel
= chan
;
412 wl_iw_get_freq(struct net_device
*dev
,
413 struct iw_request_info
*info
, struct iw_freq
*fwrq
, char *extra
)
418 WL_TRACE(("%s: SIOCGIWFREQ\n", dev
->name
));
420 error
= dev_wlc_ioctl(dev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
424 fwrq
->m
= dtoh32(ci
.hw_channel
);
430 wl_iw_set_mode(struct net_device
*dev
,
431 struct iw_request_info
*info
, __u32
*uwrq
, char *extra
)
433 int infra
= 0, ap
= 0, error
= 0;
435 WL_TRACE(("%s: SIOCSIWMODE\n", dev
->name
));
450 infra
= htod32(infra
);
453 error
= dev_wlc_ioctl(dev
, WLC_SET_INFRA
, &infra
, sizeof(infra
));
457 error
= dev_wlc_ioctl(dev
, WLC_SET_AP
, &ap
, sizeof(ap
));
465 wl_iw_get_mode(struct net_device
*dev
,
466 struct iw_request_info
*info
, __u32
*uwrq
, char *extra
)
468 int error
, infra
= 0, ap
= 0;
470 WL_TRACE(("%s: SIOCGIWMODE\n", dev
->name
));
472 error
= dev_wlc_ioctl(dev
, WLC_GET_INFRA
, &infra
, sizeof(infra
));
476 error
= dev_wlc_ioctl(dev
, WLC_GET_AP
, &ap
, sizeof(ap
));
480 infra
= dtoh32(infra
);
482 *uwrq
= infra
? ap
? IW_MODE_MASTER
: IW_MODE_INFRA
: IW_MODE_ADHOC
;
488 wl_iw_get_range(struct net_device
*dev
,
489 struct iw_request_info
*info
,
490 struct iw_point
*dwrq
, char *extra
)
492 struct iw_range
*range
= (struct iw_range
*)extra
;
493 wl_uint32_list_t
*list
;
494 wl_rateset_t rateset
;
500 int bw_cap
= 0, sgi_tx
= 0, nmode
= 0;
502 u8 nrate_list2copy
= 0;
503 uint16 nrate_list
[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
504 {14, 29, 43, 58, 87, 116, 130, 144},
505 {27, 54, 81, 108, 162, 216, 243, 270},
506 {30, 60, 90, 120, 180, 240, 270, 300}
509 WL_TRACE(("%s: SIOCGIWRANGE\n", dev
->name
));
514 channels
= kmalloc((MAXCHANNEL
+ 1) * 4, GFP_KERNEL
);
516 WL_ERROR(("Could not alloc channels\n"));
519 list
= (wl_uint32_list_t
*) channels
;
521 dwrq
->length
= sizeof(struct iw_range
);
522 memset(range
, 0, sizeof(range
));
524 range
->min_nwid
= range
->max_nwid
= 0;
526 list
->count
= htod32(MAXCHANNEL
);
527 error
= dev_wlc_ioctl(dev
, WLC_GET_VALID_CHANNELS
, channels
,
528 (MAXCHANNEL
+ 1) * 4);
533 for (i
= 0; i
< dtoh32(list
->count
) && i
< IW_MAX_FREQUENCIES
; i
++) {
534 range
->freq
[i
].i
= dtoh32(list
->element
[i
]);
536 ch
= dtoh32(list
->element
[i
]);
537 if (ch
<= CH_MAX_2G_CHANNEL
)
538 sf
= WF_CHAN_FACTOR_2_4_G
;
540 sf
= WF_CHAN_FACTOR_5_G
;
542 range
->freq
[i
].m
= wf_channel2mhz(ch
, sf
);
543 range
->freq
[i
].e
= 6;
545 range
->num_frequency
= range
->num_channels
= i
;
547 range
->max_qual
.qual
= 5;
548 range
->max_qual
.level
= 0x100 - 200;
549 range
->max_qual
.noise
= 0x100 - 200;
550 range
->sensitivity
= 65535;
552 #if WIRELESS_EXT > 11
553 range
->avg_qual
.qual
= 3;
554 range
->avg_qual
.level
= 0x100 + WL_IW_RSSI_GOOD
;
555 range
->avg_qual
.noise
= 0x100 - 75;
558 error
= dev_wlc_ioctl(dev
, WLC_GET_CURR_RATESET
, &rateset
,
564 rateset
.count
= dtoh32(rateset
.count
);
565 range
->num_bitrates
= rateset
.count
;
566 for (i
= 0; i
< rateset
.count
&& i
< IW_MAX_BITRATES
; i
++)
567 range
->bitrate
[i
] = (rateset
.rates
[i
] & 0x7f) * 500000;
568 dev_wlc_intvar_get(dev
, "nmode", &nmode
);
569 dev_wlc_ioctl(dev
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
571 if (nmode
== 1 && phytype
== WLC_PHY_TYPE_SSN
) {
572 dev_wlc_intvar_get(dev
, "mimo_bw_cap", &bw_cap
);
573 dev_wlc_intvar_get(dev
, "sgi_tx", &sgi_tx
);
574 dev_wlc_ioctl(dev
, WLC_GET_CHANNEL
, &ci
,
575 sizeof(channel_info_t
));
576 ci
.hw_channel
= dtoh32(ci
.hw_channel
);
578 if (bw_cap
== 0 || (bw_cap
== 2 && ci
.hw_channel
<= 14)) {
584 if (bw_cap
== 1 || (bw_cap
== 2 && ci
.hw_channel
>= 36)) {
590 range
->num_bitrates
+= 8;
591 for (k
= 0; i
< range
->num_bitrates
; k
++, i
++) {
593 (nrate_list
[nrate_list2copy
][k
]) * 500000;
597 error
= dev_wlc_ioctl(dev
, WLC_GET_PHYTYPE
, &i
, sizeof(i
));
603 if (i
== WLC_PHY_TYPE_A
)
604 range
->throughput
= 24000000;
606 range
->throughput
= 1500000;
609 range
->max_rts
= 2347;
610 range
->min_frag
= 256;
611 range
->max_frag
= 2346;
613 range
->max_encoding_tokens
= DOT11_MAX_DEFAULT_KEYS
;
614 range
->num_encoding_sizes
= 4;
615 range
->encoding_size
[0] = WEP1_KEY_SIZE
;
616 range
->encoding_size
[1] = WEP128_KEY_SIZE
;
617 #if WIRELESS_EXT > 17
618 range
->encoding_size
[2] = TKIP_KEY_SIZE
;
620 range
->encoding_size
[2] = 0;
622 range
->encoding_size
[3] = AES_KEY_SIZE
;
628 range
->pmp_flags
= 0;
631 range
->num_txpower
= 2;
632 range
->txpower
[0] = 1;
633 range
->txpower
[1] = 255;
634 range
->txpower_capa
= IW_TXPOW_MWATT
;
636 #if WIRELESS_EXT > 10
637 range
->we_version_compiled
= WIRELESS_EXT
;
638 range
->we_version_source
= 19;
640 range
->retry_capa
= IW_RETRY_LIMIT
;
641 range
->retry_flags
= IW_RETRY_LIMIT
;
642 range
->r_time_flags
= 0;
643 range
->min_retry
= 1;
644 range
->max_retry
= 255;
645 range
->min_r_time
= 0;
646 range
->max_r_time
= 0;
649 #if WIRELESS_EXT > 17
650 range
->enc_capa
= IW_ENC_CAPA_WPA
;
651 range
->enc_capa
|= IW_ENC_CAPA_CIPHER_TKIP
;
652 range
->enc_capa
|= IW_ENC_CAPA_CIPHER_CCMP
;
654 range
->enc_capa
|= IW_ENC_CAPA_WPA2
;
657 IW_EVENT_CAPA_SET_KERNEL(range
->event_capa
);
658 IW_EVENT_CAPA_SET(range
->event_capa
, SIOCGIWAP
);
659 IW_EVENT_CAPA_SET(range
->event_capa
, SIOCGIWSCAN
);
660 IW_EVENT_CAPA_SET(range
->event_capa
, IWEVTXDROP
);
661 IW_EVENT_CAPA_SET(range
->event_capa
, IWEVMICHAELMICFAILURE
);
663 IW_EVENT_CAPA_SET(range
->event_capa
, IWEVPMKIDCAND
);
665 #endif /* WIRELESS_EXT > 17 */
672 static int rssi_to_qual(int rssi
)
674 if (rssi
<= WL_IW_RSSI_NO_SIGNAL
)
676 else if (rssi
<= WL_IW_RSSI_VERY_LOW
)
678 else if (rssi
<= WL_IW_RSSI_LOW
)
680 else if (rssi
<= WL_IW_RSSI_GOOD
)
682 else if (rssi
<= WL_IW_RSSI_VERY_GOOD
)
689 wl_iw_set_spy(struct net_device
*dev
,
690 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
692 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
693 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
696 WL_TRACE(("%s: SIOCSIWSPY\n", dev
->name
));
701 iw
->spy_num
= MIN(ARRAYSIZE(iw
->spy_addr
), dwrq
->length
);
702 for (i
= 0; i
< iw
->spy_num
; i
++)
703 memcpy(&iw
->spy_addr
[i
], addr
[i
].sa_data
, ETHER_ADDR_LEN
);
704 memset(iw
->spy_qual
, 0, sizeof(iw
->spy_qual
));
710 wl_iw_get_spy(struct net_device
*dev
,
711 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
713 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
714 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
715 struct iw_quality
*qual
= (struct iw_quality
*)&addr
[iw
->spy_num
];
718 WL_TRACE(("%s: SIOCGIWSPY\n", dev
->name
));
723 dwrq
->length
= iw
->spy_num
;
724 for (i
= 0; i
< iw
->spy_num
; i
++) {
725 memcpy(addr
[i
].sa_data
, &iw
->spy_addr
[i
], ETHER_ADDR_LEN
);
726 addr
[i
].sa_family
= AF_UNIX
;
727 memcpy(&qual
[i
], &iw
->spy_qual
[i
], sizeof(struct iw_quality
));
728 iw
->spy_qual
[i
].updated
= 0;
735 wl_iw_ch_to_chanspec(int ch
, wl_join_params_t
*join_params
,
736 int *join_params_size
)
738 chanspec_t chanspec
= 0;
741 join_params
->params
.chanspec_num
= 1;
742 join_params
->params
.chanspec_list
[0] = ch
;
744 if (join_params
->params
.chanspec_list
[0])
745 chanspec
|= WL_CHANSPEC_BAND_2G
;
747 chanspec
|= WL_CHANSPEC_BAND_5G
;
749 chanspec
|= WL_CHANSPEC_BW_20
;
750 chanspec
|= WL_CHANSPEC_CTL_SB_NONE
;
752 *join_params_size
+= WL_ASSOC_PARAMS_FIXED_SIZE
+
753 join_params
->params
.chanspec_num
* sizeof(chanspec_t
);
755 join_params
->params
.chanspec_list
[0] &= WL_CHANSPEC_CHAN_MASK
;
756 join_params
->params
.chanspec_list
[0] |= chanspec
;
757 join_params
->params
.chanspec_list
[0] =
758 htodchanspec(join_params
->params
.chanspec_list
[0]);
760 join_params
->params
.chanspec_num
=
761 htod32(join_params
->params
.chanspec_num
);
763 WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n",
764 __func__
, join_params
->params
.chanspec_list
[0]));
770 wl_iw_set_wap(struct net_device
*dev
,
771 struct iw_request_info
*info
, struct sockaddr
*awrq
, char *extra
)
774 wl_join_params_t join_params
;
775 int join_params_size
;
777 WL_TRACE(("%s: SIOCSIWAP\n", dev
->name
));
779 if (awrq
->sa_family
!= ARPHRD_ETHER
) {
780 WL_ERROR(("Invalid Header...sa_family\n"));
784 if (ETHER_ISBCAST(awrq
->sa_data
) || ETHER_ISNULLADDR(awrq
->sa_data
)) {
786 bzero(&scbval
, sizeof(scb_val_t
));
787 (void)dev_wlc_ioctl(dev
, WLC_DISASSOC
, &scbval
,
792 memset(&join_params
, 0, sizeof(join_params
));
793 join_params_size
= sizeof(join_params
.ssid
);
795 memcpy(join_params
.ssid
.SSID
, g_ssid
.SSID
, g_ssid
.SSID_len
);
796 join_params
.ssid
.SSID_len
= htod32(g_ssid
.SSID_len
);
797 memcpy(&join_params
.params
.bssid
, awrq
->sa_data
, ETHER_ADDR_LEN
);
799 WL_TRACE(("%s target_channel=%d\n", __func__
,
800 g_wl_iw_params
.target_channel
));
801 wl_iw_ch_to_chanspec(g_wl_iw_params
.target_channel
, &join_params
,
804 error
= dev_wlc_ioctl(dev
, WLC_SET_SSID
, &join_params
,
807 WL_ERROR(("%s Invalid ioctl data=%d\n", __func__
, error
));
810 if (g_ssid
.SSID_len
) {
811 WL_TRACE(("%s: join SSID=%s BSSID=" MACSTR
" ch=%d\n",
812 __func__
, g_ssid
.SSID
,
813 MAC2STR((u8
*) awrq
->sa_data
),
814 g_wl_iw_params
.target_channel
));
817 memset(&g_ssid
, 0, sizeof(g_ssid
));
822 wl_iw_get_wap(struct net_device
*dev
,
823 struct iw_request_info
*info
, struct sockaddr
*awrq
, char *extra
)
825 WL_TRACE(("%s: SIOCGIWAP\n", dev
->name
));
827 awrq
->sa_family
= ARPHRD_ETHER
;
828 memset(awrq
->sa_data
, 0, ETHER_ADDR_LEN
);
830 (void)dev_wlc_ioctl(dev
, WLC_GET_BSSID
, awrq
->sa_data
, ETHER_ADDR_LEN
);
835 #if WIRELESS_EXT > 17
837 wl_iw_mlme(struct net_device
*dev
,
838 struct iw_request_info
*info
, struct sockaddr
*awrq
, char *extra
)
840 struct iw_mlme
*mlme
;
844 WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev
->name
));
846 mlme
= (struct iw_mlme
*)extra
;
848 WL_ERROR(("Invalid ioctl data.\n"));
852 scbval
.val
= mlme
->reason_code
;
853 bcopy(&mlme
->addr
.sa_data
, &scbval
.ea
, ETHER_ADDR_LEN
);
855 if (mlme
->cmd
== IW_MLME_DISASSOC
) {
856 scbval
.val
= htod32(scbval
.val
);
858 dev_wlc_ioctl(dev
, WLC_DISASSOC
, &scbval
,
860 } else if (mlme
->cmd
== IW_MLME_DEAUTH
) {
861 scbval
.val
= htod32(scbval
.val
);
863 dev_wlc_ioctl(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
,
864 &scbval
, sizeof(scb_val_t
));
866 WL_ERROR(("Invalid ioctl data.\n"));
872 #endif /* WIRELESS_EXT > 17 */
874 #ifndef WL_IW_USE_ISCAN
876 wl_iw_get_aplist(struct net_device
*dev
,
877 struct iw_request_info
*info
,
878 struct iw_point
*dwrq
, char *extra
)
880 wl_scan_results_t
*list
;
881 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
882 struct iw_quality qual
[IW_MAX_AP
];
883 wl_bss_info_t
*bi
= NULL
;
885 uint buflen
= dwrq
->length
;
887 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev
->name
));
892 list
= kmalloc(buflen
, GFP_KERNEL
);
895 memset(list
, 0, buflen
);
896 list
->buflen
= htod32(buflen
);
897 error
= dev_wlc_ioctl(dev
, WLC_SCAN_RESULTS
, list
, buflen
);
899 WL_ERROR(("%d: Scan results error %d\n", __LINE__
, error
));
903 list
->buflen
= dtoh32(list
->buflen
);
904 list
->version
= dtoh32(list
->version
);
905 list
->count
= dtoh32(list
->count
);
906 if (list
->version
!= WL_BSS_INFO_VERSION
) {
907 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
908 __func__
, list
->version
));
913 for (i
= 0, dwrq
->length
= 0;
914 i
< list
->count
&& dwrq
->length
< IW_MAX_AP
; i
++) {
915 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
916 dtoh32(bi
->length
)) : list
->
918 ASSERT(((uintptr
) bi
+ dtoh32(bi
->length
)) <=
919 ((uintptr
) list
+ buflen
));
921 if (!(dtoh16(bi
->capability
) & DOT11_CAP_ESS
))
924 memcpy(addr
[dwrq
->length
].sa_data
, &bi
->BSSID
, ETHER_ADDR_LEN
);
925 addr
[dwrq
->length
].sa_family
= ARPHRD_ETHER
;
926 qual
[dwrq
->length
].qual
= rssi_to_qual(dtoh16(bi
->RSSI
));
927 qual
[dwrq
->length
].level
= 0x100 + dtoh16(bi
->RSSI
);
928 qual
[dwrq
->length
].noise
= 0x100 + bi
->phy_noise
;
930 #if WIRELESS_EXT > 18
931 qual
[dwrq
->length
].updated
= IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
;
933 qual
[dwrq
->length
].updated
= 7;
941 memcpy(&addr
[dwrq
->length
], qual
,
942 sizeof(struct iw_quality
) * dwrq
->length
);
948 #endif /* WL_IW_USE_ISCAN */
950 #ifdef WL_IW_USE_ISCAN
952 wl_iw_iscan_get_aplist(struct net_device
*dev
,
953 struct iw_request_info
*info
,
954 struct iw_point
*dwrq
, char *extra
)
956 wl_scan_results_t
*list
;
958 iscan_info_t
*iscan
= g_iscan
;
960 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
961 struct iw_quality qual
[IW_MAX_AP
];
962 wl_bss_info_t
*bi
= NULL
;
965 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev
->name
));
970 if ((!iscan
) || (iscan
->sysioc_pid
< 0)) {
971 WL_ERROR(("%s error\n", __func__
));
975 buf
= iscan
->list_hdr
;
977 list
= &((wl_iscan_results_t
*) buf
->iscan_buf
)->results
;
978 if (list
->version
!= WL_BSS_INFO_VERSION
) {
979 WL_ERROR(("%s : list->version %d != "
980 "WL_BSS_INFO_VERSION\n",
981 __func__
, list
->version
));
986 for (i
= 0, dwrq
->length
= 0;
987 i
< list
->count
&& dwrq
->length
< IW_MAX_AP
; i
++) {
988 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
989 dtoh32(bi
->length
)) :
991 ASSERT(((uintptr
) bi
+ dtoh32(bi
->length
)) <=
992 ((uintptr
) list
+ WLC_IW_ISCAN_MAXLEN
));
994 if (!(dtoh16(bi
->capability
) & DOT11_CAP_ESS
))
997 memcpy(addr
[dwrq
->length
].sa_data
, &bi
->BSSID
,
999 addr
[dwrq
->length
].sa_family
= ARPHRD_ETHER
;
1000 qual
[dwrq
->length
].qual
=
1001 rssi_to_qual(dtoh16(bi
->RSSI
));
1002 qual
[dwrq
->length
].level
= 0x100 + dtoh16(bi
->RSSI
);
1003 qual
[dwrq
->length
].noise
= 0x100 + bi
->phy_noise
;
1005 #if WIRELESS_EXT > 18
1006 qual
[dwrq
->length
].updated
=
1007 IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
;
1009 qual
[dwrq
->length
].updated
= 7;
1017 memcpy(&addr
[dwrq
->length
], qual
,
1018 sizeof(struct iw_quality
) * dwrq
->length
);
1025 static int wl_iw_iscan_prep(wl_scan_params_t
*params
, wlc_ssid_t
*ssid
)
1029 memcpy(¶ms
->bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
1030 params
->bss_type
= DOT11_BSSTYPE_ANY
;
1031 params
->scan_type
= 0;
1032 params
->nprobes
= -1;
1033 params
->active_time
= -1;
1034 params
->passive_time
= -1;
1035 params
->home_time
= -1;
1036 params
->channel_num
= 0;
1038 params
->nprobes
= htod32(params
->nprobes
);
1039 params
->active_time
= htod32(params
->active_time
);
1040 params
->passive_time
= htod32(params
->passive_time
);
1041 params
->home_time
= htod32(params
->home_time
);
1042 if (ssid
&& ssid
->SSID_len
)
1043 memcpy(¶ms
->ssid
, ssid
, sizeof(wlc_ssid_t
));
1048 static int wl_iw_iscan(iscan_info_t
*iscan
, wlc_ssid_t
*ssid
, uint16 action
)
1052 iscan
->iscan_ex_params_p
->version
= htod32(ISCAN_REQ_VERSION
);
1053 iscan
->iscan_ex_params_p
->action
= htod16(action
);
1054 iscan
->iscan_ex_params_p
->scan_duration
= htod16(0);
1056 WL_SCAN(("%s : nprobes=%d\n", __func__
,
1057 iscan
->iscan_ex_params_p
->params
.nprobes
));
1058 WL_SCAN(("active_time=%d\n",
1059 iscan
->iscan_ex_params_p
->params
.active_time
));
1060 WL_SCAN(("passive_time=%d\n",
1061 iscan
->iscan_ex_params_p
->params
.passive_time
));
1062 WL_SCAN(("home_time=%d\n", iscan
->iscan_ex_params_p
->params
.home_time
));
1063 WL_SCAN(("scan_type=%d\n", iscan
->iscan_ex_params_p
->params
.scan_type
));
1064 WL_SCAN(("bss_type=%d\n", iscan
->iscan_ex_params_p
->params
.bss_type
));
1066 (void)dev_iw_iovar_setbuf(iscan
->dev
, "iscan", iscan
->iscan_ex_params_p
,
1067 iscan
->iscan_ex_param_size
, iscan
->ioctlbuf
,
1068 sizeof(iscan
->ioctlbuf
));
1073 static void wl_iw_timerfunc(ulong data
)
1075 iscan_info_t
*iscan
= (iscan_info_t
*) data
;
1077 iscan
->timer_on
= 0;
1078 if (iscan
->iscan_state
!= ISCAN_STATE_IDLE
) {
1079 WL_TRACE(("timer trigger\n"));
1080 up(&iscan
->sysioc_sem
);
1085 static void wl_iw_set_event_mask(struct net_device
*dev
)
1087 char eventmask
[WL_EVENTING_MASK_LEN
];
1088 char iovbuf
[WL_EVENTING_MASK_LEN
+ 12];
1090 dev_iw_iovar_getbuf(dev
, "event_msgs", "", 0, iovbuf
, sizeof(iovbuf
));
1091 bcopy(iovbuf
, eventmask
, WL_EVENTING_MASK_LEN
);
1092 setbit(eventmask
, WLC_E_SCAN_COMPLETE
);
1093 dev_iw_iovar_setbuf(dev
, "event_msgs", eventmask
, WL_EVENTING_MASK_LEN
,
1094 iovbuf
, sizeof(iovbuf
));
1097 static uint32
wl_iw_iscan_get(iscan_info_t
*iscan
)
1101 wl_iscan_results_t
*list_buf
;
1102 wl_iscan_results_t list
;
1103 wl_scan_results_t
*results
;
1107 MUTEX_LOCK_WL_SCAN_SET();
1108 if (iscan
->list_cur
) {
1109 buf
= iscan
->list_cur
;
1110 iscan
->list_cur
= buf
->next
;
1112 buf
= kmalloc(sizeof(iscan_buf_t
), GFP_KERNEL
);
1114 WL_ERROR(("%s can't alloc iscan_buf_t : going to abort "
1115 "currect iscan\n", __func__
));
1116 MUTEX_UNLOCK_WL_SCAN_SET();
1117 return WL_SCAN_RESULTS_NO_MEM
;
1120 if (!iscan
->list_hdr
)
1121 iscan
->list_hdr
= buf
;
1123 ptr
= iscan
->list_hdr
;
1130 memset(buf
->iscan_buf
, 0, WLC_IW_ISCAN_MAXLEN
);
1131 list_buf
= (wl_iscan_results_t
*) buf
->iscan_buf
;
1132 results
= &list_buf
->results
;
1133 results
->buflen
= WL_ISCAN_RESULTS_FIXED_SIZE
;
1134 results
->version
= 0;
1137 memset(&list
, 0, sizeof(list
));
1138 list
.results
.buflen
= htod32(WLC_IW_ISCAN_MAXLEN
);
1139 res
= dev_iw_iovar_getbuf(iscan
->dev
,
1142 WL_ISCAN_RESULTS_FIXED_SIZE
,
1143 buf
->iscan_buf
, WLC_IW_ISCAN_MAXLEN
);
1145 results
->buflen
= dtoh32(results
->buflen
);
1146 results
->version
= dtoh32(results
->version
);
1147 results
->count
= dtoh32(results
->count
);
1148 WL_TRACE(("results->count = %d\n", results
->count
));
1149 WL_TRACE(("results->buflen = %d\n", results
->buflen
));
1150 status
= dtoh32(list_buf
->status
);
1152 WL_ERROR(("%s returns error %d\n", __func__
, res
));
1153 status
= WL_SCAN_RESULTS_NO_MEM
;
1155 MUTEX_UNLOCK_WL_SCAN_SET();
1159 static void wl_iw_force_specific_scan(iscan_info_t
*iscan
)
1161 WL_TRACE(("%s force Specific SCAN for %s\n", __func__
,
1162 g_specific_ssid
.SSID
));
1165 (void)dev_wlc_ioctl(iscan
->dev
, WLC_SCAN
, &g_specific_ssid
,
1166 sizeof(g_specific_ssid
));
1171 static void wl_iw_send_scan_complete(iscan_info_t
*iscan
)
1174 union iwreq_data wrqu
;
1176 memset(&wrqu
, 0, sizeof(wrqu
));
1178 wireless_send_event(iscan
->dev
, SIOCGIWSCAN
, &wrqu
, NULL
);
1179 WL_TRACE(("Send Event ISCAN complete\n"));
1183 static int _iscan_sysioc_thread(void *data
)
1186 iscan_info_t
*iscan
= (iscan_info_t
*) data
;
1187 static bool iscan_pass_abort
= FALSE
;
1188 DAEMONIZE("iscan_sysioc");
1190 status
= WL_SCAN_RESULTS_PARTIAL
;
1191 while (down_interruptible(&iscan
->sysioc_sem
) == 0) {
1193 if (iscan
->timer_on
) {
1194 del_timer_sync(&iscan
->timer
);
1195 iscan
->timer_on
= 0;
1198 status
= wl_iw_iscan_get(iscan
);
1200 if (g_scan_specified_ssid
&& (iscan_pass_abort
== TRUE
)) {
1201 WL_TRACE(("%s Get results from specific scan "
1202 "status = %d\n", __func__
, status
));
1203 wl_iw_send_scan_complete(iscan
);
1204 iscan_pass_abort
= FALSE
;
1209 case WL_SCAN_RESULTS_PARTIAL
:
1210 WL_TRACE(("iscanresults incomplete\n"));
1212 wl_iw_iscan(iscan
, NULL
, WL_SCAN_ACTION_CONTINUE
);
1214 mod_timer(&iscan
->timer
,
1215 jiffies
+ iscan
->timer_ms
* HZ
/ 1000);
1216 iscan
->timer_on
= 1;
1218 case WL_SCAN_RESULTS_SUCCESS
:
1219 WL_TRACE(("iscanresults complete\n"));
1220 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
1221 wl_iw_send_scan_complete(iscan
);
1223 case WL_SCAN_RESULTS_PENDING
:
1224 WL_TRACE(("iscanresults pending\n"));
1225 mod_timer(&iscan
->timer
,
1226 jiffies
+ iscan
->timer_ms
* HZ
/ 1000);
1227 iscan
->timer_on
= 1;
1229 case WL_SCAN_RESULTS_ABORTED
:
1230 WL_TRACE(("iscanresults aborted\n"));
1231 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
1232 if (g_scan_specified_ssid
== 0)
1233 wl_iw_send_scan_complete(iscan
);
1235 iscan_pass_abort
= TRUE
;
1236 wl_iw_force_specific_scan(iscan
);
1239 case WL_SCAN_RESULTS_NO_MEM
:
1240 WL_TRACE(("iscanresults can't alloc memory: skip\n"));
1241 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
1244 WL_TRACE(("iscanresults returned unknown status %d\n",
1250 if (iscan
->timer_on
) {
1251 del_timer_sync(&iscan
->timer
);
1252 iscan
->timer_on
= 0;
1254 complete_and_exit(&iscan
->sysioc_exited
, 0);
1256 #endif /* WL_IW_USE_ISCAN */
1259 wl_iw_set_scan(struct net_device
*dev
,
1260 struct iw_request_info
*info
,
1261 union iwreq_data
*wrqu
, char *extra
)
1264 WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__
, dev
->name
));
1266 g_set_essid_before_scan
= FALSE
;
1268 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__
));
1272 if (g_onoff
== G_WLAN_SET_OFF
)
1275 memset(&g_specific_ssid
, 0, sizeof(g_specific_ssid
));
1276 #ifndef WL_IW_USE_ISCAN
1277 g_scan_specified_ssid
= 0;
1280 #if WIRELESS_EXT > 17
1281 if (wrqu
->data
.length
== sizeof(struct iw_scan_req
)) {
1282 if (wrqu
->data
.flags
& IW_SCAN_THIS_ESSID
) {
1283 struct iw_scan_req
*req
= (struct iw_scan_req
*)extra
;
1284 if (g_scan_specified_ssid
) {
1285 WL_TRACE(("%s Specific SCAN is not done ignore "
1287 __func__
, req
->essid
));
1290 g_specific_ssid
.SSID_len
=
1291 MIN(sizeof(g_specific_ssid
.SSID
),
1293 memcpy(g_specific_ssid
.SSID
, req
->essid
,
1294 g_specific_ssid
.SSID_len
);
1295 g_specific_ssid
.SSID_len
=
1296 htod32(g_specific_ssid
.SSID_len
);
1297 g_scan_specified_ssid
= 1;
1298 WL_TRACE(("### Specific scan ssid=%s len=%d\n",
1299 g_specific_ssid
.SSID
,
1300 g_specific_ssid
.SSID_len
));
1304 #endif /* WIRELESS_EXT > 17 */
1305 error
= dev_wlc_ioctl(dev
, WLC_SCAN
, &g_specific_ssid
,
1306 sizeof(g_specific_ssid
));
1308 WL_TRACE(("#### Set SCAN for %s failed with %d\n",
1309 g_specific_ssid
.SSID
, error
));
1310 g_scan_specified_ssid
= 0;
1317 #ifdef WL_IW_USE_ISCAN
1318 int wl_iw_iscan_set_scan_broadcast_prep(struct net_device
*dev
, uint flag
)
1321 iscan_info_t
*iscan
= g_iscan
;
1326 wl_iw_set_event_mask(dev
);
1328 WL_TRACE(("+++: Set Broadcast ISCAN\n"));
1329 memset(&ssid
, 0, sizeof(ssid
));
1331 iscan
->list_cur
= iscan
->list_hdr
;
1332 iscan
->iscan_state
= ISCAN_STATE_SCANING
;
1334 memset(&iscan
->iscan_ex_params_p
->params
, 0,
1335 iscan
->iscan_ex_param_size
);
1336 wl_iw_iscan_prep(&iscan
->iscan_ex_params_p
->params
, &ssid
);
1337 wl_iw_iscan(iscan
, &ssid
, WL_SCAN_ACTION_START
);
1342 mod_timer(&iscan
->timer
, jiffies
+ iscan
->timer_ms
* HZ
/ 1000);
1344 iscan
->timer_on
= 1;
1350 wl_iw_iscan_set_scan(struct net_device
*dev
,
1351 struct iw_request_info
*info
,
1352 union iwreq_data
*wrqu
, char *extra
)
1355 iscan_info_t
*iscan
= g_iscan
;
1357 WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev
->name
));
1360 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__
));
1364 if (g_onoff
== G_WLAN_SET_OFF
) {
1365 WL_TRACE(("%s: driver is not up yet after START\n", __func__
));
1369 if (dhd_dev_get_pno_status(dev
)) {
1370 WL_ERROR(("%s: Scan called when PNO is active\n", __func__
));
1374 if ((!iscan
) || (iscan
->sysioc_pid
< 0))
1375 return wl_iw_set_scan(dev
, info
, wrqu
, extra
);
1377 if (g_scan_specified_ssid
) {
1378 WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n",
1383 memset(&ssid
, 0, sizeof(ssid
));
1385 #if WIRELESS_EXT > 17
1386 if (wrqu
->data
.length
== sizeof(struct iw_scan_req
)) {
1387 if (wrqu
->data
.flags
& IW_SCAN_THIS_ESSID
) {
1388 struct iw_scan_req
*req
= (struct iw_scan_req
*)extra
;
1389 ssid
.SSID_len
= MIN(sizeof(ssid
.SSID
), req
->essid_len
);
1390 memcpy(ssid
.SSID
, req
->essid
, ssid
.SSID_len
);
1391 ssid
.SSID_len
= htod32(ssid
.SSID_len
);
1393 g_scan_specified_ssid
= 0;
1395 if (iscan
->iscan_state
== ISCAN_STATE_SCANING
) {
1396 WL_TRACE(("%s ISCAN already in progress \n",
1402 #endif /* WIRELESS_EXT > 17 */
1403 wl_iw_iscan_set_scan_broadcast_prep(dev
, 0);
1407 #endif /* WL_IW_USE_ISCAN */
1409 #if WIRELESS_EXT > 17
1410 static bool ie_is_wpa_ie(u8
**wpaie
, u8
**tlvs
, int *tlvs_len
)
1416 !bcmp((const void *)&ie
[2], (const void *)(WPA_OUI
"\x01"), 4)) {
1421 *tlvs_len
-= (int)(ie
- *tlvs
);
1426 static bool ie_is_wps_ie(u8
**wpsie
, u8
**tlvs
, int *tlvs_len
)
1432 !bcmp((const void *)&ie
[2], (const void *)(WPA_OUI
"\x04"), 4)) {
1437 *tlvs_len
-= (int)(ie
- *tlvs
);
1441 #endif /* WIRELESS_EXT > 17 */
1444 wl_iw_handle_scanresults_ies(char **event_p
, char *end
,
1445 struct iw_request_info
*info
, wl_bss_info_t
*bi
)
1447 #if WIRELESS_EXT > 17
1448 struct iw_event iwe
;
1452 if (bi
->ie_length
) {
1454 u8
*ptr
= ((u8
*) bi
) + sizeof(wl_bss_info_t
);
1455 int ptr_len
= bi
->ie_length
;
1458 ie
= bcm_parse_tlvs(ptr
, ptr_len
, DOT11_MNG_RSN_ID
);
1460 iwe
.cmd
= IWEVGENIE
;
1461 iwe
.u
.data
.length
= ie
->len
+ 2;
1463 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1466 ptr
= ((u8
*) bi
) + sizeof(wl_bss_info_t
);
1469 while ((ie
= bcm_parse_tlvs(ptr
, ptr_len
, DOT11_MNG_WPA_ID
))) {
1470 if (ie_is_wps_ie(((u8
**)&ie
), &ptr
, &ptr_len
)) {
1471 iwe
.cmd
= IWEVGENIE
;
1472 iwe
.u
.data
.length
= ie
->len
+ 2;
1474 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1480 ptr
= ((u8
*) bi
) + sizeof(wl_bss_info_t
);
1481 ptr_len
= bi
->ie_length
;
1482 while ((ie
= bcm_parse_tlvs(ptr
, ptr_len
, DOT11_MNG_WPA_ID
))) {
1483 if (ie_is_wpa_ie(((u8
**)&ie
), &ptr
, &ptr_len
)) {
1484 iwe
.cmd
= IWEVGENIE
;
1485 iwe
.u
.data
.length
= ie
->len
+ 2;
1487 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1495 #endif /* WIRELESS_EXT > 17 */
1500 wl_iw_get_scan_prep(wl_scan_results_t
*list
,
1501 struct iw_request_info
*info
, char *extra
, short max_size
)
1504 struct iw_event iwe
;
1505 wl_bss_info_t
*bi
= NULL
;
1506 char *event
= extra
, *end
= extra
+ max_size
- WE_ADD_EVENT_FIX
, *value
;
1511 for (i
= 0; i
< list
->count
&& i
< IW_MAX_AP
; i
++) {
1512 if (list
->version
!= WL_BSS_INFO_VERSION
) {
1513 WL_ERROR(("%s : list->version %d != "
1514 "WL_BSS_INFO_VERSION\n",
1515 __func__
, list
->version
));
1519 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
1520 dtoh32(bi
->length
)) : list
->
1523 WL_TRACE(("%s : %s\n", __func__
, bi
->SSID
));
1525 iwe
.cmd
= SIOCGIWAP
;
1526 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
1527 memcpy(iwe
.u
.ap_addr
.sa_data
, &bi
->BSSID
, ETHER_ADDR_LEN
);
1529 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1531 iwe
.u
.data
.length
= dtoh32(bi
->SSID_len
);
1532 iwe
.cmd
= SIOCGIWESSID
;
1533 iwe
.u
.data
.flags
= 1;
1534 event
= IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
, bi
->SSID
);
1536 if (dtoh16(bi
->capability
) & (DOT11_CAP_ESS
| DOT11_CAP_IBSS
)) {
1537 iwe
.cmd
= SIOCGIWMODE
;
1538 if (dtoh16(bi
->capability
) & DOT11_CAP_ESS
)
1539 iwe
.u
.mode
= IW_MODE_INFRA
;
1541 iwe
.u
.mode
= IW_MODE_ADHOC
;
1543 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1547 iwe
.cmd
= SIOCGIWFREQ
;
1548 iwe
.u
.freq
.m
= wf_channel2mhz(CHSPEC_CHANNEL(bi
->chanspec
),
1549 CHSPEC_CHANNEL(bi
->chanspec
) <=
1551 WF_CHAN_FACTOR_2_4_G
:
1552 WF_CHAN_FACTOR_5_G
);
1555 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1559 iwe
.u
.qual
.qual
= rssi_to_qual(dtoh16(bi
->RSSI
));
1560 iwe
.u
.qual
.level
= 0x100 + dtoh16(bi
->RSSI
);
1561 iwe
.u
.qual
.noise
= 0x100 + bi
->phy_noise
;
1563 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1566 wl_iw_handle_scanresults_ies(&event
, end
, info
, bi
);
1568 iwe
.cmd
= SIOCGIWENCODE
;
1569 if (dtoh16(bi
->capability
) & DOT11_CAP_PRIVACY
)
1570 iwe
.u
.data
.flags
= IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
1572 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
1573 iwe
.u
.data
.length
= 0;
1575 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
, (char *)event
);
1577 if (bi
->rateset
.count
) {
1578 if (((event
- extra
) +
1579 IW_EV_LCP_LEN
) <= (uintptr
) end
) {
1580 value
= event
+ IW_EV_LCP_LEN
;
1581 iwe
.cmd
= SIOCGIWRATE
;
1582 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
=
1585 j
< bi
->rateset
.count
1586 && j
< IW_MAX_BITRATES
; j
++) {
1587 iwe
.u
.bitrate
.value
=
1588 (bi
->rateset
.rates
[j
] & 0x7f) *
1591 IWE_STREAM_ADD_VALUE(info
, event
,
1600 ret
= event
- extra
;
1602 WL_ERROR(("==> Wrong size\n"));
1605 WL_TRACE(("%s: size=%d bytes prepared\n", __func__
,
1606 (unsigned int)(event
- extra
)));
1611 wl_iw_get_scan(struct net_device
*dev
,
1612 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
1615 wl_scan_results_t
*list_merge
;
1616 wl_scan_results_t
*list
= (wl_scan_results_t
*) g_scan
;
1618 uint buflen_from_user
= dwrq
->length
;
1619 uint len
= G_SCAN_RESULTS
;
1621 #if defined(WL_IW_USE_ISCAN)
1622 iscan_info_t
*iscan
= g_iscan
;
1626 WL_TRACE(("%s: buflen_from_user %d: \n", dev
->name
, buflen_from_user
));
1629 WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev
->name
));
1633 error
= dev_wlc_ioctl(dev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
1636 ci
.scan_channel
= dtoh32(ci
.scan_channel
);
1637 if (ci
.scan_channel
)
1640 if (g_scan_specified_ssid
) {
1641 list
= kmalloc(len
, GFP_KERNEL
);
1643 WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n",
1645 g_scan_specified_ssid
= 0;
1650 memset(list
, 0, len
);
1651 list
->buflen
= htod32(len
);
1652 error
= dev_wlc_ioctl(dev
, WLC_SCAN_RESULTS
, list
, len
);
1654 WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev
->name
,
1657 if (g_scan_specified_ssid
) {
1658 g_scan_specified_ssid
= 0;
1663 list
->buflen
= dtoh32(list
->buflen
);
1664 list
->version
= dtoh32(list
->version
);
1665 list
->count
= dtoh32(list
->count
);
1667 if (list
->version
!= WL_BSS_INFO_VERSION
) {
1668 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1669 __func__
, list
->version
));
1670 if (g_scan_specified_ssid
) {
1671 g_scan_specified_ssid
= 0;
1677 if (g_scan_specified_ssid
) {
1678 WL_TRACE(("%s: Specified scan APs in the list =%d\n",
1679 __func__
, list
->count
));
1681 (__u16
) wl_iw_get_scan_prep(list
, info
, extra
,
1685 #if defined(WL_IW_USE_ISCAN)
1686 p_buf
= iscan
->list_hdr
;
1687 while (p_buf
!= iscan
->list_cur
) {
1689 &((wl_iscan_results_t
*) p_buf
->iscan_buf
)->results
;
1690 WL_TRACE(("%s: Bcast APs list=%d\n", __func__
,
1691 list_merge
->count
));
1692 if (list_merge
->count
> 0)
1694 (__u16
) wl_iw_get_scan_prep(list_merge
,
1695 info
, extra
+ len_ret
,
1696 buflen_from_user
- len_ret
);
1697 p_buf
= p_buf
->next
;
1700 list_merge
= (wl_scan_results_t
*) g_scan
;
1701 WL_TRACE(("%s: Bcast APs list=%d\n", __func__
,
1702 list_merge
->count
));
1703 if (list_merge
->count
> 0)
1705 (__u16
) wl_iw_get_scan_prep(list_merge
, info
,
1709 #endif /* defined(WL_IW_USE_ISCAN) */
1711 list
= (wl_scan_results_t
*) g_scan
;
1713 (__u16
) wl_iw_get_scan_prep(list
, info
, extra
,
1717 #if defined(WL_IW_USE_ISCAN)
1718 g_scan_specified_ssid
= 0;
1720 if ((len_ret
+ WE_ADD_EVENT_FIX
) < buflen_from_user
)
1726 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__
,
1727 dwrq
->length
, list
->count
));
1731 #if defined(WL_IW_USE_ISCAN)
1733 wl_iw_iscan_get_scan(struct net_device
*dev
,
1734 struct iw_request_info
*info
,
1735 struct iw_point
*dwrq
, char *extra
)
1737 wl_scan_results_t
*list
;
1738 struct iw_event iwe
;
1739 wl_bss_info_t
*bi
= NULL
;
1742 char *event
= extra
, *end
= extra
+ dwrq
->length
, *value
;
1743 iscan_info_t
*iscan
= g_iscan
;
1748 WL_TRACE(("%s %s buflen_from_user %d:\n", dev
->name
, __func__
,
1752 WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
1757 if ((!iscan
) || (iscan
->sysioc_pid
< 0)) {
1758 WL_ERROR(("%ssysioc_pid\n", __func__
));
1759 return wl_iw_get_scan(dev
, info
, dwrq
, extra
);
1762 if (iscan
->iscan_state
== ISCAN_STATE_SCANING
) {
1763 WL_TRACE(("%s: SIOCGIWSCAN GET still scanning\n", dev
->name
));
1767 WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev
->name
));
1769 p_buf
= iscan
->list_hdr
;
1770 while (p_buf
!= iscan
->list_cur
) {
1771 list
= &((wl_iscan_results_t
*) p_buf
->iscan_buf
)->results
;
1773 counter
+= list
->count
;
1775 if (list
->version
!= WL_BSS_INFO_VERSION
) {
1776 WL_ERROR(("%s : list->version %d != "
1777 "WL_BSS_INFO_VERSION\n",
1778 __func__
, list
->version
));
1783 for (ii
= 0; ii
< list
->count
&& apcnt
< IW_MAX_AP
;
1785 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
1786 dtoh32(bi
->length
)) :
1788 ASSERT(((uintptr
) bi
+ dtoh32(bi
->length
)) <=
1789 ((uintptr
) list
+ WLC_IW_ISCAN_MAXLEN
));
1791 if (event
+ ETHER_ADDR_LEN
+ bi
->SSID_len
+
1792 IW_EV_UINT_LEN
+ IW_EV_FREQ_LEN
+ IW_EV_QUAL_LEN
>=
1795 iwe
.cmd
= SIOCGIWAP
;
1796 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
1797 memcpy(iwe
.u
.ap_addr
.sa_data
, &bi
->BSSID
,
1800 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1803 iwe
.u
.data
.length
= dtoh32(bi
->SSID_len
);
1804 iwe
.cmd
= SIOCGIWESSID
;
1805 iwe
.u
.data
.flags
= 1;
1807 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1810 if (dtoh16(bi
->capability
) &
1811 (DOT11_CAP_ESS
| DOT11_CAP_IBSS
)) {
1812 iwe
.cmd
= SIOCGIWMODE
;
1813 if (dtoh16(bi
->capability
) & DOT11_CAP_ESS
)
1814 iwe
.u
.mode
= IW_MODE_INFRA
;
1816 iwe
.u
.mode
= IW_MODE_ADHOC
;
1818 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1822 iwe
.cmd
= SIOCGIWFREQ
;
1825 0) ? CHSPEC_CHANNEL(bi
->chanspec
) : bi
->ctl_ch
;
1827 wf_channel2mhz(channel
,
1830 WF_CHAN_FACTOR_2_4_G
:
1831 WF_CHAN_FACTOR_5_G
);
1834 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1838 iwe
.u
.qual
.qual
= rssi_to_qual(dtoh16(bi
->RSSI
));
1839 iwe
.u
.qual
.level
= 0x100 + dtoh16(bi
->RSSI
);
1840 iwe
.u
.qual
.noise
= 0x100 + bi
->phy_noise
;
1842 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1845 wl_iw_handle_scanresults_ies(&event
, end
, info
, bi
);
1847 iwe
.cmd
= SIOCGIWENCODE
;
1848 if (dtoh16(bi
->capability
) & DOT11_CAP_PRIVACY
)
1850 IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
1852 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
1853 iwe
.u
.data
.length
= 0;
1855 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1858 if (bi
->rateset
.count
) {
1859 if (event
+ IW_MAX_BITRATES
* IW_EV_PARAM_LEN
>=
1863 value
= event
+ IW_EV_LCP_LEN
;
1864 iwe
.cmd
= SIOCGIWRATE
;
1865 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
=
1868 j
< bi
->rateset
.count
1869 && j
< IW_MAX_BITRATES
; j
++) {
1870 iwe
.u
.bitrate
.value
=
1871 (bi
->rateset
.rates
[j
] & 0x7f) *
1874 IWE_STREAM_ADD_VALUE(info
, event
,
1882 p_buf
= p_buf
->next
;
1885 dwrq
->length
= event
- extra
;
1888 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__
,
1889 dwrq
->length
, counter
));
1896 #endif /* defined(WL_IW_USE_ISCAN) */
1899 wl_iw_set_essid(struct net_device
*dev
,
1900 struct iw_request_info
*info
,
1901 struct iw_point
*dwrq
, char *extra
)
1904 wl_join_params_t join_params
;
1905 int join_params_size
;
1907 WL_TRACE(("%s: SIOCSIWESSID\n", dev
->name
));
1909 if (g_set_essid_before_scan
)
1912 memset(&g_ssid
, 0, sizeof(g_ssid
));
1914 CHECK_EXTRA_FOR_NULL(extra
);
1916 if (dwrq
->length
&& extra
) {
1917 #if WIRELESS_EXT > 20
1918 g_ssid
.SSID_len
= MIN(sizeof(g_ssid
.SSID
), dwrq
->length
);
1920 g_ssid
.SSID_len
= MIN(sizeof(g_ssid
.SSID
), dwrq
->length
- 1);
1922 memcpy(g_ssid
.SSID
, extra
, g_ssid
.SSID_len
);
1924 g_ssid
.SSID_len
= 0;
1926 g_ssid
.SSID_len
= htod32(g_ssid
.SSID_len
);
1928 memset(&join_params
, 0, sizeof(join_params
));
1929 join_params_size
= sizeof(join_params
.ssid
);
1931 memcpy(&join_params
.ssid
.SSID
, g_ssid
.SSID
, g_ssid
.SSID_len
);
1932 join_params
.ssid
.SSID_len
= htod32(g_ssid
.SSID_len
);
1933 memcpy(&join_params
.params
.bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
1935 wl_iw_ch_to_chanspec(g_wl_iw_params
.target_channel
, &join_params
,
1938 error
= dev_wlc_ioctl(dev
, WLC_SET_SSID
, &join_params
,
1941 WL_ERROR(("Invalid ioctl data=%d\n", error
));
1943 if (g_ssid
.SSID_len
) {
1944 WL_TRACE(("%s: join SSID=%s ch=%d\n", __func__
,
1945 g_ssid
.SSID
, g_wl_iw_params
.target_channel
));
1951 wl_iw_get_essid(struct net_device
*dev
,
1952 struct iw_request_info
*info
,
1953 struct iw_point
*dwrq
, char *extra
)
1958 WL_TRACE(("%s: SIOCGIWESSID\n", dev
->name
));
1963 error
= dev_wlc_ioctl(dev
, WLC_GET_SSID
, &ssid
, sizeof(ssid
));
1965 WL_ERROR(("Error getting the SSID\n"));
1969 ssid
.SSID_len
= dtoh32(ssid
.SSID_len
);
1971 memcpy(extra
, ssid
.SSID
, ssid
.SSID_len
);
1973 dwrq
->length
= ssid
.SSID_len
;
1981 wl_iw_set_nick(struct net_device
*dev
,
1982 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
1984 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
1986 WL_TRACE(("%s: SIOCSIWNICKN\n", dev
->name
));
1991 if (dwrq
->length
> sizeof(iw
->nickname
))
1994 memcpy(iw
->nickname
, extra
, dwrq
->length
);
1995 iw
->nickname
[dwrq
->length
- 1] = '\0';
2001 wl_iw_get_nick(struct net_device
*dev
,
2002 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
2004 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
2006 WL_TRACE(("%s: SIOCGIWNICKN\n", dev
->name
));
2011 strcpy(extra
, iw
->nickname
);
2012 dwrq
->length
= strlen(extra
) + 1;
2018 wl_iw_set_rate(struct net_device
*dev
,
2019 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2021 wl_rateset_t rateset
;
2022 int error
, rate
, i
, error_bg
, error_a
;
2024 WL_TRACE(("%s: SIOCSIWRATE\n", dev
->name
));
2026 error
= dev_wlc_ioctl(dev
, WLC_GET_CURR_RATESET
, &rateset
,
2031 rateset
.count
= dtoh32(rateset
.count
);
2033 if (vwrq
->value
< 0)
2034 rate
= rateset
.rates
[rateset
.count
- 1] & 0x7f;
2035 else if (vwrq
->value
< rateset
.count
)
2036 rate
= rateset
.rates
[vwrq
->value
] & 0x7f;
2038 rate
= vwrq
->value
/ 500000;
2041 error_bg
= dev_wlc_intvar_set(dev
, "bg_rate", rate
);
2042 error_a
= dev_wlc_intvar_set(dev
, "a_rate", rate
);
2044 if (error_bg
&& error_a
)
2045 return error_bg
| error_a
;
2047 error_bg
= dev_wlc_intvar_set(dev
, "bg_rate", 0);
2048 error_a
= dev_wlc_intvar_set(dev
, "a_rate", 0);
2050 if (error_bg
&& error_a
)
2051 return error_bg
| error_a
;
2053 for (i
= 0; i
< rateset
.count
; i
++)
2054 if ((rateset
.rates
[i
] & 0x7f) > rate
)
2056 rateset
.count
= htod32(i
);
2058 error
= dev_wlc_ioctl(dev
, WLC_SET_RATESET
, &rateset
,
2068 wl_iw_get_rate(struct net_device
*dev
,
2069 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2073 WL_TRACE(("%s: SIOCGIWRATE\n", dev
->name
));
2075 error
= dev_wlc_ioctl(dev
, WLC_GET_RATE
, &rate
, sizeof(rate
));
2078 rate
= dtoh32(rate
);
2079 vwrq
->value
= rate
* 500000;
2085 wl_iw_set_rts(struct net_device
*dev
,
2086 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2090 WL_TRACE(("%s: SIOCSIWRTS\n", dev
->name
));
2093 rts
= DOT11_DEFAULT_RTS_LEN
;
2094 else if (vwrq
->value
< 0 || vwrq
->value
> DOT11_DEFAULT_RTS_LEN
)
2099 error
= dev_wlc_intvar_set(dev
, "rtsthresh", rts
);
2107 wl_iw_get_rts(struct net_device
*dev
,
2108 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2112 WL_TRACE(("%s: SIOCGIWRTS\n", dev
->name
));
2114 error
= dev_wlc_intvar_get(dev
, "rtsthresh", &rts
);
2119 vwrq
->disabled
= (rts
>= DOT11_DEFAULT_RTS_LEN
);
2126 wl_iw_set_frag(struct net_device
*dev
,
2127 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2131 WL_TRACE(("%s: SIOCSIWFRAG\n", dev
->name
));
2134 frag
= DOT11_DEFAULT_FRAG_LEN
;
2135 else if (vwrq
->value
< 0 || vwrq
->value
> DOT11_DEFAULT_FRAG_LEN
)
2140 error
= dev_wlc_intvar_set(dev
, "fragthresh", frag
);
2148 wl_iw_get_frag(struct net_device
*dev
,
2149 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2151 int error
, fragthreshold
;
2153 WL_TRACE(("%s: SIOCGIWFRAG\n", dev
->name
));
2155 error
= dev_wlc_intvar_get(dev
, "fragthresh", &fragthreshold
);
2159 vwrq
->value
= fragthreshold
;
2160 vwrq
->disabled
= (fragthreshold
>= DOT11_DEFAULT_FRAG_LEN
);
2167 wl_iw_set_txpow(struct net_device
*dev
,
2168 struct iw_request_info
*info
,
2169 struct iw_param
*vwrq
, char *extra
)
2173 WL_TRACE(("%s: SIOCSIWTXPOW\n", dev
->name
));
2175 disable
= vwrq
->disabled
? WL_RADIO_SW_DISABLE
: 0;
2176 disable
+= WL_RADIO_SW_DISABLE
<< 16;
2178 disable
= htod32(disable
);
2179 error
= dev_wlc_ioctl(dev
, WLC_SET_RADIO
, &disable
, sizeof(disable
));
2183 if (disable
& WL_RADIO_SW_DISABLE
)
2186 if (!(vwrq
->flags
& IW_TXPOW_MWATT
))
2189 if (vwrq
->value
< 0)
2192 if (vwrq
->value
> 0xffff)
2195 txpwrmw
= (uint16
) vwrq
->value
;
2198 dev_wlc_intvar_set(dev
, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw
)));
2203 wl_iw_get_txpow(struct net_device
*dev
,
2204 struct iw_request_info
*info
,
2205 struct iw_param
*vwrq
, char *extra
)
2207 int error
, disable
, txpwrdbm
;
2210 WL_TRACE(("%s: SIOCGIWTXPOW\n", dev
->name
));
2212 error
= dev_wlc_ioctl(dev
, WLC_GET_RADIO
, &disable
, sizeof(disable
));
2216 error
= dev_wlc_intvar_get(dev
, "qtxpower", &txpwrdbm
);
2220 disable
= dtoh32(disable
);
2221 result
= (u8
) (txpwrdbm
& ~WL_TXPWR_OVERRIDE
);
2222 vwrq
->value
= (int32
) bcm_qdbm_to_mw(result
);
2225 (disable
& (WL_RADIO_SW_DISABLE
| WL_RADIO_HW_DISABLE
)) ? 1 : 0;
2226 vwrq
->flags
= IW_TXPOW_MWATT
;
2231 #if WIRELESS_EXT > 10
2233 wl_iw_set_retry(struct net_device
*dev
,
2234 struct iw_request_info
*info
,
2235 struct iw_param
*vwrq
, char *extra
)
2237 int error
, lrl
, srl
;
2239 WL_TRACE(("%s: SIOCSIWRETRY\n", dev
->name
));
2241 if (vwrq
->disabled
|| (vwrq
->flags
& IW_RETRY_LIFETIME
))
2244 if (vwrq
->flags
& IW_RETRY_LIMIT
) {
2246 #if WIRELESS_EXT > 20
2247 if ((vwrq
->flags
& IW_RETRY_LONG
)
2248 || (vwrq
->flags
& IW_RETRY_MAX
)
2249 || !((vwrq
->flags
& IW_RETRY_SHORT
)
2250 || (vwrq
->flags
& IW_RETRY_MIN
))) {
2252 if ((vwrq
->flags
& IW_RETRY_MAX
)
2253 || !(vwrq
->flags
& IW_RETRY_MIN
)) {
2255 lrl
= htod32(vwrq
->value
);
2256 error
= dev_wlc_ioctl(dev
, WLC_SET_LRL
, &lrl
,
2261 #if WIRELESS_EXT > 20
2262 if ((vwrq
->flags
& IW_RETRY_SHORT
)
2263 || (vwrq
->flags
& IW_RETRY_MIN
)
2264 || !((vwrq
->flags
& IW_RETRY_LONG
)
2265 || (vwrq
->flags
& IW_RETRY_MAX
))) {
2267 if ((vwrq
->flags
& IW_RETRY_MIN
)
2268 || !(vwrq
->flags
& IW_RETRY_MAX
)) {
2270 srl
= htod32(vwrq
->value
);
2271 error
= dev_wlc_ioctl(dev
, WLC_SET_SRL
, &srl
,
2281 wl_iw_get_retry(struct net_device
*dev
,
2282 struct iw_request_info
*info
,
2283 struct iw_param
*vwrq
, char *extra
)
2285 int error
, lrl
, srl
;
2287 WL_TRACE(("%s: SIOCGIWRETRY\n", dev
->name
));
2291 if ((vwrq
->flags
& IW_RETRY_TYPE
) == IW_RETRY_LIFETIME
)
2294 error
= dev_wlc_ioctl(dev
, WLC_GET_LRL
, &lrl
, sizeof(lrl
));
2298 error
= dev_wlc_ioctl(dev
, WLC_GET_SRL
, &srl
, sizeof(srl
));
2305 if (vwrq
->flags
& IW_RETRY_MAX
) {
2306 vwrq
->flags
= IW_RETRY_LIMIT
| IW_RETRY_MAX
;
2309 vwrq
->flags
= IW_RETRY_LIMIT
;
2312 vwrq
->flags
|= IW_RETRY_MIN
;
2317 #endif /* WIRELESS_EXT > 10 */
2320 wl_iw_set_encode(struct net_device
*dev
,
2321 struct iw_request_info
*info
,
2322 struct iw_point
*dwrq
, char *extra
)
2325 int error
, val
, wsec
;
2327 WL_TRACE(("%s: SIOCSIWENCODE\n", dev
->name
));
2329 memset(&key
, 0, sizeof(key
));
2331 if ((dwrq
->flags
& IW_ENCODE_INDEX
) == 0) {
2332 for (key
.index
= 0; key
.index
< DOT11_MAX_DEFAULT_KEYS
;
2334 val
= htod32(key
.index
);
2335 error
= dev_wlc_ioctl(dev
, WLC_GET_KEY_PRIMARY
, &val
,
2343 if (key
.index
== DOT11_MAX_DEFAULT_KEYS
)
2346 key
.index
= (dwrq
->flags
& IW_ENCODE_INDEX
) - 1;
2347 if (key
.index
>= DOT11_MAX_DEFAULT_KEYS
)
2351 if (!extra
|| !dwrq
->length
|| (dwrq
->flags
& IW_ENCODE_NOKEY
)) {
2352 val
= htod32(key
.index
);
2353 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY_PRIMARY
, &val
,
2358 key
.len
= dwrq
->length
;
2360 if (dwrq
->length
> sizeof(key
.data
))
2363 memcpy(key
.data
, extra
, dwrq
->length
);
2365 key
.flags
= WL_PRIMARY_KEY
;
2368 key
.algo
= CRYPTO_ALGO_WEP1
;
2370 case WEP128_KEY_SIZE
:
2371 key
.algo
= CRYPTO_ALGO_WEP128
;
2374 key
.algo
= CRYPTO_ALGO_TKIP
;
2377 key
.algo
= CRYPTO_ALGO_AES_CCM
;
2383 swap_key_from_BE(&key
);
2384 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY
, &key
, sizeof(key
));
2389 val
= (dwrq
->flags
& IW_ENCODE_DISABLED
) ? 0 : WEP_ENABLED
;
2391 error
= dev_wlc_intvar_get(dev
, "wsec", &wsec
);
2395 wsec
&= ~(WEP_ENABLED
);
2398 error
= dev_wlc_intvar_set(dev
, "wsec", wsec
);
2402 val
= (dwrq
->flags
& IW_ENCODE_RESTRICTED
) ? 1 : 0;
2404 error
= dev_wlc_ioctl(dev
, WLC_SET_AUTH
, &val
, sizeof(val
));
2412 wl_iw_get_encode(struct net_device
*dev
,
2413 struct iw_request_info
*info
,
2414 struct iw_point
*dwrq
, char *extra
)
2417 int error
, val
, wsec
, auth
;
2419 WL_TRACE(("%s: SIOCGIWENCODE\n", dev
->name
));
2421 bzero(&key
, sizeof(wl_wsec_key_t
));
2423 if ((dwrq
->flags
& IW_ENCODE_INDEX
) == 0) {
2424 for (key
.index
= 0; key
.index
< DOT11_MAX_DEFAULT_KEYS
;
2427 error
= dev_wlc_ioctl(dev
, WLC_GET_KEY_PRIMARY
, &val
,
2436 key
.index
= (dwrq
->flags
& IW_ENCODE_INDEX
) - 1;
2438 if (key
.index
>= DOT11_MAX_DEFAULT_KEYS
)
2441 error
= dev_wlc_ioctl(dev
, WLC_GET_WSEC
, &wsec
, sizeof(wsec
));
2445 error
= dev_wlc_ioctl(dev
, WLC_GET_AUTH
, &auth
, sizeof(auth
));
2449 swap_key_to_BE(&key
);
2451 wsec
= dtoh32(wsec
);
2452 auth
= dtoh32(auth
);
2453 dwrq
->length
= MIN(DOT11_MAX_KEY_SIZE
, key
.len
);
2455 dwrq
->flags
= key
.index
+ 1;
2456 if (!(wsec
& (WEP_ENABLED
| TKIP_ENABLED
| AES_ENABLED
)))
2457 dwrq
->flags
|= IW_ENCODE_DISABLED
;
2460 dwrq
->flags
|= IW_ENCODE_RESTRICTED
;
2462 if (dwrq
->length
&& extra
)
2463 memcpy(extra
, key
.data
, dwrq
->length
);
2469 wl_iw_set_power(struct net_device
*dev
,
2470 struct iw_request_info
*info
,
2471 struct iw_param
*vwrq
, char *extra
)
2475 WL_TRACE(("%s: SIOCSIWPOWER\n", dev
->name
));
2477 pm
= vwrq
->disabled
? PM_OFF
: PM_MAX
;
2480 error
= dev_wlc_ioctl(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
2488 wl_iw_get_power(struct net_device
*dev
,
2489 struct iw_request_info
*info
,
2490 struct iw_param
*vwrq
, char *extra
)
2494 WL_TRACE(("%s: SIOCGIWPOWER\n", dev
->name
));
2496 error
= dev_wlc_ioctl(dev
, WLC_GET_PM
, &pm
, sizeof(pm
));
2501 vwrq
->disabled
= pm
? 0 : 1;
2502 vwrq
->flags
= IW_POWER_ALL_R
;
2507 #if WIRELESS_EXT > 17
2509 wl_iw_set_wpaie(struct net_device
*dev
,
2510 struct iw_request_info
*info
, struct iw_point
*iwp
, char *extra
)
2513 WL_TRACE(("%s: SIOCSIWGENIE\n", dev
->name
));
2515 CHECK_EXTRA_FOR_NULL(extra
);
2517 dev_wlc_bufvar_set(dev
, "wpaie", extra
, iwp
->length
);
2523 wl_iw_get_wpaie(struct net_device
*dev
,
2524 struct iw_request_info
*info
, struct iw_point
*iwp
, char *extra
)
2526 WL_TRACE(("%s: SIOCGIWGENIE\n", dev
->name
));
2528 dev_wlc_bufvar_get(dev
, "wpaie", extra
, iwp
->length
);
2533 wl_iw_set_encodeext(struct net_device
*dev
,
2534 struct iw_request_info
*info
,
2535 struct iw_point
*dwrq
, char *extra
)
2539 struct iw_encode_ext
*iwe
;
2541 WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev
->name
));
2543 CHECK_EXTRA_FOR_NULL(extra
);
2545 memset(&key
, 0, sizeof(key
));
2546 iwe
= (struct iw_encode_ext
*)extra
;
2548 if (dwrq
->flags
& IW_ENCODE_DISABLED
) {
2553 if (dwrq
->flags
& IW_ENCODE_INDEX
)
2554 key
.index
= (dwrq
->flags
& IW_ENCODE_INDEX
) - 1;
2556 key
.len
= iwe
->key_len
;
2558 if (!ETHER_ISMULTI(iwe
->addr
.sa_data
))
2559 bcopy((void *)&iwe
->addr
.sa_data
, (char *)&key
.ea
,
2563 if (iwe
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
2564 WL_WSEC(("Changing the the primary Key to %d\n",
2566 key
.index
= htod32(key
.index
);
2567 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY_PRIMARY
,
2568 &key
.index
, sizeof(key
.index
));
2572 swap_key_from_BE(&key
);
2573 dev_wlc_ioctl(dev
, WLC_SET_KEY
, &key
, sizeof(key
));
2576 if (iwe
->key_len
> sizeof(key
.data
))
2579 WL_WSEC(("Setting the key index %d\n", key
.index
));
2580 if (iwe
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
2581 WL_WSEC(("key is a Primary Key\n"));
2582 key
.flags
= WL_PRIMARY_KEY
;
2585 bcopy((void *)iwe
->key
, key
.data
, iwe
->key_len
);
2587 if (iwe
->alg
== IW_ENCODE_ALG_TKIP
) {
2589 bcopy(&key
.data
[24], keybuf
, sizeof(keybuf
));
2590 bcopy(&key
.data
[16], &key
.data
[24], sizeof(keybuf
));
2591 bcopy(keybuf
, &key
.data
[16], sizeof(keybuf
));
2594 if (iwe
->ext_flags
& IW_ENCODE_EXT_RX_SEQ_VALID
) {
2596 ivptr
= (uchar
*) iwe
->rx_seq
;
2597 key
.rxiv
.hi
= (ivptr
[5] << 24) | (ivptr
[4] << 16) |
2598 (ivptr
[3] << 8) | ivptr
[2];
2599 key
.rxiv
.lo
= (ivptr
[1] << 8) | ivptr
[0];
2600 key
.iv_initialized
= TRUE
;
2604 case IW_ENCODE_ALG_NONE
:
2605 key
.algo
= CRYPTO_ALGO_OFF
;
2607 case IW_ENCODE_ALG_WEP
:
2608 if (iwe
->key_len
== WEP1_KEY_SIZE
)
2609 key
.algo
= CRYPTO_ALGO_WEP1
;
2611 key
.algo
= CRYPTO_ALGO_WEP128
;
2613 case IW_ENCODE_ALG_TKIP
:
2614 key
.algo
= CRYPTO_ALGO_TKIP
;
2616 case IW_ENCODE_ALG_CCMP
:
2617 key
.algo
= CRYPTO_ALGO_AES_CCM
;
2622 swap_key_from_BE(&key
);
2624 dhd_wait_pend8021x(dev
);
2626 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY
, &key
, sizeof(key
));
2633 #if WIRELESS_EXT > 17
2636 pmkid_list_t pmkids
;
2637 pmkid_t foo
[MAXPMKID
- 1];
2641 wl_iw_set_pmksa(struct net_device
*dev
,
2642 struct iw_request_info
*info
,
2643 struct iw_param
*vwrq
, char *extra
)
2645 struct iw_pmksa
*iwpmksa
;
2648 char eabuf
[ETHER_ADDR_STR_LEN
];
2650 WL_WSEC(("%s: SIOCSIWPMKSA\n", dev
->name
));
2652 CHECK_EXTRA_FOR_NULL(extra
);
2654 iwpmksa
= (struct iw_pmksa
*)extra
;
2655 bzero((char *)eabuf
, ETHER_ADDR_STR_LEN
);
2657 if (iwpmksa
->cmd
== IW_PMKSA_FLUSH
) {
2658 WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
2659 bzero((char *)&pmkid_list
, sizeof(pmkid_list
));
2662 else if (iwpmksa
->cmd
== IW_PMKSA_REMOVE
) {
2664 pmkid_list_t pmkid
, *pmkidptr
;
2668 bcopy(&iwpmksa
->bssid
.sa_data
[0],
2669 &pmkidptr
->pmkid
[0].BSSID
, ETHER_ADDR_LEN
);
2670 bcopy(&iwpmksa
->pmkid
[0], &pmkidptr
->pmkid
[0].PMKID
,
2673 WL_WSEC(("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: %s = ",
2674 bcm_ether_ntoa(&pmkidptr
->pmkid
[0].BSSID
, eabuf
)));
2675 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++)
2676 WL_WSEC(("%02x ", pmkidptr
->pmkid
[0].PMKID
[j
]));
2680 for (i
= 0; i
< pmkid_list
.pmkids
.npmkid
; i
++)
2682 (&iwpmksa
->bssid
.sa_data
[0],
2683 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
, ETHER_ADDR_LEN
))
2686 if ((pmkid_list
.pmkids
.npmkid
> 0)
2687 && (i
< pmkid_list
.pmkids
.npmkid
)) {
2688 bzero(&pmkid_list
.pmkids
.pmkid
[i
], sizeof(pmkid_t
));
2689 for (; i
< (pmkid_list
.pmkids
.npmkid
- 1); i
++) {
2690 bcopy(&pmkid_list
.pmkids
.pmkid
[i
+ 1].BSSID
,
2691 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
,
2693 bcopy(&pmkid_list
.pmkids
.pmkid
[i
+ 1].PMKID
,
2694 &pmkid_list
.pmkids
.pmkid
[i
].PMKID
,
2697 pmkid_list
.pmkids
.npmkid
--;
2702 else if (iwpmksa
->cmd
== IW_PMKSA_ADD
) {
2703 for (i
= 0; i
< pmkid_list
.pmkids
.npmkid
; i
++)
2705 (&iwpmksa
->bssid
.sa_data
[0],
2706 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
, ETHER_ADDR_LEN
))
2709 bcopy(&iwpmksa
->bssid
.sa_data
[0],
2710 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
,
2712 bcopy(&iwpmksa
->pmkid
[0],
2713 &pmkid_list
.pmkids
.pmkid
[i
].PMKID
,
2715 if (i
== pmkid_list
.pmkids
.npmkid
)
2716 pmkid_list
.pmkids
.npmkid
++;
2722 k
= pmkid_list
.pmkids
.npmkid
;
2723 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
2724 bcm_ether_ntoa(&pmkid_list
.pmkids
.pmkid
[k
].
2726 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++)
2728 pmkid_list
.pmkids
.pmkid
[k
].PMKID
[j
]));
2732 WL_WSEC(("PRINTING pmkid LIST - No of elements %d\n",
2733 pmkid_list
.pmkids
.npmkid
));
2734 for (i
= 0; i
< pmkid_list
.pmkids
.npmkid
; i
++) {
2736 WL_WSEC(("PMKID[%d]: %s = ", i
,
2737 bcm_ether_ntoa(&pmkid_list
.pmkids
.pmkid
[i
].BSSID
,
2739 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++)
2740 WL_WSEC(("%02x ", pmkid_list
.pmkids
.pmkid
[i
].PMKID
[j
]));
2746 ret
= dev_wlc_bufvar_set(dev
, "pmkid_info", (char *)&pmkid_list
,
2747 sizeof(pmkid_list
));
2750 #endif /* BCMWPA2 */
2751 #endif /* WIRELESS_EXT > 17 */
2754 wl_iw_get_encodeext(struct net_device
*dev
,
2755 struct iw_request_info
*info
,
2756 struct iw_param
*vwrq
, char *extra
)
2758 WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev
->name
));
2763 wl_iw_set_wpaauth(struct net_device
*dev
,
2764 struct iw_request_info
*info
,
2765 struct iw_param
*vwrq
, char *extra
)
2771 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
2773 WL_TRACE(("%s: SIOCSIWAUTH\n", dev
->name
));
2775 paramid
= vwrq
->flags
& IW_AUTH_INDEX
;
2776 paramval
= vwrq
->value
;
2778 WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
2779 dev
->name
, paramid
, paramval
));
2782 case IW_AUTH_WPA_VERSION
:
2783 if (paramval
& IW_AUTH_WPA_VERSION_DISABLED
)
2784 val
= WPA_AUTH_DISABLED
;
2785 else if (paramval
& (IW_AUTH_WPA_VERSION_WPA
))
2786 val
= WPA_AUTH_PSK
| WPA_AUTH_UNSPECIFIED
;
2788 else if (paramval
& IW_AUTH_WPA_VERSION_WPA2
)
2789 val
= WPA2_AUTH_PSK
| WPA2_AUTH_UNSPECIFIED
;
2791 WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __func__
,
2793 error
= dev_wlc_intvar_set(dev
, "wpa_auth", val
);
2797 case IW_AUTH_CIPHER_PAIRWISE
:
2798 case IW_AUTH_CIPHER_GROUP
:
2799 if (paramval
& (IW_AUTH_CIPHER_WEP40
| IW_AUTH_CIPHER_WEP104
))
2801 if (paramval
& IW_AUTH_CIPHER_TKIP
)
2803 if (paramval
& IW_AUTH_CIPHER_CCMP
)
2806 if (paramid
== IW_AUTH_CIPHER_PAIRWISE
) {
2814 if (iw
->privacy_invoked
&& !val
) {
2815 WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing "
2816 "wsec, assuming " "we're a WPS enrollee\n",
2817 dev
->name
, __func__
));
2818 error
= dev_wlc_intvar_set(dev
, "is_WPS_enrollee",
2821 WL_WSEC(("Failed to set is_WPS_enrollee\n"));
2825 error
= dev_wlc_intvar_set(dev
, "is_WPS_enrollee",
2828 WL_WSEC(("Failed to clear is_WPS_enrollee\n"));
2833 error
= dev_wlc_intvar_set(dev
, "wsec", val
);
2839 case IW_AUTH_KEY_MGMT
:
2840 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
2844 if (val
& (WPA_AUTH_PSK
| WPA_AUTH_UNSPECIFIED
)) {
2845 if (paramval
& IW_AUTH_KEY_MGMT_PSK
)
2848 val
= WPA_AUTH_UNSPECIFIED
;
2851 else if (val
& (WPA2_AUTH_PSK
| WPA2_AUTH_UNSPECIFIED
)) {
2852 if (paramval
& IW_AUTH_KEY_MGMT_PSK
)
2853 val
= WPA2_AUTH_PSK
;
2855 val
= WPA2_AUTH_UNSPECIFIED
;
2858 WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __func__
,
2860 error
= dev_wlc_intvar_set(dev
, "wpa_auth", val
);
2865 case IW_AUTH_TKIP_COUNTERMEASURES
:
2866 dev_wlc_bufvar_set(dev
, "tkip_countermeasures",
2867 (char *)¶mval
, 1);
2870 case IW_AUTH_80211_AUTH_ALG
:
2871 WL_INFORM(("Setting the D11auth %d\n", paramval
));
2872 if (paramval
== IW_AUTH_ALG_OPEN_SYSTEM
)
2874 else if (paramval
== IW_AUTH_ALG_SHARED_KEY
)
2876 else if (paramval
==
2877 (IW_AUTH_ALG_OPEN_SYSTEM
| IW_AUTH_ALG_SHARED_KEY
))
2882 error
= dev_wlc_intvar_set(dev
, "auth", val
);
2888 case IW_AUTH_WPA_ENABLED
:
2889 if (paramval
== 0) {
2892 error
= dev_wlc_intvar_get(dev
, "wsec", &val
);
2895 if (val
& (TKIP_ENABLED
| AES_ENABLED
)) {
2896 val
&= ~(TKIP_ENABLED
| AES_ENABLED
);
2897 dev_wlc_intvar_set(dev
, "wsec", val
);
2900 WL_INFORM(("%s: %d: setting wpa_auth to %d\n",
2901 __func__
, __LINE__
, val
));
2902 dev_wlc_intvar_set(dev
, "wpa_auth", 0);
2907 case IW_AUTH_DROP_UNENCRYPTED
:
2908 dev_wlc_bufvar_set(dev
, "wsec_restrict", (char *)¶mval
, 1);
2911 case IW_AUTH_RX_UNENCRYPTED_EAPOL
:
2912 dev_wlc_bufvar_set(dev
, "rx_unencrypted_eapol",
2913 (char *)¶mval
, 1);
2916 #if WIRELESS_EXT > 17
2917 case IW_AUTH_ROAMING_CONTROL
:
2918 WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__
));
2920 case IW_AUTH_PRIVACY_INVOKED
:
2924 if (paramval
== 0) {
2925 iw
->privacy_invoked
= FALSE
;
2926 error
= dev_wlc_intvar_set(dev
,
2927 "is_WPS_enrollee", FALSE
);
2929 WL_WSEC(("Failed to clear iovar "
2930 "is_WPS_enrollee\n"));
2934 iw
->privacy_invoked
= TRUE
;
2935 error
= dev_wlc_intvar_get(dev
, "wsec", &wsec
);
2939 if (!(IW_WSEC_ENABLED(wsec
))) {
2940 error
= dev_wlc_intvar_set(dev
,
2944 WL_WSEC(("Failed to set iovar "
2945 "is_WPS_enrollee\n"));
2949 error
= dev_wlc_intvar_set(dev
,
2953 WL_WSEC(("Failed to clear "
2954 "is_WPS_enrollee\n"));
2961 #endif /* WIRELESS_EXT > 17 */
2969 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
2971 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK))
2975 wl_iw_get_wpaauth(struct net_device
*dev
,
2976 struct iw_request_info
*info
,
2977 struct iw_param
*vwrq
, char *extra
)
2983 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
2985 WL_TRACE(("%s: SIOCGIWAUTH\n", dev
->name
));
2987 paramid
= vwrq
->flags
& IW_AUTH_INDEX
;
2990 case IW_AUTH_WPA_VERSION
:
2991 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
2994 if (val
& (WPA_AUTH_NONE
| WPA_AUTH_DISABLED
))
2995 paramval
= IW_AUTH_WPA_VERSION_DISABLED
;
2996 else if (val
& (WPA_AUTH_PSK
| WPA_AUTH_UNSPECIFIED
))
2997 paramval
= IW_AUTH_WPA_VERSION_WPA
;
2999 else if (val
& (WPA2_AUTH_PSK
| WPA2_AUTH_UNSPECIFIED
))
3000 paramval
= IW_AUTH_WPA_VERSION_WPA2
;
3003 case IW_AUTH_CIPHER_PAIRWISE
:
3004 case IW_AUTH_CIPHER_GROUP
:
3005 if (paramid
== IW_AUTH_CIPHER_PAIRWISE
)
3012 if (val
& WEP_ENABLED
)
3014 (IW_AUTH_CIPHER_WEP40
|
3015 IW_AUTH_CIPHER_WEP104
);
3016 if (val
& TKIP_ENABLED
)
3017 paramval
|= (IW_AUTH_CIPHER_TKIP
);
3018 if (val
& AES_ENABLED
)
3019 paramval
|= (IW_AUTH_CIPHER_CCMP
);
3021 paramval
= IW_AUTH_CIPHER_NONE
;
3023 case IW_AUTH_KEY_MGMT
:
3024 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
3028 paramval
= IW_AUTH_KEY_MGMT_PSK
;
3030 paramval
= IW_AUTH_KEY_MGMT_802_1X
;
3033 case IW_AUTH_TKIP_COUNTERMEASURES
:
3034 dev_wlc_bufvar_get(dev
, "tkip_countermeasures",
3035 (char *)¶mval
, 1);
3038 case IW_AUTH_DROP_UNENCRYPTED
:
3039 dev_wlc_bufvar_get(dev
, "wsec_restrict", (char *)¶mval
, 1);
3042 case IW_AUTH_RX_UNENCRYPTED_EAPOL
:
3043 dev_wlc_bufvar_get(dev
, "rx_unencrypted_eapol",
3044 (char *)¶mval
, 1);
3047 case IW_AUTH_80211_AUTH_ALG
:
3048 error
= dev_wlc_intvar_get(dev
, "auth", &val
);
3052 paramval
= IW_AUTH_ALG_OPEN_SYSTEM
;
3054 paramval
= IW_AUTH_ALG_SHARED_KEY
;
3056 case IW_AUTH_WPA_ENABLED
:
3057 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
3065 #if WIRELESS_EXT > 17
3066 case IW_AUTH_ROAMING_CONTROL
:
3067 WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__
));
3069 case IW_AUTH_PRIVACY_INVOKED
:
3070 paramval
= iw
->privacy_invoked
;
3075 vwrq
->value
= paramval
;
3078 #endif /* WIRELESS_EXT > 17 */
3080 static const iw_handler wl_iw_handler
[] = {
3081 (iw_handler
) wl_iw_config_commit
,
3082 (iw_handler
) wl_iw_get_name
,
3085 (iw_handler
) wl_iw_set_freq
,
3086 (iw_handler
) wl_iw_get_freq
,
3087 (iw_handler
) wl_iw_set_mode
,
3088 (iw_handler
) wl_iw_get_mode
,
3092 (iw_handler
) wl_iw_get_range
,
3097 (iw_handler
) wl_iw_set_spy
,
3098 (iw_handler
) wl_iw_get_spy
,
3101 (iw_handler
) wl_iw_set_wap
,
3102 (iw_handler
) wl_iw_get_wap
,
3103 #if WIRELESS_EXT > 17
3104 (iw_handler
) wl_iw_mlme
,
3108 #if defined(WL_IW_USE_ISCAN)
3109 (iw_handler
) wl_iw_iscan_get_aplist
,
3111 (iw_handler
) wl_iw_get_aplist
,
3113 #if WIRELESS_EXT > 13
3114 #if defined(WL_IW_USE_ISCAN)
3115 (iw_handler
) wl_iw_iscan_set_scan
,
3116 (iw_handler
) wl_iw_iscan_get_scan
,
3118 (iw_handler
) wl_iw_set_scan
,
3119 (iw_handler
) wl_iw_get_scan
,
3124 #endif /* WIRELESS_EXT > 13 */
3125 (iw_handler
) wl_iw_set_essid
,
3126 (iw_handler
) wl_iw_get_essid
,
3127 (iw_handler
) wl_iw_set_nick
,
3128 (iw_handler
) wl_iw_get_nick
,
3131 (iw_handler
) wl_iw_set_rate
,
3132 (iw_handler
) wl_iw_get_rate
,
3133 (iw_handler
) wl_iw_set_rts
,
3134 (iw_handler
) wl_iw_get_rts
,
3135 (iw_handler
) wl_iw_set_frag
,
3136 (iw_handler
) wl_iw_get_frag
,
3137 (iw_handler
) wl_iw_set_txpow
,
3138 (iw_handler
) wl_iw_get_txpow
,
3139 #if WIRELESS_EXT > 10
3140 (iw_handler
) wl_iw_set_retry
,
3141 (iw_handler
) wl_iw_get_retry
,
3143 (iw_handler
) wl_iw_set_encode
,
3144 (iw_handler
) wl_iw_get_encode
,
3145 (iw_handler
) wl_iw_set_power
,
3146 (iw_handler
) wl_iw_get_power
,
3147 #if WIRELESS_EXT > 17
3150 (iw_handler
) wl_iw_set_wpaie
,
3151 (iw_handler
) wl_iw_get_wpaie
,
3152 (iw_handler
) wl_iw_set_wpaauth
,
3153 (iw_handler
) wl_iw_get_wpaauth
,
3154 (iw_handler
) wl_iw_set_encodeext
,
3155 (iw_handler
) wl_iw_get_encodeext
,
3157 (iw_handler
) wl_iw_set_pmksa
,
3159 #endif /* WIRELESS_EXT > 17 */
3162 #if WIRELESS_EXT > 12
3164 const struct iw_handler_def wl_iw_handler_def
= {
3165 .num_standard
= ARRAYSIZE(wl_iw_handler
),
3166 .standard
= (iw_handler
*) wl_iw_handler
,
3168 .num_private_args
= 0,
3172 #if WIRELESS_EXT >= 19
3173 .get_wireless_stats
= dhd_get_wireless_stats
,
3176 #endif /* WIRELESS_EXT > 12 */
3178 int wl_iw_ioctl(struct net_device
*dev
, struct ifreq
*rq
, int cmd
)
3180 struct iwreq
*wrq
= (struct iwreq
*)rq
;
3181 struct iw_request_info info
;
3184 int token_size
= 1, max_tokens
= 0, ret
= 0;
3186 WL_TRACE(("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
3188 if (cmd
< SIOCIWFIRST
||
3189 IW_IOCTL_IDX(cmd
) >= ARRAYSIZE(wl_iw_handler
)) {
3190 WL_ERROR(("%s: error in cmd=%x : out of range\n", __func__
,
3195 handler
= wl_iw_handler
[IW_IOCTL_IDX(cmd
)];
3197 WL_ERROR(("%s: error in cmd=%x : not supported\n",
3208 max_tokens
= IW_ESSID_MAX_SIZE
+ 1;
3213 #if WIRELESS_EXT > 17
3214 case SIOCSIWENCODEEXT
:
3215 case SIOCGIWENCODEEXT
:
3217 max_tokens
= wrq
->u
.data
.length
;
3221 max_tokens
= sizeof(struct iw_range
) + 500;
3226 sizeof(struct sockaddr
) + sizeof(struct iw_quality
);
3227 max_tokens
= IW_MAX_AP
;
3230 #if WIRELESS_EXT > 13
3232 #if defined(WL_IW_USE_ISCAN)
3234 max_tokens
= wrq
->u
.data
.length
;
3237 max_tokens
= IW_SCAN_MAX_DATA
;
3239 #endif /* WIRELESS_EXT > 13 */
3242 token_size
= sizeof(struct sockaddr
);
3243 max_tokens
= IW_MAX_SPY
;
3248 sizeof(struct sockaddr
) + sizeof(struct iw_quality
);
3249 max_tokens
= IW_MAX_SPY
;
3252 #if WIRELESS_EXT > 17
3257 max_tokens
= wrq
->u
.data
.length
;
3261 if (max_tokens
&& wrq
->u
.data
.pointer
) {
3262 if (wrq
->u
.data
.length
> max_tokens
) {
3263 WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d "
3264 "> max_tokens=%d\n",
3265 __func__
, cmd
, wrq
->u
.data
.length
, max_tokens
));
3268 extra
= kmalloc(max_tokens
* token_size
, GFP_KERNEL
);
3273 (extra
, wrq
->u
.data
.pointer
,
3274 wrq
->u
.data
.length
* token_size
)) {
3283 ret
= handler(dev
, &info
, &wrq
->u
, extra
);
3287 (wrq
->u
.data
.pointer
, extra
,
3288 wrq
->u
.data
.length
* token_size
)) {
3300 wl_iw_conn_status_str(uint32 event_type
, uint32 status
, uint32 reason
,
3301 char *stringBuf
, uint buflen
)
3303 typedef struct conn_fail_event_map_t
{
3307 const char *outName
;
3308 const char *outCause
;
3309 } conn_fail_event_map_t
;
3311 #define WL_IW_DONT_CARE 9999
3312 const conn_fail_event_map_t event_map
[] = {
3313 {WLC_E_SET_SSID
, WLC_E_STATUS_SUCCESS
, WL_IW_DONT_CARE
,
3315 {WLC_E_SET_SSID
, WLC_E_STATUS_NO_NETWORKS
, WL_IW_DONT_CARE
,
3316 "Conn", "NoNetworks"},
3317 {WLC_E_SET_SSID
, WLC_E_STATUS_FAIL
, WL_IW_DONT_CARE
,
3318 "Conn", "ConfigMismatch"},
3319 {WLC_E_PRUNE
, WL_IW_DONT_CARE
, WLC_E_PRUNE_ENCR_MISMATCH
,
3320 "Conn", "EncrypMismatch"},
3321 {WLC_E_PRUNE
, WL_IW_DONT_CARE
, WLC_E_RSN_MISMATCH
,
3322 "Conn", "RsnMismatch"},
3323 {WLC_E_AUTH
, WLC_E_STATUS_TIMEOUT
, WL_IW_DONT_CARE
,
3324 "Conn", "AuthTimeout"},
3325 {WLC_E_AUTH
, WLC_E_STATUS_FAIL
, WL_IW_DONT_CARE
,
3326 "Conn", "AuthFail"},
3327 {WLC_E_AUTH
, WLC_E_STATUS_NO_ACK
, WL_IW_DONT_CARE
,
3328 "Conn", "AuthNoAck"},
3329 {WLC_E_REASSOC
, WLC_E_STATUS_FAIL
, WL_IW_DONT_CARE
,
3330 "Conn", "ReassocFail"},
3331 {WLC_E_REASSOC
, WLC_E_STATUS_TIMEOUT
, WL_IW_DONT_CARE
,
3332 "Conn", "ReassocTimeout"},
3333 {WLC_E_REASSOC
, WLC_E_STATUS_ABORT
, WL_IW_DONT_CARE
,
3334 "Conn", "ReassocAbort"},
3335 {WLC_E_PSK_SUP
, WLC_SUP_KEYED
, WL_IW_DONT_CARE
,
3336 "Sup", "ConnSuccess"},
3337 {WLC_E_PSK_SUP
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3338 "Sup", "WpaHandshakeFail"},
3339 {WLC_E_DEAUTH_IND
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3341 {WLC_E_DISASSOC_IND
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3342 "Conn", "DisassocInd"},
3343 {WLC_E_DISASSOC
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3347 const char *name
= "";
3348 const char *cause
= NULL
;
3351 for (i
= 0; i
< sizeof(event_map
) / sizeof(event_map
[0]); i
++) {
3352 const conn_fail_event_map_t
*row
= &event_map
[i
];
3353 if (row
->inEvent
== event_type
&&
3354 (row
->inStatus
== status
3355 || row
->inStatus
== WL_IW_DONT_CARE
)
3356 && (row
->inReason
== reason
3357 || row
->inReason
== WL_IW_DONT_CARE
)) {
3358 name
= row
->outName
;
3359 cause
= row
->outCause
;
3365 memset(stringBuf
, 0, buflen
);
3366 snprintf(stringBuf
, buflen
, "%s %s %02d %02d",
3367 name
, cause
, status
, reason
);
3368 WL_INFORM(("Connection status: %s\n", stringBuf
));
3375 #if WIRELESS_EXT > 14
3378 wl_iw_check_conn_fail(wl_event_msg_t
*e
, char *stringBuf
, uint buflen
)
3380 uint32 event
= ntoh32(e
->event_type
);
3381 uint32 status
= ntoh32(e
->status
);
3382 uint32 reason
= ntoh32(e
->reason
);
3384 if (wl_iw_conn_status_str(event
, status
, reason
, stringBuf
, buflen
)) {
3391 #ifndef IW_CUSTOM_MAX
3392 #define IW_CUSTOM_MAX 256
3395 void wl_iw_event(struct net_device
*dev
, wl_event_msg_t
*e
, void *data
)
3397 #if WIRELESS_EXT > 13
3398 union iwreq_data wrqu
;
3399 char extra
[IW_CUSTOM_MAX
+ 1];
3401 uint32 event_type
= ntoh32(e
->event_type
);
3402 uint16 flags
= ntoh16(e
->flags
);
3403 uint32 datalen
= ntoh32(e
->datalen
);
3404 uint32 status
= ntoh32(e
->status
);
3407 memset(&wrqu
, 0, sizeof(wrqu
));
3408 memset(extra
, 0, sizeof(extra
));
3412 WL_ERROR(("%s: dev is null\n", __func__
));
3416 iw
= *(wl_iw_t
**) netdev_priv(dev
);
3418 WL_TRACE(("%s: dev=%s event=%d\n", __func__
, dev
->name
, event_type
));
3420 switch (event_type
) {
3423 memcpy(wrqu
.addr
.sa_data
, &e
->addr
, ETHER_ADDR_LEN
);
3424 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3426 #if WIRELESS_EXT > 14
3428 case WLC_E_ASSOC_IND
:
3429 case WLC_E_REASSOC_IND
:
3430 memcpy(wrqu
.addr
.sa_data
, &e
->addr
, ETHER_ADDR_LEN
);
3431 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3432 cmd
= IWEVREGISTERED
;
3434 case WLC_E_DEAUTH_IND
:
3435 case WLC_E_DISASSOC_IND
:
3437 bzero(wrqu
.addr
.sa_data
, ETHER_ADDR_LEN
);
3438 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3439 bzero(&extra
, ETHER_ADDR_LEN
);
3442 case WLC_E_NDIS_LINK
:
3444 if (!(flags
& WLC_EVENT_MSG_LINK
)) {
3445 bzero(wrqu
.addr
.sa_data
, ETHER_ADDR_LEN
);
3446 bzero(&extra
, ETHER_ADDR_LEN
);
3447 WAKE_LOCK_TIMEOUT(iw
->pub
, WAKE_LOCK_LINK_DOWN_TMOUT
,
3450 memcpy(wrqu
.addr
.sa_data
, &e
->addr
, ETHER_ADDR_LEN
);
3451 WL_TRACE(("Link UP\n"));
3454 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3456 case WLC_E_ACTION_FRAME
:
3458 if (datalen
+ 1 <= sizeof(extra
)) {
3459 wrqu
.data
.length
= datalen
+ 1;
3460 extra
[0] = WLC_E_ACTION_FRAME
;
3461 memcpy(&extra
[1], data
, datalen
);
3462 WL_TRACE(("WLC_E_ACTION_FRAME len %d \n",
3467 case WLC_E_ACTION_FRAME_COMPLETE
:
3469 memcpy(&toto
, data
, 4);
3470 if (sizeof(status
) + 1 <= sizeof(extra
)) {
3471 wrqu
.data
.length
= sizeof(status
) + 1;
3472 extra
[0] = WLC_E_ACTION_FRAME_COMPLETE
;
3473 memcpy(&extra
[1], &status
, sizeof(status
));
3474 printf("wl_iw_event status %d PacketId %d\n", status
,
3476 printf("WLC_E_ACTION_FRAME_COMPLETE len %d\n",
3480 #endif /* WIRELESS_EXT > 14 */
3481 #if WIRELESS_EXT > 17
3482 case WLC_E_MIC_ERROR
:
3484 struct iw_michaelmicfailure
*micerrevt
=
3485 (struct iw_michaelmicfailure
*)&extra
;
3486 cmd
= IWEVMICHAELMICFAILURE
;
3487 wrqu
.data
.length
= sizeof(struct iw_michaelmicfailure
);
3488 if (flags
& WLC_EVENT_MSG_GROUP
)
3489 micerrevt
->flags
|= IW_MICFAILURE_GROUP
;
3491 micerrevt
->flags
|= IW_MICFAILURE_PAIRWISE
;
3492 memcpy(micerrevt
->src_addr
.sa_data
, &e
->addr
,
3494 micerrevt
->src_addr
.sa_family
= ARPHRD_ETHER
;
3499 case WLC_E_PMKID_CACHE
:
3502 struct iw_pmkid_cand
*iwpmkidcand
=
3503 (struct iw_pmkid_cand
*)&extra
;
3504 pmkid_cand_list_t
*pmkcandlist
;
3505 pmkid_cand_t
*pmkidcand
;
3508 cmd
= IWEVPMKIDCAND
;
3512 pmkcandlist
->npmkid_cand
);
3514 wrqu
.data
.length
= sizeof(struct iw_pmkid_cand
);
3515 pmkidcand
= pmkcandlist
->pmkid_cand
;
3518 sizeof(struct iw_pmkid_cand
));
3519 if (pmkidcand
->preauth
)
3520 iwpmkidcand
->flags
|=
3521 IW_PMKID_CAND_PREAUTH
;
3522 bcopy(&pmkidcand
->BSSID
,
3523 &iwpmkidcand
->bssid
.sa_data
,
3526 wireless_send_event(dev
, cmd
, &wrqu
,
3535 #endif /* BCMWPA2 */
3536 #endif /* WIRELESS_EXT > 17 */
3538 case WLC_E_SCAN_COMPLETE
:
3539 #if defined(WL_IW_USE_ISCAN)
3540 if ((g_iscan
) && (g_iscan
->sysioc_pid
> 0) &&
3541 (g_iscan
->iscan_state
!= ISCAN_STATE_IDLE
)) {
3542 up(&g_iscan
->sysioc_sem
);
3545 wrqu
.data
.length
= strlen(extra
);
3546 WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific "
3547 "scan %d\n", g_iscan
->iscan_state
));
3551 wrqu
.data
.length
= strlen(extra
);
3552 WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
3556 case WLC_E_PFN_NET_FOUND
:
3559 ssid
= (wlc_ssid_t
*) data
;
3560 WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : "
3561 "find %s len=%d\n", __func__
, PNO_EVENT_UP
,
3562 ssid
->SSID
, ssid
->SSID_len
));
3563 WAKE_LOCK_TIMEOUT(iw
->pub
, WAKE_LOCK_PNO_FIND_TMOUT
,
3566 memset(&wrqu
, 0, sizeof(wrqu
));
3567 strcpy(extra
, PNO_EVENT_UP
);
3568 wrqu
.data
.length
= strlen(extra
);
3573 WL_TRACE(("Unknown Event %d: ignoring\n", event_type
));
3578 if (cmd
== SIOCGIWSCAN
)
3579 wireless_send_event(dev
, cmd
, &wrqu
, NULL
);
3581 wireless_send_event(dev
, cmd
, &wrqu
, extra
);
3585 #if WIRELESS_EXT > 14
3586 memset(extra
, 0, sizeof(extra
));
3587 if (wl_iw_check_conn_fail(e
, extra
, sizeof(extra
))) {
3589 wrqu
.data
.length
= strlen(extra
);
3591 wireless_send_event(dev
, cmd
, &wrqu
, extra
);
3594 #endif /* WIRELESS_EXT > 14 */
3595 #endif /* WIRELESS_EXT > 13 */
3599 wl_iw_get_wireless_stats(struct net_device
*dev
, struct iw_statistics
*wstats
)
3608 res
= dev_wlc_ioctl(dev
, WLC_GET_PHY_NOISE
, &phy_noise
,
3613 phy_noise
= dtoh32(phy_noise
);
3614 WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise
));
3616 bzero(&scb_val
, sizeof(scb_val_t
));
3617 res
= dev_wlc_ioctl(dev
, WLC_GET_RSSI
, &scb_val
, sizeof(scb_val_t
));
3621 rssi
= dtoh32(scb_val
.val
);
3622 WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi
));
3623 if (rssi
<= WL_IW_RSSI_NO_SIGNAL
)
3624 wstats
->qual
.qual
= 0;
3625 else if (rssi
<= WL_IW_RSSI_VERY_LOW
)
3626 wstats
->qual
.qual
= 1;
3627 else if (rssi
<= WL_IW_RSSI_LOW
)
3628 wstats
->qual
.qual
= 2;
3629 else if (rssi
<= WL_IW_RSSI_GOOD
)
3630 wstats
->qual
.qual
= 3;
3631 else if (rssi
<= WL_IW_RSSI_VERY_GOOD
)
3632 wstats
->qual
.qual
= 4;
3634 wstats
->qual
.qual
= 5;
3636 wstats
->qual
.level
= 0x100 + rssi
;
3637 wstats
->qual
.noise
= 0x100 + phy_noise
;
3638 #if WIRELESS_EXT > 18
3639 wstats
->qual
.updated
|= (IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
);
3641 wstats
->qual
.updated
|= 7;
3644 #if WIRELESS_EXT > 11
3645 WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n",
3646 (int)sizeof(wl_cnt_t
)));
3648 memset(&cnt
, 0, sizeof(wl_cnt_t
));
3650 dev_wlc_bufvar_get(dev
, "counters", (char *)&cnt
, sizeof(wl_cnt_t
));
3652 WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n",
3657 cnt
.version
= dtoh16(cnt
.version
);
3658 if (cnt
.version
!= WL_CNT_T_VERSION
) {
3659 WL_TRACE(("\tIncorrect version of counters struct: expected "
3661 WL_CNT_T_VERSION
, cnt
.version
));
3665 wstats
->discard
.nwid
= 0;
3666 wstats
->discard
.code
= dtoh32(cnt
.rxundec
);
3667 wstats
->discard
.fragment
= dtoh32(cnt
.rxfragerr
);
3668 wstats
->discard
.retries
= dtoh32(cnt
.txfail
);
3669 wstats
->discard
.misc
= dtoh32(cnt
.rxrunt
) + dtoh32(cnt
.rxgiant
);
3670 wstats
->miss
.beacon
= 0;
3672 WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
3673 dtoh32(cnt
.txframe
), dtoh32(cnt
.txbyte
)));
3674 WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n",
3675 dtoh32(cnt
.rxfrmtoolong
)));
3676 WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n",
3677 dtoh32(cnt
.rxbadplcp
)));
3678 WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n",
3679 dtoh32(cnt
.rxundec
)));
3680 WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n",
3681 dtoh32(cnt
.rxfragerr
)));
3682 WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n",
3683 dtoh32(cnt
.txfail
)));
3684 WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n",
3685 dtoh32(cnt
.rxrunt
)));
3686 WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n",
3687 dtoh32(cnt
.rxgiant
)));
3688 #endif /* WIRELESS_EXT > 11 */
3694 int wl_iw_attach(struct net_device
*dev
, void *dhdp
)
3698 #if defined(WL_IW_USE_ISCAN)
3699 iscan_info_t
*iscan
= NULL
;
3704 memset(&g_wl_iw_params
, 0, sizeof(wl_iw_extra_params_t
));
3708 (WL_SCAN_PARAMS_FIXED_SIZE
+ OFFSETOF(wl_iscan_params_t
, params
)) +
3709 (WL_NUMCHANNELS
* sizeof(uint16
)) +
3710 WL_SCAN_PARAMS_SSID_MAX
* sizeof(wlc_ssid_t
);
3713 (WL_SCAN_PARAMS_FIXED_SIZE
+ OFFSETOF(wl_iscan_params_t
, params
));
3715 iscan
= kmalloc(sizeof(iscan_info_t
), GFP_KERNEL
);
3719 memset(iscan
, 0, sizeof(iscan_info_t
));
3721 iscan
->iscan_ex_params_p
=
3722 (wl_iscan_params_t
*) kmalloc(params_size
, GFP_KERNEL
);
3723 if (!iscan
->iscan_ex_params_p
)
3725 iscan
->iscan_ex_param_size
= params_size
;
3726 iscan
->sysioc_pid
= -1;
3730 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
3732 iscan
->timer_ms
= 3000;
3733 init_timer(&iscan
->timer
);
3734 iscan
->timer
.data
= (ulong
) iscan
;
3735 iscan
->timer
.function
= wl_iw_timerfunc
;
3737 sema_init(&iscan
->sysioc_sem
, 0);
3738 init_completion(&iscan
->sysioc_exited
);
3739 iscan
->sysioc_pid
= kernel_thread(_iscan_sysioc_thread
, iscan
, 0);
3740 if (iscan
->sysioc_pid
< 0)
3742 #endif /* defined(WL_IW_USE_ISCAN) */
3744 iw
= *(wl_iw_t
**) netdev_priv(dev
);
3745 iw
->pub
= (dhd_pub_t
*) dhdp
;
3746 MUTEX_LOCK_INIT(iw
->pub
);
3747 MUTEX_LOCK_WL_SCAN_SET_INIT();
3750 MUTEX_LOCK_SOFTAP_SET_INIT(iw
->pub
);
3754 g_scan
= (void *)kmalloc(G_SCAN_RESULTS
, GFP_KERNEL
);
3758 memset(g_scan
, 0, G_SCAN_RESULTS
);
3759 g_scan_specified_ssid
= 0;
3764 void wl_iw_detach(void)
3766 #if defined(WL_IW_USE_ISCAN)
3768 iscan_info_t
*iscan
= g_iscan
;
3772 if (iscan
->sysioc_pid
>= 0) {
3773 KILL_PROC(iscan
->sysioc_pid
, SIGTERM
);
3774 wait_for_completion(&iscan
->sysioc_exited
);
3776 MUTEX_LOCK_WL_SCAN_SET();
3777 while (iscan
->list_hdr
) {
3778 buf
= iscan
->list_hdr
->next
;
3779 kfree(iscan
->list_hdr
);
3780 iscan
->list_hdr
= buf
;
3782 MUTEX_UNLOCK_WL_SCAN_SET();
3783 kfree(iscan
->iscan_ex_params_p
);
3786 #endif /* WL_IW_USE_ISCAN */