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)
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) \
113 allow_signal(SIGKILL); \
114 allow_signal(SIGTERM); \
117 #if defined(WL_IW_USE_ISCAN)
118 #define ISCAN_STATE_IDLE 0
119 #define ISCAN_STATE_SCANING 1
121 #define WLC_IW_ISCAN_MAXLEN 2048
122 typedef struct iscan_buf
{
123 struct iscan_buf
*next
;
124 char iscan_buf
[WLC_IW_ISCAN_MAXLEN
];
127 typedef struct iscan_info
{
128 struct net_device
*dev
;
129 struct timer_list timer
;
133 iscan_buf_t
*list_hdr
;
134 iscan_buf_t
*list_cur
;
137 struct semaphore sysioc_sem
;
138 struct completion sysioc_exited
;
141 char ioctlbuf
[WLC_IOCTL_MEDLEN
];
143 char ioctlbuf
[WLC_IOCTL_SMLEN
];
145 wl_iscan_params_t
*iscan_ex_params_p
;
146 int iscan_ex_param_size
;
148 iscan_info_t
*g_iscan
;
149 static void wl_iw_timerfunc(unsigned long data
);
150 static void wl_iw_set_event_mask(struct net_device
*dev
);
151 static int wl_iw_iscan(iscan_info_t
*iscan
, wlc_ssid_t
*ssid
, uint16 action
);
152 #endif /* defined(WL_IW_USE_ISCAN) */
155 wl_iw_set_scan(struct net_device
*dev
,
156 struct iw_request_info
*info
,
157 union iwreq_data
*wrqu
, char *extra
);
160 wl_iw_get_scan(struct net_device
*dev
,
161 struct iw_request_info
*info
,
162 struct iw_point
*dwrq
, char *extra
);
165 wl_iw_get_scan_prep(wl_scan_results_t
*list
,
166 struct iw_request_info
*info
, char *extra
, short max_size
);
168 static void swap_key_from_BE(wl_wsec_key_t
*key
)
170 key
->index
= htod32(key
->index
);
171 key
->len
= htod32(key
->len
);
172 key
->algo
= htod32(key
->algo
);
173 key
->flags
= htod32(key
->flags
);
174 key
->rxiv
.hi
= htod32(key
->rxiv
.hi
);
175 key
->rxiv
.lo
= htod16(key
->rxiv
.lo
);
176 key
->iv_initialized
= htod32(key
->iv_initialized
);
179 static void swap_key_to_BE(wl_wsec_key_t
*key
)
181 key
->index
= dtoh32(key
->index
);
182 key
->len
= dtoh32(key
->len
);
183 key
->algo
= dtoh32(key
->algo
);
184 key
->flags
= dtoh32(key
->flags
);
185 key
->rxiv
.hi
= dtoh32(key
->rxiv
.hi
);
186 key
->rxiv
.lo
= dtoh16(key
->rxiv
.lo
);
187 key
->iv_initialized
= dtoh32(key
->iv_initialized
);
190 static int dev_wlc_ioctl(struct net_device
*dev
, int cmd
, void *arg
, int len
)
198 WL_ERROR(("%s: dev is null\n", __func__
));
202 WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, "
203 "len:%d ,\n", __func__
, current
->pid
, cmd
, arg
, len
));
205 if (g_onoff
== G_WLAN_SET_ON
) {
206 memset(&ioc
, 0, sizeof(ioc
));
211 strcpy(ifr
.ifr_name
, dev
->name
);
212 ifr
.ifr_data
= (caddr_t
)&ioc
;
216 WL_ERROR(("%s: Error dev_open: %d\n", __func__
, ret
));
222 ret
= dev
->netdev_ops
->ndo_do_ioctl(dev
, &ifr
, SIOCDEVPRIVATE
);
225 WL_TRACE(("%s: call after driver stop : ignored\n", __func__
));
230 static int dev_wlc_intvar_set(struct net_device
*dev
, char *name
, int val
)
232 char buf
[WLC_IOCTL_SMLEN
];
236 len
= bcm_mkiovar(name
, (char *)(&val
), sizeof(val
), buf
, sizeof(buf
));
239 return dev_wlc_ioctl(dev
, WLC_SET_VAR
, buf
, len
);
242 #if defined(WL_IW_USE_ISCAN)
244 dev_iw_iovar_setbuf(struct net_device
*dev
,
246 void *param
, int paramlen
, void *bufptr
, int buflen
)
250 iolen
= bcm_mkiovar(iovar
, param
, paramlen
, bufptr
, buflen
);
256 return dev_wlc_ioctl(dev
, WLC_SET_VAR
, bufptr
, iolen
);
260 dev_iw_iovar_getbuf(struct net_device
*dev
,
262 void *param
, int paramlen
, void *bufptr
, int buflen
)
266 iolen
= bcm_mkiovar(iovar
, param
, paramlen
, bufptr
, buflen
);
269 return dev_wlc_ioctl(dev
, WLC_GET_VAR
, bufptr
, buflen
);
271 #endif /* defined(WL_IW_USE_ISCAN) */
273 #if WIRELESS_EXT > 17
275 dev_wlc_bufvar_set(struct net_device
*dev
, char *name
, char *buf
, int len
)
277 static char ioctlbuf
[MAX_WLIW_IOCTL_LEN
];
280 buflen
= bcm_mkiovar(name
, buf
, len
, ioctlbuf
, sizeof(ioctlbuf
));
283 return dev_wlc_ioctl(dev
, WLC_SET_VAR
, ioctlbuf
, buflen
);
285 #endif /* WIRELESS_EXT > 17 */
288 dev_wlc_bufvar_get(struct net_device
*dev
, char *name
, char *buf
, int buflen
)
290 static char ioctlbuf
[MAX_WLIW_IOCTL_LEN
];
294 len
= bcm_mkiovar(name
, NULL
, 0, ioctlbuf
, sizeof(ioctlbuf
));
297 dev_wlc_ioctl(dev
, WLC_GET_VAR
, (void *)ioctlbuf
,
300 bcopy(ioctlbuf
, buf
, buflen
);
305 static int dev_wlc_intvar_get(struct net_device
*dev
, char *name
, int *retval
)
308 char buf
[WLC_IOCTL_SMLEN
];
317 bcm_mkiovar(name
, (char *)(&data_null
), 0, (char *)(&var
),
320 error
= dev_wlc_ioctl(dev
, WLC_GET_VAR
, (void *)&var
, len
);
322 *retval
= dtoh32(var
.val
);
327 #if WIRELESS_EXT < 13
328 struct iw_request_info
{
333 typedef int (*iw_handler
) (struct net_device
*dev
,
334 struct iw_request_info
*info
,
335 void *wrqu
, char *extra
);
339 wl_iw_config_commit(struct net_device
*dev
,
340 struct iw_request_info
*info
, void *zwrq
, char *extra
)
344 struct sockaddr bssid
;
346 WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev
->name
));
348 error
= dev_wlc_ioctl(dev
, WLC_GET_SSID
, &ssid
, sizeof(ssid
));
352 ssid
.SSID_len
= dtoh32(ssid
.SSID_len
);
357 bzero(&bssid
, sizeof(struct sockaddr
));
358 error
= dev_wlc_ioctl(dev
, WLC_REASSOC
, &bssid
, ETHER_ADDR_LEN
);
360 WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __func__
,
369 wl_iw_get_name(struct net_device
*dev
,
370 struct iw_request_info
*info
, char *cwrq
, char *extra
)
372 WL_TRACE(("%s: SIOCGIWNAME\n", dev
->name
));
374 strcpy(cwrq
, "IEEE 802.11-DS");
380 wl_iw_set_freq(struct net_device
*dev
,
381 struct iw_request_info
*info
, struct iw_freq
*fwrq
, char *extra
)
386 WL_TRACE(("\n %s %s: SIOCSIWFREQ\n", __func__
, dev
->name
));
388 if (fwrq
->e
== 0 && fwrq
->m
< MAXCHANNEL
) {
395 } else if (fwrq
->e
< 6) {
396 while (fwrq
->e
++ < 6)
399 if (fwrq
->m
> 4000 && fwrq
->m
< 5000)
400 sf
= WF_CHAN_FACTOR_4_G
;
402 chan
= wf_mhz2channel(fwrq
->m
, sf
);
406 error
= dev_wlc_ioctl(dev
, WLC_SET_CHANNEL
, &chan
, sizeof(chan
));
410 g_wl_iw_params
.target_channel
= chan
;
415 wl_iw_get_freq(struct net_device
*dev
,
416 struct iw_request_info
*info
, struct iw_freq
*fwrq
, char *extra
)
421 WL_TRACE(("%s: SIOCGIWFREQ\n", dev
->name
));
423 error
= dev_wlc_ioctl(dev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
427 fwrq
->m
= dtoh32(ci
.hw_channel
);
433 wl_iw_set_mode(struct net_device
*dev
,
434 struct iw_request_info
*info
, __u32
*uwrq
, char *extra
)
436 int infra
= 0, ap
= 0, error
= 0;
438 WL_TRACE(("%s: SIOCSIWMODE\n", dev
->name
));
453 infra
= htod32(infra
);
456 error
= dev_wlc_ioctl(dev
, WLC_SET_INFRA
, &infra
, sizeof(infra
));
460 error
= dev_wlc_ioctl(dev
, WLC_SET_AP
, &ap
, sizeof(ap
));
468 wl_iw_get_mode(struct net_device
*dev
,
469 struct iw_request_info
*info
, __u32
*uwrq
, char *extra
)
471 int error
, infra
= 0, ap
= 0;
473 WL_TRACE(("%s: SIOCGIWMODE\n", dev
->name
));
475 error
= dev_wlc_ioctl(dev
, WLC_GET_INFRA
, &infra
, sizeof(infra
));
479 error
= dev_wlc_ioctl(dev
, WLC_GET_AP
, &ap
, sizeof(ap
));
483 infra
= dtoh32(infra
);
485 *uwrq
= infra
? ap
? IW_MODE_MASTER
: IW_MODE_INFRA
: IW_MODE_ADHOC
;
491 wl_iw_get_range(struct net_device
*dev
,
492 struct iw_request_info
*info
,
493 struct iw_point
*dwrq
, char *extra
)
495 struct iw_range
*range
= (struct iw_range
*)extra
;
496 wl_uint32_list_t
*list
;
497 wl_rateset_t rateset
;
503 int bw_cap
= 0, sgi_tx
= 0, nmode
= 0;
505 u8 nrate_list2copy
= 0;
506 uint16 nrate_list
[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
507 {14, 29, 43, 58, 87, 116, 130, 144},
508 {27, 54, 81, 108, 162, 216, 243, 270},
509 {30, 60, 90, 120, 180, 240, 270, 300}
512 WL_TRACE(("%s: SIOCGIWRANGE\n", dev
->name
));
517 channels
= kmalloc((MAXCHANNEL
+ 1) * 4, GFP_KERNEL
);
519 WL_ERROR(("Could not alloc channels\n"));
522 list
= (wl_uint32_list_t
*) channels
;
524 dwrq
->length
= sizeof(struct iw_range
);
525 memset(range
, 0, sizeof(range
));
527 range
->min_nwid
= range
->max_nwid
= 0;
529 list
->count
= htod32(MAXCHANNEL
);
530 error
= dev_wlc_ioctl(dev
, WLC_GET_VALID_CHANNELS
, channels
,
531 (MAXCHANNEL
+ 1) * 4);
536 for (i
= 0; i
< dtoh32(list
->count
) && i
< IW_MAX_FREQUENCIES
; i
++) {
537 range
->freq
[i
].i
= dtoh32(list
->element
[i
]);
539 ch
= dtoh32(list
->element
[i
]);
540 if (ch
<= CH_MAX_2G_CHANNEL
)
541 sf
= WF_CHAN_FACTOR_2_4_G
;
543 sf
= WF_CHAN_FACTOR_5_G
;
545 range
->freq
[i
].m
= wf_channel2mhz(ch
, sf
);
546 range
->freq
[i
].e
= 6;
548 range
->num_frequency
= range
->num_channels
= i
;
550 range
->max_qual
.qual
= 5;
551 range
->max_qual
.level
= 0x100 - 200;
552 range
->max_qual
.noise
= 0x100 - 200;
553 range
->sensitivity
= 65535;
555 #if WIRELESS_EXT > 11
556 range
->avg_qual
.qual
= 3;
557 range
->avg_qual
.level
= 0x100 + WL_IW_RSSI_GOOD
;
558 range
->avg_qual
.noise
= 0x100 - 75;
561 error
= dev_wlc_ioctl(dev
, WLC_GET_CURR_RATESET
, &rateset
,
567 rateset
.count
= dtoh32(rateset
.count
);
568 range
->num_bitrates
= rateset
.count
;
569 for (i
= 0; i
< rateset
.count
&& i
< IW_MAX_BITRATES
; i
++)
570 range
->bitrate
[i
] = (rateset
.rates
[i
] & 0x7f) * 500000;
571 dev_wlc_intvar_get(dev
, "nmode", &nmode
);
572 dev_wlc_ioctl(dev
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
574 if (nmode
== 1 && phytype
== WLC_PHY_TYPE_SSN
) {
575 dev_wlc_intvar_get(dev
, "mimo_bw_cap", &bw_cap
);
576 dev_wlc_intvar_get(dev
, "sgi_tx", &sgi_tx
);
577 dev_wlc_ioctl(dev
, WLC_GET_CHANNEL
, &ci
,
578 sizeof(channel_info_t
));
579 ci
.hw_channel
= dtoh32(ci
.hw_channel
);
581 if (bw_cap
== 0 || (bw_cap
== 2 && ci
.hw_channel
<= 14)) {
587 if (bw_cap
== 1 || (bw_cap
== 2 && ci
.hw_channel
>= 36)) {
593 range
->num_bitrates
+= 8;
594 for (k
= 0; i
< range
->num_bitrates
; k
++, i
++) {
596 (nrate_list
[nrate_list2copy
][k
]) * 500000;
600 error
= dev_wlc_ioctl(dev
, WLC_GET_PHYTYPE
, &i
, sizeof(i
));
606 if (i
== WLC_PHY_TYPE_A
)
607 range
->throughput
= 24000000;
609 range
->throughput
= 1500000;
612 range
->max_rts
= 2347;
613 range
->min_frag
= 256;
614 range
->max_frag
= 2346;
616 range
->max_encoding_tokens
= DOT11_MAX_DEFAULT_KEYS
;
617 range
->num_encoding_sizes
= 4;
618 range
->encoding_size
[0] = WEP1_KEY_SIZE
;
619 range
->encoding_size
[1] = WEP128_KEY_SIZE
;
620 #if WIRELESS_EXT > 17
621 range
->encoding_size
[2] = TKIP_KEY_SIZE
;
623 range
->encoding_size
[2] = 0;
625 range
->encoding_size
[3] = AES_KEY_SIZE
;
631 range
->pmp_flags
= 0;
634 range
->num_txpower
= 2;
635 range
->txpower
[0] = 1;
636 range
->txpower
[1] = 255;
637 range
->txpower_capa
= IW_TXPOW_MWATT
;
639 #if WIRELESS_EXT > 10
640 range
->we_version_compiled
= WIRELESS_EXT
;
641 range
->we_version_source
= 19;
643 range
->retry_capa
= IW_RETRY_LIMIT
;
644 range
->retry_flags
= IW_RETRY_LIMIT
;
645 range
->r_time_flags
= 0;
646 range
->min_retry
= 1;
647 range
->max_retry
= 255;
648 range
->min_r_time
= 0;
649 range
->max_r_time
= 0;
652 #if WIRELESS_EXT > 17
653 range
->enc_capa
= IW_ENC_CAPA_WPA
;
654 range
->enc_capa
|= IW_ENC_CAPA_CIPHER_TKIP
;
655 range
->enc_capa
|= IW_ENC_CAPA_CIPHER_CCMP
;
657 range
->enc_capa
|= IW_ENC_CAPA_WPA2
;
660 IW_EVENT_CAPA_SET_KERNEL(range
->event_capa
);
661 IW_EVENT_CAPA_SET(range
->event_capa
, SIOCGIWAP
);
662 IW_EVENT_CAPA_SET(range
->event_capa
, SIOCGIWSCAN
);
663 IW_EVENT_CAPA_SET(range
->event_capa
, IWEVTXDROP
);
664 IW_EVENT_CAPA_SET(range
->event_capa
, IWEVMICHAELMICFAILURE
);
666 IW_EVENT_CAPA_SET(range
->event_capa
, IWEVPMKIDCAND
);
668 #endif /* WIRELESS_EXT > 17 */
675 static int rssi_to_qual(int rssi
)
677 if (rssi
<= WL_IW_RSSI_NO_SIGNAL
)
679 else if (rssi
<= WL_IW_RSSI_VERY_LOW
)
681 else if (rssi
<= WL_IW_RSSI_LOW
)
683 else if (rssi
<= WL_IW_RSSI_GOOD
)
685 else if (rssi
<= WL_IW_RSSI_VERY_GOOD
)
692 wl_iw_set_spy(struct net_device
*dev
,
693 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
695 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
696 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
699 WL_TRACE(("%s: SIOCSIWSPY\n", dev
->name
));
704 iw
->spy_num
= MIN(ARRAYSIZE(iw
->spy_addr
), dwrq
->length
);
705 for (i
= 0; i
< iw
->spy_num
; i
++)
706 memcpy(&iw
->spy_addr
[i
], addr
[i
].sa_data
, ETHER_ADDR_LEN
);
707 memset(iw
->spy_qual
, 0, sizeof(iw
->spy_qual
));
713 wl_iw_get_spy(struct net_device
*dev
,
714 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
716 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
717 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
718 struct iw_quality
*qual
= (struct iw_quality
*)&addr
[iw
->spy_num
];
721 WL_TRACE(("%s: SIOCGIWSPY\n", dev
->name
));
726 dwrq
->length
= iw
->spy_num
;
727 for (i
= 0; i
< iw
->spy_num
; i
++) {
728 memcpy(addr
[i
].sa_data
, &iw
->spy_addr
[i
], ETHER_ADDR_LEN
);
729 addr
[i
].sa_family
= AF_UNIX
;
730 memcpy(&qual
[i
], &iw
->spy_qual
[i
], sizeof(struct iw_quality
));
731 iw
->spy_qual
[i
].updated
= 0;
738 wl_iw_ch_to_chanspec(int ch
, wl_join_params_t
*join_params
,
739 int *join_params_size
)
741 chanspec_t chanspec
= 0;
744 join_params
->params
.chanspec_num
= 1;
745 join_params
->params
.chanspec_list
[0] = ch
;
747 if (join_params
->params
.chanspec_list
[0])
748 chanspec
|= WL_CHANSPEC_BAND_2G
;
750 chanspec
|= WL_CHANSPEC_BAND_5G
;
752 chanspec
|= WL_CHANSPEC_BW_20
;
753 chanspec
|= WL_CHANSPEC_CTL_SB_NONE
;
755 *join_params_size
+= WL_ASSOC_PARAMS_FIXED_SIZE
+
756 join_params
->params
.chanspec_num
* sizeof(chanspec_t
);
758 join_params
->params
.chanspec_list
[0] &= WL_CHANSPEC_CHAN_MASK
;
759 join_params
->params
.chanspec_list
[0] |= chanspec
;
760 join_params
->params
.chanspec_list
[0] =
761 htodchanspec(join_params
->params
.chanspec_list
[0]);
763 join_params
->params
.chanspec_num
=
764 htod32(join_params
->params
.chanspec_num
);
766 WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n",
767 __func__
, join_params
->params
.chanspec_list
[0]));
773 wl_iw_set_wap(struct net_device
*dev
,
774 struct iw_request_info
*info
, struct sockaddr
*awrq
, char *extra
)
777 wl_join_params_t join_params
;
778 int join_params_size
;
780 WL_TRACE(("%s: SIOCSIWAP\n", dev
->name
));
782 if (awrq
->sa_family
!= ARPHRD_ETHER
) {
783 WL_ERROR(("Invalid Header...sa_family\n"));
787 if (ETHER_ISBCAST(awrq
->sa_data
) || ETHER_ISNULLADDR(awrq
->sa_data
)) {
789 bzero(&scbval
, sizeof(scb_val_t
));
790 (void)dev_wlc_ioctl(dev
, WLC_DISASSOC
, &scbval
,
795 memset(&join_params
, 0, sizeof(join_params
));
796 join_params_size
= sizeof(join_params
.ssid
);
798 memcpy(join_params
.ssid
.SSID
, g_ssid
.SSID
, g_ssid
.SSID_len
);
799 join_params
.ssid
.SSID_len
= htod32(g_ssid
.SSID_len
);
800 memcpy(&join_params
.params
.bssid
, awrq
->sa_data
, ETHER_ADDR_LEN
);
802 WL_TRACE(("%s target_channel=%d\n", __func__
,
803 g_wl_iw_params
.target_channel
));
804 wl_iw_ch_to_chanspec(g_wl_iw_params
.target_channel
, &join_params
,
807 error
= dev_wlc_ioctl(dev
, WLC_SET_SSID
, &join_params
,
810 WL_ERROR(("%s Invalid ioctl data=%d\n", __func__
, error
));
813 if (g_ssid
.SSID_len
) {
814 WL_TRACE(("%s: join SSID=%s BSSID=" MACSTR
" ch=%d\n",
815 __func__
, g_ssid
.SSID
,
816 MAC2STR((u8
*) awrq
->sa_data
),
817 g_wl_iw_params
.target_channel
));
820 memset(&g_ssid
, 0, sizeof(g_ssid
));
825 wl_iw_get_wap(struct net_device
*dev
,
826 struct iw_request_info
*info
, struct sockaddr
*awrq
, char *extra
)
828 WL_TRACE(("%s: SIOCGIWAP\n", dev
->name
));
830 awrq
->sa_family
= ARPHRD_ETHER
;
831 memset(awrq
->sa_data
, 0, ETHER_ADDR_LEN
);
833 (void)dev_wlc_ioctl(dev
, WLC_GET_BSSID
, awrq
->sa_data
, ETHER_ADDR_LEN
);
838 #if WIRELESS_EXT > 17
840 wl_iw_mlme(struct net_device
*dev
,
841 struct iw_request_info
*info
, struct sockaddr
*awrq
, char *extra
)
843 struct iw_mlme
*mlme
;
847 WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev
->name
));
849 mlme
= (struct iw_mlme
*)extra
;
851 WL_ERROR(("Invalid ioctl data.\n"));
855 scbval
.val
= mlme
->reason_code
;
856 bcopy(&mlme
->addr
.sa_data
, &scbval
.ea
, ETHER_ADDR_LEN
);
858 if (mlme
->cmd
== IW_MLME_DISASSOC
) {
859 scbval
.val
= htod32(scbval
.val
);
861 dev_wlc_ioctl(dev
, WLC_DISASSOC
, &scbval
,
863 } else if (mlme
->cmd
== IW_MLME_DEAUTH
) {
864 scbval
.val
= htod32(scbval
.val
);
866 dev_wlc_ioctl(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
,
867 &scbval
, sizeof(scb_val_t
));
869 WL_ERROR(("Invalid ioctl data.\n"));
875 #endif /* WIRELESS_EXT > 17 */
877 #ifndef WL_IW_USE_ISCAN
879 wl_iw_get_aplist(struct net_device
*dev
,
880 struct iw_request_info
*info
,
881 struct iw_point
*dwrq
, char *extra
)
883 wl_scan_results_t
*list
;
884 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
885 struct iw_quality qual
[IW_MAX_AP
];
886 wl_bss_info_t
*bi
= NULL
;
888 uint buflen
= dwrq
->length
;
890 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev
->name
));
895 list
= kmalloc(buflen
, GFP_KERNEL
);
898 memset(list
, 0, buflen
);
899 list
->buflen
= htod32(buflen
);
900 error
= dev_wlc_ioctl(dev
, WLC_SCAN_RESULTS
, list
, buflen
);
902 WL_ERROR(("%d: Scan results error %d\n", __LINE__
, error
));
906 list
->buflen
= dtoh32(list
->buflen
);
907 list
->version
= dtoh32(list
->version
);
908 list
->count
= dtoh32(list
->count
);
909 if (list
->version
!= WL_BSS_INFO_VERSION
) {
910 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
911 __func__
, list
->version
));
916 for (i
= 0, dwrq
->length
= 0;
917 i
< list
->count
&& dwrq
->length
< IW_MAX_AP
; i
++) {
918 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
919 dtoh32(bi
->length
)) : list
->
921 ASSERT(((uintptr
) bi
+ dtoh32(bi
->length
)) <=
922 ((uintptr
) list
+ buflen
));
924 if (!(dtoh16(bi
->capability
) & DOT11_CAP_ESS
))
927 memcpy(addr
[dwrq
->length
].sa_data
, &bi
->BSSID
, ETHER_ADDR_LEN
);
928 addr
[dwrq
->length
].sa_family
= ARPHRD_ETHER
;
929 qual
[dwrq
->length
].qual
= rssi_to_qual(dtoh16(bi
->RSSI
));
930 qual
[dwrq
->length
].level
= 0x100 + dtoh16(bi
->RSSI
);
931 qual
[dwrq
->length
].noise
= 0x100 + bi
->phy_noise
;
933 #if WIRELESS_EXT > 18
934 qual
[dwrq
->length
].updated
= IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
;
936 qual
[dwrq
->length
].updated
= 7;
944 memcpy(&addr
[dwrq
->length
], qual
,
945 sizeof(struct iw_quality
) * dwrq
->length
);
951 #endif /* WL_IW_USE_ISCAN */
953 #ifdef WL_IW_USE_ISCAN
955 wl_iw_iscan_get_aplist(struct net_device
*dev
,
956 struct iw_request_info
*info
,
957 struct iw_point
*dwrq
, char *extra
)
959 wl_scan_results_t
*list
;
961 iscan_info_t
*iscan
= g_iscan
;
963 struct sockaddr
*addr
= (struct sockaddr
*)extra
;
964 struct iw_quality qual
[IW_MAX_AP
];
965 wl_bss_info_t
*bi
= NULL
;
968 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev
->name
));
973 if ((!iscan
) || (iscan
->sysioc_pid
< 0)) {
974 WL_ERROR(("%s error\n", __func__
));
978 buf
= iscan
->list_hdr
;
980 list
= &((wl_iscan_results_t
*) buf
->iscan_buf
)->results
;
981 if (list
->version
!= WL_BSS_INFO_VERSION
) {
982 WL_ERROR(("%s : list->version %d != "
983 "WL_BSS_INFO_VERSION\n",
984 __func__
, list
->version
));
989 for (i
= 0, dwrq
->length
= 0;
990 i
< list
->count
&& dwrq
->length
< IW_MAX_AP
; i
++) {
991 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
992 dtoh32(bi
->length
)) :
994 ASSERT(((uintptr
) bi
+ dtoh32(bi
->length
)) <=
995 ((uintptr
) list
+ WLC_IW_ISCAN_MAXLEN
));
997 if (!(dtoh16(bi
->capability
) & DOT11_CAP_ESS
))
1000 memcpy(addr
[dwrq
->length
].sa_data
, &bi
->BSSID
,
1002 addr
[dwrq
->length
].sa_family
= ARPHRD_ETHER
;
1003 qual
[dwrq
->length
].qual
=
1004 rssi_to_qual(dtoh16(bi
->RSSI
));
1005 qual
[dwrq
->length
].level
= 0x100 + dtoh16(bi
->RSSI
);
1006 qual
[dwrq
->length
].noise
= 0x100 + bi
->phy_noise
;
1008 #if WIRELESS_EXT > 18
1009 qual
[dwrq
->length
].updated
=
1010 IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
;
1012 qual
[dwrq
->length
].updated
= 7;
1020 memcpy(&addr
[dwrq
->length
], qual
,
1021 sizeof(struct iw_quality
) * dwrq
->length
);
1028 static int wl_iw_iscan_prep(wl_scan_params_t
*params
, wlc_ssid_t
*ssid
)
1032 memcpy(¶ms
->bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
1033 params
->bss_type
= DOT11_BSSTYPE_ANY
;
1034 params
->scan_type
= 0;
1035 params
->nprobes
= -1;
1036 params
->active_time
= -1;
1037 params
->passive_time
= -1;
1038 params
->home_time
= -1;
1039 params
->channel_num
= 0;
1041 params
->nprobes
= htod32(params
->nprobes
);
1042 params
->active_time
= htod32(params
->active_time
);
1043 params
->passive_time
= htod32(params
->passive_time
);
1044 params
->home_time
= htod32(params
->home_time
);
1045 if (ssid
&& ssid
->SSID_len
)
1046 memcpy(¶ms
->ssid
, ssid
, sizeof(wlc_ssid_t
));
1051 static int wl_iw_iscan(iscan_info_t
*iscan
, wlc_ssid_t
*ssid
, uint16 action
)
1055 iscan
->iscan_ex_params_p
->version
= htod32(ISCAN_REQ_VERSION
);
1056 iscan
->iscan_ex_params_p
->action
= htod16(action
);
1057 iscan
->iscan_ex_params_p
->scan_duration
= htod16(0);
1059 WL_SCAN(("%s : nprobes=%d\n", __func__
,
1060 iscan
->iscan_ex_params_p
->params
.nprobes
));
1061 WL_SCAN(("active_time=%d\n",
1062 iscan
->iscan_ex_params_p
->params
.active_time
));
1063 WL_SCAN(("passive_time=%d\n",
1064 iscan
->iscan_ex_params_p
->params
.passive_time
));
1065 WL_SCAN(("home_time=%d\n", iscan
->iscan_ex_params_p
->params
.home_time
));
1066 WL_SCAN(("scan_type=%d\n", iscan
->iscan_ex_params_p
->params
.scan_type
));
1067 WL_SCAN(("bss_type=%d\n", iscan
->iscan_ex_params_p
->params
.bss_type
));
1069 (void)dev_iw_iovar_setbuf(iscan
->dev
, "iscan", iscan
->iscan_ex_params_p
,
1070 iscan
->iscan_ex_param_size
, iscan
->ioctlbuf
,
1071 sizeof(iscan
->ioctlbuf
));
1076 static void wl_iw_timerfunc(unsigned long data
)
1078 iscan_info_t
*iscan
= (iscan_info_t
*) data
;
1080 iscan
->timer_on
= 0;
1081 if (iscan
->iscan_state
!= ISCAN_STATE_IDLE
) {
1082 WL_TRACE(("timer trigger\n"));
1083 up(&iscan
->sysioc_sem
);
1088 static void wl_iw_set_event_mask(struct net_device
*dev
)
1090 char eventmask
[WL_EVENTING_MASK_LEN
];
1091 char iovbuf
[WL_EVENTING_MASK_LEN
+ 12];
1093 dev_iw_iovar_getbuf(dev
, "event_msgs", "", 0, iovbuf
, sizeof(iovbuf
));
1094 bcopy(iovbuf
, eventmask
, WL_EVENTING_MASK_LEN
);
1095 setbit(eventmask
, WLC_E_SCAN_COMPLETE
);
1096 dev_iw_iovar_setbuf(dev
, "event_msgs", eventmask
, WL_EVENTING_MASK_LEN
,
1097 iovbuf
, sizeof(iovbuf
));
1100 static uint32
wl_iw_iscan_get(iscan_info_t
*iscan
)
1104 wl_iscan_results_t
*list_buf
;
1105 wl_iscan_results_t list
;
1106 wl_scan_results_t
*results
;
1110 MUTEX_LOCK_WL_SCAN_SET();
1111 if (iscan
->list_cur
) {
1112 buf
= iscan
->list_cur
;
1113 iscan
->list_cur
= buf
->next
;
1115 buf
= kmalloc(sizeof(iscan_buf_t
), GFP_KERNEL
);
1117 WL_ERROR(("%s can't alloc iscan_buf_t : going to abort "
1118 "currect iscan\n", __func__
));
1119 MUTEX_UNLOCK_WL_SCAN_SET();
1120 return WL_SCAN_RESULTS_NO_MEM
;
1123 if (!iscan
->list_hdr
)
1124 iscan
->list_hdr
= buf
;
1126 ptr
= iscan
->list_hdr
;
1133 memset(buf
->iscan_buf
, 0, WLC_IW_ISCAN_MAXLEN
);
1134 list_buf
= (wl_iscan_results_t
*) buf
->iscan_buf
;
1135 results
= &list_buf
->results
;
1136 results
->buflen
= WL_ISCAN_RESULTS_FIXED_SIZE
;
1137 results
->version
= 0;
1140 memset(&list
, 0, sizeof(list
));
1141 list
.results
.buflen
= htod32(WLC_IW_ISCAN_MAXLEN
);
1142 res
= dev_iw_iovar_getbuf(iscan
->dev
,
1145 WL_ISCAN_RESULTS_FIXED_SIZE
,
1146 buf
->iscan_buf
, WLC_IW_ISCAN_MAXLEN
);
1148 results
->buflen
= dtoh32(results
->buflen
);
1149 results
->version
= dtoh32(results
->version
);
1150 results
->count
= dtoh32(results
->count
);
1151 WL_TRACE(("results->count = %d\n", results
->count
));
1152 WL_TRACE(("results->buflen = %d\n", results
->buflen
));
1153 status
= dtoh32(list_buf
->status
);
1155 WL_ERROR(("%s returns error %d\n", __func__
, res
));
1156 status
= WL_SCAN_RESULTS_NO_MEM
;
1158 MUTEX_UNLOCK_WL_SCAN_SET();
1162 static void wl_iw_force_specific_scan(iscan_info_t
*iscan
)
1164 WL_TRACE(("%s force Specific SCAN for %s\n", __func__
,
1165 g_specific_ssid
.SSID
));
1168 (void)dev_wlc_ioctl(iscan
->dev
, WLC_SCAN
, &g_specific_ssid
,
1169 sizeof(g_specific_ssid
));
1174 static void wl_iw_send_scan_complete(iscan_info_t
*iscan
)
1177 union iwreq_data wrqu
;
1179 memset(&wrqu
, 0, sizeof(wrqu
));
1181 wireless_send_event(iscan
->dev
, SIOCGIWSCAN
, &wrqu
, NULL
);
1182 WL_TRACE(("Send Event ISCAN complete\n"));
1186 static int _iscan_sysioc_thread(void *data
)
1189 iscan_info_t
*iscan
= (iscan_info_t
*) data
;
1190 static bool iscan_pass_abort
= FALSE
;
1191 DAEMONIZE("iscan_sysioc");
1193 status
= WL_SCAN_RESULTS_PARTIAL
;
1194 while (down_interruptible(&iscan
->sysioc_sem
) == 0) {
1196 if (iscan
->timer_on
) {
1197 del_timer_sync(&iscan
->timer
);
1198 iscan
->timer_on
= 0;
1201 status
= wl_iw_iscan_get(iscan
);
1203 if (g_scan_specified_ssid
&& (iscan_pass_abort
== TRUE
)) {
1204 WL_TRACE(("%s Get results from specific scan "
1205 "status = %d\n", __func__
, status
));
1206 wl_iw_send_scan_complete(iscan
);
1207 iscan_pass_abort
= FALSE
;
1212 case WL_SCAN_RESULTS_PARTIAL
:
1213 WL_TRACE(("iscanresults incomplete\n"));
1215 wl_iw_iscan(iscan
, NULL
, WL_SCAN_ACTION_CONTINUE
);
1217 mod_timer(&iscan
->timer
,
1218 jiffies
+ iscan
->timer_ms
* HZ
/ 1000);
1219 iscan
->timer_on
= 1;
1221 case WL_SCAN_RESULTS_SUCCESS
:
1222 WL_TRACE(("iscanresults complete\n"));
1223 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
1224 wl_iw_send_scan_complete(iscan
);
1226 case WL_SCAN_RESULTS_PENDING
:
1227 WL_TRACE(("iscanresults pending\n"));
1228 mod_timer(&iscan
->timer
,
1229 jiffies
+ iscan
->timer_ms
* HZ
/ 1000);
1230 iscan
->timer_on
= 1;
1232 case WL_SCAN_RESULTS_ABORTED
:
1233 WL_TRACE(("iscanresults aborted\n"));
1234 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
1235 if (g_scan_specified_ssid
== 0)
1236 wl_iw_send_scan_complete(iscan
);
1238 iscan_pass_abort
= TRUE
;
1239 wl_iw_force_specific_scan(iscan
);
1242 case WL_SCAN_RESULTS_NO_MEM
:
1243 WL_TRACE(("iscanresults can't alloc memory: skip\n"));
1244 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
1247 WL_TRACE(("iscanresults returned unknown status %d\n",
1253 if (iscan
->timer_on
) {
1254 del_timer_sync(&iscan
->timer
);
1255 iscan
->timer_on
= 0;
1257 complete_and_exit(&iscan
->sysioc_exited
, 0);
1259 #endif /* WL_IW_USE_ISCAN */
1262 wl_iw_set_scan(struct net_device
*dev
,
1263 struct iw_request_info
*info
,
1264 union iwreq_data
*wrqu
, char *extra
)
1267 WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__
, dev
->name
));
1269 g_set_essid_before_scan
= FALSE
;
1271 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__
));
1275 if (g_onoff
== G_WLAN_SET_OFF
)
1278 memset(&g_specific_ssid
, 0, sizeof(g_specific_ssid
));
1279 #ifndef WL_IW_USE_ISCAN
1280 g_scan_specified_ssid
= 0;
1283 #if WIRELESS_EXT > 17
1284 if (wrqu
->data
.length
== sizeof(struct iw_scan_req
)) {
1285 if (wrqu
->data
.flags
& IW_SCAN_THIS_ESSID
) {
1286 struct iw_scan_req
*req
= (struct iw_scan_req
*)extra
;
1287 if (g_scan_specified_ssid
) {
1288 WL_TRACE(("%s Specific SCAN is not done ignore "
1290 __func__
, req
->essid
));
1293 g_specific_ssid
.SSID_len
=
1294 MIN(sizeof(g_specific_ssid
.SSID
),
1296 memcpy(g_specific_ssid
.SSID
, req
->essid
,
1297 g_specific_ssid
.SSID_len
);
1298 g_specific_ssid
.SSID_len
=
1299 htod32(g_specific_ssid
.SSID_len
);
1300 g_scan_specified_ssid
= 1;
1301 WL_TRACE(("### Specific scan ssid=%s len=%d\n",
1302 g_specific_ssid
.SSID
,
1303 g_specific_ssid
.SSID_len
));
1307 #endif /* WIRELESS_EXT > 17 */
1308 error
= dev_wlc_ioctl(dev
, WLC_SCAN
, &g_specific_ssid
,
1309 sizeof(g_specific_ssid
));
1311 WL_TRACE(("#### Set SCAN for %s failed with %d\n",
1312 g_specific_ssid
.SSID
, error
));
1313 g_scan_specified_ssid
= 0;
1320 #ifdef WL_IW_USE_ISCAN
1321 int wl_iw_iscan_set_scan_broadcast_prep(struct net_device
*dev
, uint flag
)
1324 iscan_info_t
*iscan
= g_iscan
;
1329 wl_iw_set_event_mask(dev
);
1331 WL_TRACE(("+++: Set Broadcast ISCAN\n"));
1332 memset(&ssid
, 0, sizeof(ssid
));
1334 iscan
->list_cur
= iscan
->list_hdr
;
1335 iscan
->iscan_state
= ISCAN_STATE_SCANING
;
1337 memset(&iscan
->iscan_ex_params_p
->params
, 0,
1338 iscan
->iscan_ex_param_size
);
1339 wl_iw_iscan_prep(&iscan
->iscan_ex_params_p
->params
, &ssid
);
1340 wl_iw_iscan(iscan
, &ssid
, WL_SCAN_ACTION_START
);
1345 mod_timer(&iscan
->timer
, jiffies
+ iscan
->timer_ms
* HZ
/ 1000);
1347 iscan
->timer_on
= 1;
1353 wl_iw_iscan_set_scan(struct net_device
*dev
,
1354 struct iw_request_info
*info
,
1355 union iwreq_data
*wrqu
, char *extra
)
1358 iscan_info_t
*iscan
= g_iscan
;
1360 WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev
->name
));
1363 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__
));
1367 if (g_onoff
== G_WLAN_SET_OFF
) {
1368 WL_TRACE(("%s: driver is not up yet after START\n", __func__
));
1372 if (dhd_dev_get_pno_status(dev
)) {
1373 WL_ERROR(("%s: Scan called when PNO is active\n", __func__
));
1377 if ((!iscan
) || (iscan
->sysioc_pid
< 0))
1378 return wl_iw_set_scan(dev
, info
, wrqu
, extra
);
1380 if (g_scan_specified_ssid
) {
1381 WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n",
1386 memset(&ssid
, 0, sizeof(ssid
));
1388 #if WIRELESS_EXT > 17
1389 if (wrqu
->data
.length
== sizeof(struct iw_scan_req
)) {
1390 if (wrqu
->data
.flags
& IW_SCAN_THIS_ESSID
) {
1391 struct iw_scan_req
*req
= (struct iw_scan_req
*)extra
;
1392 ssid
.SSID_len
= MIN(sizeof(ssid
.SSID
), req
->essid_len
);
1393 memcpy(ssid
.SSID
, req
->essid
, ssid
.SSID_len
);
1394 ssid
.SSID_len
= htod32(ssid
.SSID_len
);
1396 g_scan_specified_ssid
= 0;
1398 if (iscan
->iscan_state
== ISCAN_STATE_SCANING
) {
1399 WL_TRACE(("%s ISCAN already in progress \n",
1405 #endif /* WIRELESS_EXT > 17 */
1406 wl_iw_iscan_set_scan_broadcast_prep(dev
, 0);
1410 #endif /* WL_IW_USE_ISCAN */
1412 #if WIRELESS_EXT > 17
1413 static bool ie_is_wpa_ie(u8
**wpaie
, u8
**tlvs
, int *tlvs_len
)
1419 !bcmp((const void *)&ie
[2], (const void *)(WPA_OUI
"\x01"), 4)) {
1424 *tlvs_len
-= (int)(ie
- *tlvs
);
1429 static bool ie_is_wps_ie(u8
**wpsie
, u8
**tlvs
, int *tlvs_len
)
1435 !bcmp((const void *)&ie
[2], (const void *)(WPA_OUI
"\x04"), 4)) {
1440 *tlvs_len
-= (int)(ie
- *tlvs
);
1444 #endif /* WIRELESS_EXT > 17 */
1447 wl_iw_handle_scanresults_ies(char **event_p
, char *end
,
1448 struct iw_request_info
*info
, wl_bss_info_t
*bi
)
1450 #if WIRELESS_EXT > 17
1451 struct iw_event iwe
;
1455 if (bi
->ie_length
) {
1457 u8
*ptr
= ((u8
*) bi
) + sizeof(wl_bss_info_t
);
1458 int ptr_len
= bi
->ie_length
;
1461 ie
= bcm_parse_tlvs(ptr
, ptr_len
, DOT11_MNG_RSN_ID
);
1463 iwe
.cmd
= IWEVGENIE
;
1464 iwe
.u
.data
.length
= ie
->len
+ 2;
1466 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1469 ptr
= ((u8
*) bi
) + sizeof(wl_bss_info_t
);
1472 while ((ie
= bcm_parse_tlvs(ptr
, ptr_len
, DOT11_MNG_WPA_ID
))) {
1473 if (ie_is_wps_ie(((u8
**)&ie
), &ptr
, &ptr_len
)) {
1474 iwe
.cmd
= IWEVGENIE
;
1475 iwe
.u
.data
.length
= ie
->len
+ 2;
1477 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1483 ptr
= ((u8
*) bi
) + sizeof(wl_bss_info_t
);
1484 ptr_len
= bi
->ie_length
;
1485 while ((ie
= bcm_parse_tlvs(ptr
, ptr_len
, DOT11_MNG_WPA_ID
))) {
1486 if (ie_is_wpa_ie(((u8
**)&ie
), &ptr
, &ptr_len
)) {
1487 iwe
.cmd
= IWEVGENIE
;
1488 iwe
.u
.data
.length
= ie
->len
+ 2;
1490 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1498 #endif /* WIRELESS_EXT > 17 */
1503 wl_iw_get_scan_prep(wl_scan_results_t
*list
,
1504 struct iw_request_info
*info
, char *extra
, short max_size
)
1507 struct iw_event iwe
;
1508 wl_bss_info_t
*bi
= NULL
;
1509 char *event
= extra
, *end
= extra
+ max_size
- WE_ADD_EVENT_FIX
, *value
;
1514 for (i
= 0; i
< list
->count
&& i
< IW_MAX_AP
; i
++) {
1515 if (list
->version
!= WL_BSS_INFO_VERSION
) {
1516 WL_ERROR(("%s : list->version %d != "
1517 "WL_BSS_INFO_VERSION\n",
1518 __func__
, list
->version
));
1522 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
1523 dtoh32(bi
->length
)) : list
->
1526 WL_TRACE(("%s : %s\n", __func__
, bi
->SSID
));
1528 iwe
.cmd
= SIOCGIWAP
;
1529 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
1530 memcpy(iwe
.u
.ap_addr
.sa_data
, &bi
->BSSID
, ETHER_ADDR_LEN
);
1532 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1534 iwe
.u
.data
.length
= dtoh32(bi
->SSID_len
);
1535 iwe
.cmd
= SIOCGIWESSID
;
1536 iwe
.u
.data
.flags
= 1;
1537 event
= IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
, bi
->SSID
);
1539 if (dtoh16(bi
->capability
) & (DOT11_CAP_ESS
| DOT11_CAP_IBSS
)) {
1540 iwe
.cmd
= SIOCGIWMODE
;
1541 if (dtoh16(bi
->capability
) & DOT11_CAP_ESS
)
1542 iwe
.u
.mode
= IW_MODE_INFRA
;
1544 iwe
.u
.mode
= IW_MODE_ADHOC
;
1546 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1550 iwe
.cmd
= SIOCGIWFREQ
;
1551 iwe
.u
.freq
.m
= wf_channel2mhz(CHSPEC_CHANNEL(bi
->chanspec
),
1552 CHSPEC_CHANNEL(bi
->chanspec
) <=
1554 WF_CHAN_FACTOR_2_4_G
:
1555 WF_CHAN_FACTOR_5_G
);
1558 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1562 iwe
.u
.qual
.qual
= rssi_to_qual(dtoh16(bi
->RSSI
));
1563 iwe
.u
.qual
.level
= 0x100 + dtoh16(bi
->RSSI
);
1564 iwe
.u
.qual
.noise
= 0x100 + bi
->phy_noise
;
1566 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1569 wl_iw_handle_scanresults_ies(&event
, end
, info
, bi
);
1571 iwe
.cmd
= SIOCGIWENCODE
;
1572 if (dtoh16(bi
->capability
) & DOT11_CAP_PRIVACY
)
1573 iwe
.u
.data
.flags
= IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
1575 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
1576 iwe
.u
.data
.length
= 0;
1578 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
, (char *)event
);
1580 if (bi
->rateset
.count
) {
1581 if (((event
- extra
) +
1582 IW_EV_LCP_LEN
) <= (uintptr
) end
) {
1583 value
= event
+ IW_EV_LCP_LEN
;
1584 iwe
.cmd
= SIOCGIWRATE
;
1585 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
=
1588 j
< bi
->rateset
.count
1589 && j
< IW_MAX_BITRATES
; j
++) {
1590 iwe
.u
.bitrate
.value
=
1591 (bi
->rateset
.rates
[j
] & 0x7f) *
1594 IWE_STREAM_ADD_VALUE(info
, event
,
1603 ret
= event
- extra
;
1605 WL_ERROR(("==> Wrong size\n"));
1608 WL_TRACE(("%s: size=%d bytes prepared\n", __func__
,
1609 (unsigned int)(event
- extra
)));
1614 wl_iw_get_scan(struct net_device
*dev
,
1615 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
1618 wl_scan_results_t
*list_merge
;
1619 wl_scan_results_t
*list
= (wl_scan_results_t
*) g_scan
;
1621 uint buflen_from_user
= dwrq
->length
;
1622 uint len
= G_SCAN_RESULTS
;
1624 #if defined(WL_IW_USE_ISCAN)
1625 iscan_info_t
*iscan
= g_iscan
;
1629 WL_TRACE(("%s: buflen_from_user %d: \n", dev
->name
, buflen_from_user
));
1632 WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev
->name
));
1636 error
= dev_wlc_ioctl(dev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
1639 ci
.scan_channel
= dtoh32(ci
.scan_channel
);
1640 if (ci
.scan_channel
)
1643 if (g_scan_specified_ssid
) {
1644 list
= kmalloc(len
, GFP_KERNEL
);
1646 WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n",
1648 g_scan_specified_ssid
= 0;
1653 memset(list
, 0, len
);
1654 list
->buflen
= htod32(len
);
1655 error
= dev_wlc_ioctl(dev
, WLC_SCAN_RESULTS
, list
, len
);
1657 WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev
->name
,
1660 if (g_scan_specified_ssid
) {
1661 g_scan_specified_ssid
= 0;
1666 list
->buflen
= dtoh32(list
->buflen
);
1667 list
->version
= dtoh32(list
->version
);
1668 list
->count
= dtoh32(list
->count
);
1670 if (list
->version
!= WL_BSS_INFO_VERSION
) {
1671 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1672 __func__
, list
->version
));
1673 if (g_scan_specified_ssid
) {
1674 g_scan_specified_ssid
= 0;
1680 if (g_scan_specified_ssid
) {
1681 WL_TRACE(("%s: Specified scan APs in the list =%d\n",
1682 __func__
, list
->count
));
1684 (__u16
) wl_iw_get_scan_prep(list
, info
, extra
,
1688 #if defined(WL_IW_USE_ISCAN)
1689 p_buf
= iscan
->list_hdr
;
1690 while (p_buf
!= iscan
->list_cur
) {
1692 &((wl_iscan_results_t
*) p_buf
->iscan_buf
)->results
;
1693 WL_TRACE(("%s: Bcast APs list=%d\n", __func__
,
1694 list_merge
->count
));
1695 if (list_merge
->count
> 0)
1697 (__u16
) wl_iw_get_scan_prep(list_merge
,
1698 info
, extra
+ len_ret
,
1699 buflen_from_user
- len_ret
);
1700 p_buf
= p_buf
->next
;
1703 list_merge
= (wl_scan_results_t
*) g_scan
;
1704 WL_TRACE(("%s: Bcast APs list=%d\n", __func__
,
1705 list_merge
->count
));
1706 if (list_merge
->count
> 0)
1708 (__u16
) wl_iw_get_scan_prep(list_merge
, info
,
1712 #endif /* defined(WL_IW_USE_ISCAN) */
1714 list
= (wl_scan_results_t
*) g_scan
;
1716 (__u16
) wl_iw_get_scan_prep(list
, info
, extra
,
1720 #if defined(WL_IW_USE_ISCAN)
1721 g_scan_specified_ssid
= 0;
1723 if ((len_ret
+ WE_ADD_EVENT_FIX
) < buflen_from_user
)
1729 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__
,
1730 dwrq
->length
, list
->count
));
1734 #if defined(WL_IW_USE_ISCAN)
1736 wl_iw_iscan_get_scan(struct net_device
*dev
,
1737 struct iw_request_info
*info
,
1738 struct iw_point
*dwrq
, char *extra
)
1740 wl_scan_results_t
*list
;
1741 struct iw_event iwe
;
1742 wl_bss_info_t
*bi
= NULL
;
1745 char *event
= extra
, *end
= extra
+ dwrq
->length
, *value
;
1746 iscan_info_t
*iscan
= g_iscan
;
1751 WL_TRACE(("%s %s buflen_from_user %d:\n", dev
->name
, __func__
,
1755 WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
1760 if ((!iscan
) || (iscan
->sysioc_pid
< 0)) {
1761 WL_ERROR(("%ssysioc_pid\n", __func__
));
1762 return wl_iw_get_scan(dev
, info
, dwrq
, extra
);
1765 if (iscan
->iscan_state
== ISCAN_STATE_SCANING
) {
1766 WL_TRACE(("%s: SIOCGIWSCAN GET still scanning\n", dev
->name
));
1770 WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev
->name
));
1772 p_buf
= iscan
->list_hdr
;
1773 while (p_buf
!= iscan
->list_cur
) {
1774 list
= &((wl_iscan_results_t
*) p_buf
->iscan_buf
)->results
;
1776 counter
+= list
->count
;
1778 if (list
->version
!= WL_BSS_INFO_VERSION
) {
1779 WL_ERROR(("%s : list->version %d != "
1780 "WL_BSS_INFO_VERSION\n",
1781 __func__
, list
->version
));
1786 for (ii
= 0; ii
< list
->count
&& apcnt
< IW_MAX_AP
;
1788 bi
= bi
? (wl_bss_info_t
*) ((uintptr
) bi
+
1789 dtoh32(bi
->length
)) :
1791 ASSERT(((uintptr
) bi
+ dtoh32(bi
->length
)) <=
1792 ((uintptr
) list
+ WLC_IW_ISCAN_MAXLEN
));
1794 if (event
+ ETHER_ADDR_LEN
+ bi
->SSID_len
+
1795 IW_EV_UINT_LEN
+ IW_EV_FREQ_LEN
+ IW_EV_QUAL_LEN
>=
1798 iwe
.cmd
= SIOCGIWAP
;
1799 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
1800 memcpy(iwe
.u
.ap_addr
.sa_data
, &bi
->BSSID
,
1803 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1806 iwe
.u
.data
.length
= dtoh32(bi
->SSID_len
);
1807 iwe
.cmd
= SIOCGIWESSID
;
1808 iwe
.u
.data
.flags
= 1;
1810 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1813 if (dtoh16(bi
->capability
) &
1814 (DOT11_CAP_ESS
| DOT11_CAP_IBSS
)) {
1815 iwe
.cmd
= SIOCGIWMODE
;
1816 if (dtoh16(bi
->capability
) & DOT11_CAP_ESS
)
1817 iwe
.u
.mode
= IW_MODE_INFRA
;
1819 iwe
.u
.mode
= IW_MODE_ADHOC
;
1821 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1825 iwe
.cmd
= SIOCGIWFREQ
;
1828 0) ? CHSPEC_CHANNEL(bi
->chanspec
) : bi
->ctl_ch
;
1830 wf_channel2mhz(channel
,
1833 WF_CHAN_FACTOR_2_4_G
:
1834 WF_CHAN_FACTOR_5_G
);
1837 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1841 iwe
.u
.qual
.qual
= rssi_to_qual(dtoh16(bi
->RSSI
));
1842 iwe
.u
.qual
.level
= 0x100 + dtoh16(bi
->RSSI
);
1843 iwe
.u
.qual
.noise
= 0x100 + bi
->phy_noise
;
1845 IWE_STREAM_ADD_EVENT(info
, event
, end
, &iwe
,
1848 wl_iw_handle_scanresults_ies(&event
, end
, info
, bi
);
1850 iwe
.cmd
= SIOCGIWENCODE
;
1851 if (dtoh16(bi
->capability
) & DOT11_CAP_PRIVACY
)
1853 IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
1855 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
1856 iwe
.u
.data
.length
= 0;
1858 IWE_STREAM_ADD_POINT(info
, event
, end
, &iwe
,
1861 if (bi
->rateset
.count
) {
1862 if (event
+ IW_MAX_BITRATES
* IW_EV_PARAM_LEN
>=
1866 value
= event
+ IW_EV_LCP_LEN
;
1867 iwe
.cmd
= SIOCGIWRATE
;
1868 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
=
1871 j
< bi
->rateset
.count
1872 && j
< IW_MAX_BITRATES
; j
++) {
1873 iwe
.u
.bitrate
.value
=
1874 (bi
->rateset
.rates
[j
] & 0x7f) *
1877 IWE_STREAM_ADD_VALUE(info
, event
,
1885 p_buf
= p_buf
->next
;
1888 dwrq
->length
= event
- extra
;
1891 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__
,
1892 dwrq
->length
, counter
));
1899 #endif /* defined(WL_IW_USE_ISCAN) */
1902 wl_iw_set_essid(struct net_device
*dev
,
1903 struct iw_request_info
*info
,
1904 struct iw_point
*dwrq
, char *extra
)
1907 wl_join_params_t join_params
;
1908 int join_params_size
;
1910 WL_TRACE(("%s: SIOCSIWESSID\n", dev
->name
));
1912 if (g_set_essid_before_scan
)
1915 memset(&g_ssid
, 0, sizeof(g_ssid
));
1917 CHECK_EXTRA_FOR_NULL(extra
);
1919 if (dwrq
->length
&& extra
) {
1920 #if WIRELESS_EXT > 20
1921 g_ssid
.SSID_len
= MIN(sizeof(g_ssid
.SSID
), dwrq
->length
);
1923 g_ssid
.SSID_len
= MIN(sizeof(g_ssid
.SSID
), dwrq
->length
- 1);
1925 memcpy(g_ssid
.SSID
, extra
, g_ssid
.SSID_len
);
1927 g_ssid
.SSID_len
= 0;
1929 g_ssid
.SSID_len
= htod32(g_ssid
.SSID_len
);
1931 memset(&join_params
, 0, sizeof(join_params
));
1932 join_params_size
= sizeof(join_params
.ssid
);
1934 memcpy(&join_params
.ssid
.SSID
, g_ssid
.SSID
, g_ssid
.SSID_len
);
1935 join_params
.ssid
.SSID_len
= htod32(g_ssid
.SSID_len
);
1936 memcpy(&join_params
.params
.bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
1938 wl_iw_ch_to_chanspec(g_wl_iw_params
.target_channel
, &join_params
,
1941 error
= dev_wlc_ioctl(dev
, WLC_SET_SSID
, &join_params
,
1944 WL_ERROR(("Invalid ioctl data=%d\n", error
));
1946 if (g_ssid
.SSID_len
) {
1947 WL_TRACE(("%s: join SSID=%s ch=%d\n", __func__
,
1948 g_ssid
.SSID
, g_wl_iw_params
.target_channel
));
1954 wl_iw_get_essid(struct net_device
*dev
,
1955 struct iw_request_info
*info
,
1956 struct iw_point
*dwrq
, char *extra
)
1961 WL_TRACE(("%s: SIOCGIWESSID\n", dev
->name
));
1966 error
= dev_wlc_ioctl(dev
, WLC_GET_SSID
, &ssid
, sizeof(ssid
));
1968 WL_ERROR(("Error getting the SSID\n"));
1972 ssid
.SSID_len
= dtoh32(ssid
.SSID_len
);
1974 memcpy(extra
, ssid
.SSID
, ssid
.SSID_len
);
1976 dwrq
->length
= ssid
.SSID_len
;
1984 wl_iw_set_nick(struct net_device
*dev
,
1985 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
1987 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
1989 WL_TRACE(("%s: SIOCSIWNICKN\n", dev
->name
));
1994 if (dwrq
->length
> sizeof(iw
->nickname
))
1997 memcpy(iw
->nickname
, extra
, dwrq
->length
);
1998 iw
->nickname
[dwrq
->length
- 1] = '\0';
2004 wl_iw_get_nick(struct net_device
*dev
,
2005 struct iw_request_info
*info
, struct iw_point
*dwrq
, char *extra
)
2007 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
2009 WL_TRACE(("%s: SIOCGIWNICKN\n", dev
->name
));
2014 strcpy(extra
, iw
->nickname
);
2015 dwrq
->length
= strlen(extra
) + 1;
2021 wl_iw_set_rate(struct net_device
*dev
,
2022 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2024 wl_rateset_t rateset
;
2025 int error
, rate
, i
, error_bg
, error_a
;
2027 WL_TRACE(("%s: SIOCSIWRATE\n", dev
->name
));
2029 error
= dev_wlc_ioctl(dev
, WLC_GET_CURR_RATESET
, &rateset
,
2034 rateset
.count
= dtoh32(rateset
.count
);
2036 if (vwrq
->value
< 0)
2037 rate
= rateset
.rates
[rateset
.count
- 1] & 0x7f;
2038 else if (vwrq
->value
< rateset
.count
)
2039 rate
= rateset
.rates
[vwrq
->value
] & 0x7f;
2041 rate
= vwrq
->value
/ 500000;
2044 error_bg
= dev_wlc_intvar_set(dev
, "bg_rate", rate
);
2045 error_a
= dev_wlc_intvar_set(dev
, "a_rate", rate
);
2047 if (error_bg
&& error_a
)
2048 return error_bg
| error_a
;
2050 error_bg
= dev_wlc_intvar_set(dev
, "bg_rate", 0);
2051 error_a
= dev_wlc_intvar_set(dev
, "a_rate", 0);
2053 if (error_bg
&& error_a
)
2054 return error_bg
| error_a
;
2056 for (i
= 0; i
< rateset
.count
; i
++)
2057 if ((rateset
.rates
[i
] & 0x7f) > rate
)
2059 rateset
.count
= htod32(i
);
2061 error
= dev_wlc_ioctl(dev
, WLC_SET_RATESET
, &rateset
,
2071 wl_iw_get_rate(struct net_device
*dev
,
2072 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2076 WL_TRACE(("%s: SIOCGIWRATE\n", dev
->name
));
2078 error
= dev_wlc_ioctl(dev
, WLC_GET_RATE
, &rate
, sizeof(rate
));
2081 rate
= dtoh32(rate
);
2082 vwrq
->value
= rate
* 500000;
2088 wl_iw_set_rts(struct net_device
*dev
,
2089 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2093 WL_TRACE(("%s: SIOCSIWRTS\n", dev
->name
));
2096 rts
= DOT11_DEFAULT_RTS_LEN
;
2097 else if (vwrq
->value
< 0 || vwrq
->value
> DOT11_DEFAULT_RTS_LEN
)
2102 error
= dev_wlc_intvar_set(dev
, "rtsthresh", rts
);
2110 wl_iw_get_rts(struct net_device
*dev
,
2111 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2115 WL_TRACE(("%s: SIOCGIWRTS\n", dev
->name
));
2117 error
= dev_wlc_intvar_get(dev
, "rtsthresh", &rts
);
2122 vwrq
->disabled
= (rts
>= DOT11_DEFAULT_RTS_LEN
);
2129 wl_iw_set_frag(struct net_device
*dev
,
2130 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2134 WL_TRACE(("%s: SIOCSIWFRAG\n", dev
->name
));
2137 frag
= DOT11_DEFAULT_FRAG_LEN
;
2138 else if (vwrq
->value
< 0 || vwrq
->value
> DOT11_DEFAULT_FRAG_LEN
)
2143 error
= dev_wlc_intvar_set(dev
, "fragthresh", frag
);
2151 wl_iw_get_frag(struct net_device
*dev
,
2152 struct iw_request_info
*info
, struct iw_param
*vwrq
, char *extra
)
2154 int error
, fragthreshold
;
2156 WL_TRACE(("%s: SIOCGIWFRAG\n", dev
->name
));
2158 error
= dev_wlc_intvar_get(dev
, "fragthresh", &fragthreshold
);
2162 vwrq
->value
= fragthreshold
;
2163 vwrq
->disabled
= (fragthreshold
>= DOT11_DEFAULT_FRAG_LEN
);
2170 wl_iw_set_txpow(struct net_device
*dev
,
2171 struct iw_request_info
*info
,
2172 struct iw_param
*vwrq
, char *extra
)
2176 WL_TRACE(("%s: SIOCSIWTXPOW\n", dev
->name
));
2178 disable
= vwrq
->disabled
? WL_RADIO_SW_DISABLE
: 0;
2179 disable
+= WL_RADIO_SW_DISABLE
<< 16;
2181 disable
= htod32(disable
);
2182 error
= dev_wlc_ioctl(dev
, WLC_SET_RADIO
, &disable
, sizeof(disable
));
2186 if (disable
& WL_RADIO_SW_DISABLE
)
2189 if (!(vwrq
->flags
& IW_TXPOW_MWATT
))
2192 if (vwrq
->value
< 0)
2195 if (vwrq
->value
> 0xffff)
2198 txpwrmw
= (uint16
) vwrq
->value
;
2201 dev_wlc_intvar_set(dev
, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw
)));
2206 wl_iw_get_txpow(struct net_device
*dev
,
2207 struct iw_request_info
*info
,
2208 struct iw_param
*vwrq
, char *extra
)
2210 int error
, disable
, txpwrdbm
;
2213 WL_TRACE(("%s: SIOCGIWTXPOW\n", dev
->name
));
2215 error
= dev_wlc_ioctl(dev
, WLC_GET_RADIO
, &disable
, sizeof(disable
));
2219 error
= dev_wlc_intvar_get(dev
, "qtxpower", &txpwrdbm
);
2223 disable
= dtoh32(disable
);
2224 result
= (u8
) (txpwrdbm
& ~WL_TXPWR_OVERRIDE
);
2225 vwrq
->value
= (int32
) bcm_qdbm_to_mw(result
);
2228 (disable
& (WL_RADIO_SW_DISABLE
| WL_RADIO_HW_DISABLE
)) ? 1 : 0;
2229 vwrq
->flags
= IW_TXPOW_MWATT
;
2234 #if WIRELESS_EXT > 10
2236 wl_iw_set_retry(struct net_device
*dev
,
2237 struct iw_request_info
*info
,
2238 struct iw_param
*vwrq
, char *extra
)
2240 int error
, lrl
, srl
;
2242 WL_TRACE(("%s: SIOCSIWRETRY\n", dev
->name
));
2244 if (vwrq
->disabled
|| (vwrq
->flags
& IW_RETRY_LIFETIME
))
2247 if (vwrq
->flags
& IW_RETRY_LIMIT
) {
2249 #if WIRELESS_EXT > 20
2250 if ((vwrq
->flags
& IW_RETRY_LONG
)
2251 || (vwrq
->flags
& IW_RETRY_MAX
)
2252 || !((vwrq
->flags
& IW_RETRY_SHORT
)
2253 || (vwrq
->flags
& IW_RETRY_MIN
))) {
2255 if ((vwrq
->flags
& IW_RETRY_MAX
)
2256 || !(vwrq
->flags
& IW_RETRY_MIN
)) {
2258 lrl
= htod32(vwrq
->value
);
2259 error
= dev_wlc_ioctl(dev
, WLC_SET_LRL
, &lrl
,
2264 #if WIRELESS_EXT > 20
2265 if ((vwrq
->flags
& IW_RETRY_SHORT
)
2266 || (vwrq
->flags
& IW_RETRY_MIN
)
2267 || !((vwrq
->flags
& IW_RETRY_LONG
)
2268 || (vwrq
->flags
& IW_RETRY_MAX
))) {
2270 if ((vwrq
->flags
& IW_RETRY_MIN
)
2271 || !(vwrq
->flags
& IW_RETRY_MAX
)) {
2273 srl
= htod32(vwrq
->value
);
2274 error
= dev_wlc_ioctl(dev
, WLC_SET_SRL
, &srl
,
2284 wl_iw_get_retry(struct net_device
*dev
,
2285 struct iw_request_info
*info
,
2286 struct iw_param
*vwrq
, char *extra
)
2288 int error
, lrl
, srl
;
2290 WL_TRACE(("%s: SIOCGIWRETRY\n", dev
->name
));
2294 if ((vwrq
->flags
& IW_RETRY_TYPE
) == IW_RETRY_LIFETIME
)
2297 error
= dev_wlc_ioctl(dev
, WLC_GET_LRL
, &lrl
, sizeof(lrl
));
2301 error
= dev_wlc_ioctl(dev
, WLC_GET_SRL
, &srl
, sizeof(srl
));
2308 if (vwrq
->flags
& IW_RETRY_MAX
) {
2309 vwrq
->flags
= IW_RETRY_LIMIT
| IW_RETRY_MAX
;
2312 vwrq
->flags
= IW_RETRY_LIMIT
;
2315 vwrq
->flags
|= IW_RETRY_MIN
;
2320 #endif /* WIRELESS_EXT > 10 */
2323 wl_iw_set_encode(struct net_device
*dev
,
2324 struct iw_request_info
*info
,
2325 struct iw_point
*dwrq
, char *extra
)
2328 int error
, val
, wsec
;
2330 WL_TRACE(("%s: SIOCSIWENCODE\n", dev
->name
));
2332 memset(&key
, 0, sizeof(key
));
2334 if ((dwrq
->flags
& IW_ENCODE_INDEX
) == 0) {
2335 for (key
.index
= 0; key
.index
< DOT11_MAX_DEFAULT_KEYS
;
2337 val
= htod32(key
.index
);
2338 error
= dev_wlc_ioctl(dev
, WLC_GET_KEY_PRIMARY
, &val
,
2346 if (key
.index
== DOT11_MAX_DEFAULT_KEYS
)
2349 key
.index
= (dwrq
->flags
& IW_ENCODE_INDEX
) - 1;
2350 if (key
.index
>= DOT11_MAX_DEFAULT_KEYS
)
2354 if (!extra
|| !dwrq
->length
|| (dwrq
->flags
& IW_ENCODE_NOKEY
)) {
2355 val
= htod32(key
.index
);
2356 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY_PRIMARY
, &val
,
2361 key
.len
= dwrq
->length
;
2363 if (dwrq
->length
> sizeof(key
.data
))
2366 memcpy(key
.data
, extra
, dwrq
->length
);
2368 key
.flags
= WL_PRIMARY_KEY
;
2371 key
.algo
= CRYPTO_ALGO_WEP1
;
2373 case WEP128_KEY_SIZE
:
2374 key
.algo
= CRYPTO_ALGO_WEP128
;
2377 key
.algo
= CRYPTO_ALGO_TKIP
;
2380 key
.algo
= CRYPTO_ALGO_AES_CCM
;
2386 swap_key_from_BE(&key
);
2387 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY
, &key
, sizeof(key
));
2392 val
= (dwrq
->flags
& IW_ENCODE_DISABLED
) ? 0 : WEP_ENABLED
;
2394 error
= dev_wlc_intvar_get(dev
, "wsec", &wsec
);
2398 wsec
&= ~(WEP_ENABLED
);
2401 error
= dev_wlc_intvar_set(dev
, "wsec", wsec
);
2405 val
= (dwrq
->flags
& IW_ENCODE_RESTRICTED
) ? 1 : 0;
2407 error
= dev_wlc_ioctl(dev
, WLC_SET_AUTH
, &val
, sizeof(val
));
2415 wl_iw_get_encode(struct net_device
*dev
,
2416 struct iw_request_info
*info
,
2417 struct iw_point
*dwrq
, char *extra
)
2420 int error
, val
, wsec
, auth
;
2422 WL_TRACE(("%s: SIOCGIWENCODE\n", dev
->name
));
2424 bzero(&key
, sizeof(wl_wsec_key_t
));
2426 if ((dwrq
->flags
& IW_ENCODE_INDEX
) == 0) {
2427 for (key
.index
= 0; key
.index
< DOT11_MAX_DEFAULT_KEYS
;
2430 error
= dev_wlc_ioctl(dev
, WLC_GET_KEY_PRIMARY
, &val
,
2439 key
.index
= (dwrq
->flags
& IW_ENCODE_INDEX
) - 1;
2441 if (key
.index
>= DOT11_MAX_DEFAULT_KEYS
)
2444 error
= dev_wlc_ioctl(dev
, WLC_GET_WSEC
, &wsec
, sizeof(wsec
));
2448 error
= dev_wlc_ioctl(dev
, WLC_GET_AUTH
, &auth
, sizeof(auth
));
2452 swap_key_to_BE(&key
);
2454 wsec
= dtoh32(wsec
);
2455 auth
= dtoh32(auth
);
2456 dwrq
->length
= MIN(DOT11_MAX_KEY_SIZE
, key
.len
);
2458 dwrq
->flags
= key
.index
+ 1;
2459 if (!(wsec
& (WEP_ENABLED
| TKIP_ENABLED
| AES_ENABLED
)))
2460 dwrq
->flags
|= IW_ENCODE_DISABLED
;
2463 dwrq
->flags
|= IW_ENCODE_RESTRICTED
;
2465 if (dwrq
->length
&& extra
)
2466 memcpy(extra
, key
.data
, dwrq
->length
);
2472 wl_iw_set_power(struct net_device
*dev
,
2473 struct iw_request_info
*info
,
2474 struct iw_param
*vwrq
, char *extra
)
2478 WL_TRACE(("%s: SIOCSIWPOWER\n", dev
->name
));
2480 pm
= vwrq
->disabled
? PM_OFF
: PM_MAX
;
2483 error
= dev_wlc_ioctl(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
2491 wl_iw_get_power(struct net_device
*dev
,
2492 struct iw_request_info
*info
,
2493 struct iw_param
*vwrq
, char *extra
)
2497 WL_TRACE(("%s: SIOCGIWPOWER\n", dev
->name
));
2499 error
= dev_wlc_ioctl(dev
, WLC_GET_PM
, &pm
, sizeof(pm
));
2504 vwrq
->disabled
= pm
? 0 : 1;
2505 vwrq
->flags
= IW_POWER_ALL_R
;
2510 #if WIRELESS_EXT > 17
2512 wl_iw_set_wpaie(struct net_device
*dev
,
2513 struct iw_request_info
*info
, struct iw_point
*iwp
, char *extra
)
2516 WL_TRACE(("%s: SIOCSIWGENIE\n", dev
->name
));
2518 CHECK_EXTRA_FOR_NULL(extra
);
2520 dev_wlc_bufvar_set(dev
, "wpaie", extra
, iwp
->length
);
2526 wl_iw_get_wpaie(struct net_device
*dev
,
2527 struct iw_request_info
*info
, struct iw_point
*iwp
, char *extra
)
2529 WL_TRACE(("%s: SIOCGIWGENIE\n", dev
->name
));
2531 dev_wlc_bufvar_get(dev
, "wpaie", extra
, iwp
->length
);
2536 wl_iw_set_encodeext(struct net_device
*dev
,
2537 struct iw_request_info
*info
,
2538 struct iw_point
*dwrq
, char *extra
)
2542 struct iw_encode_ext
*iwe
;
2544 WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev
->name
));
2546 CHECK_EXTRA_FOR_NULL(extra
);
2548 memset(&key
, 0, sizeof(key
));
2549 iwe
= (struct iw_encode_ext
*)extra
;
2551 if (dwrq
->flags
& IW_ENCODE_DISABLED
) {
2556 if (dwrq
->flags
& IW_ENCODE_INDEX
)
2557 key
.index
= (dwrq
->flags
& IW_ENCODE_INDEX
) - 1;
2559 key
.len
= iwe
->key_len
;
2561 if (!ETHER_ISMULTI(iwe
->addr
.sa_data
))
2562 bcopy((void *)&iwe
->addr
.sa_data
, (char *)&key
.ea
,
2566 if (iwe
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
2567 WL_WSEC(("Changing the the primary Key to %d\n",
2569 key
.index
= htod32(key
.index
);
2570 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY_PRIMARY
,
2571 &key
.index
, sizeof(key
.index
));
2575 swap_key_from_BE(&key
);
2576 dev_wlc_ioctl(dev
, WLC_SET_KEY
, &key
, sizeof(key
));
2579 if (iwe
->key_len
> sizeof(key
.data
))
2582 WL_WSEC(("Setting the key index %d\n", key
.index
));
2583 if (iwe
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
2584 WL_WSEC(("key is a Primary Key\n"));
2585 key
.flags
= WL_PRIMARY_KEY
;
2588 bcopy((void *)iwe
->key
, key
.data
, iwe
->key_len
);
2590 if (iwe
->alg
== IW_ENCODE_ALG_TKIP
) {
2592 bcopy(&key
.data
[24], keybuf
, sizeof(keybuf
));
2593 bcopy(&key
.data
[16], &key
.data
[24], sizeof(keybuf
));
2594 bcopy(keybuf
, &key
.data
[16], sizeof(keybuf
));
2597 if (iwe
->ext_flags
& IW_ENCODE_EXT_RX_SEQ_VALID
) {
2598 unsigned char *ivptr
;
2599 ivptr
= (unsigned char *) iwe
->rx_seq
;
2600 key
.rxiv
.hi
= (ivptr
[5] << 24) | (ivptr
[4] << 16) |
2601 (ivptr
[3] << 8) | ivptr
[2];
2602 key
.rxiv
.lo
= (ivptr
[1] << 8) | ivptr
[0];
2603 key
.iv_initialized
= TRUE
;
2607 case IW_ENCODE_ALG_NONE
:
2608 key
.algo
= CRYPTO_ALGO_OFF
;
2610 case IW_ENCODE_ALG_WEP
:
2611 if (iwe
->key_len
== WEP1_KEY_SIZE
)
2612 key
.algo
= CRYPTO_ALGO_WEP1
;
2614 key
.algo
= CRYPTO_ALGO_WEP128
;
2616 case IW_ENCODE_ALG_TKIP
:
2617 key
.algo
= CRYPTO_ALGO_TKIP
;
2619 case IW_ENCODE_ALG_CCMP
:
2620 key
.algo
= CRYPTO_ALGO_AES_CCM
;
2625 swap_key_from_BE(&key
);
2627 dhd_wait_pend8021x(dev
);
2629 error
= dev_wlc_ioctl(dev
, WLC_SET_KEY
, &key
, sizeof(key
));
2636 #if WIRELESS_EXT > 17
2639 pmkid_list_t pmkids
;
2640 pmkid_t foo
[MAXPMKID
- 1];
2644 wl_iw_set_pmksa(struct net_device
*dev
,
2645 struct iw_request_info
*info
,
2646 struct iw_param
*vwrq
, char *extra
)
2648 struct iw_pmksa
*iwpmksa
;
2651 char eabuf
[ETHER_ADDR_STR_LEN
];
2653 WL_WSEC(("%s: SIOCSIWPMKSA\n", dev
->name
));
2655 CHECK_EXTRA_FOR_NULL(extra
);
2657 iwpmksa
= (struct iw_pmksa
*)extra
;
2658 bzero((char *)eabuf
, ETHER_ADDR_STR_LEN
);
2660 if (iwpmksa
->cmd
== IW_PMKSA_FLUSH
) {
2661 WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
2662 bzero((char *)&pmkid_list
, sizeof(pmkid_list
));
2665 else if (iwpmksa
->cmd
== IW_PMKSA_REMOVE
) {
2667 pmkid_list_t pmkid
, *pmkidptr
;
2671 bcopy(&iwpmksa
->bssid
.sa_data
[0],
2672 &pmkidptr
->pmkid
[0].BSSID
, ETHER_ADDR_LEN
);
2673 bcopy(&iwpmksa
->pmkid
[0], &pmkidptr
->pmkid
[0].PMKID
,
2676 WL_WSEC(("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: %s = ",
2677 bcm_ether_ntoa(&pmkidptr
->pmkid
[0].BSSID
, eabuf
)));
2678 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++)
2679 WL_WSEC(("%02x ", pmkidptr
->pmkid
[0].PMKID
[j
]));
2683 for (i
= 0; i
< pmkid_list
.pmkids
.npmkid
; i
++)
2685 (&iwpmksa
->bssid
.sa_data
[0],
2686 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
, ETHER_ADDR_LEN
))
2689 if ((pmkid_list
.pmkids
.npmkid
> 0)
2690 && (i
< pmkid_list
.pmkids
.npmkid
)) {
2691 bzero(&pmkid_list
.pmkids
.pmkid
[i
], sizeof(pmkid_t
));
2692 for (; i
< (pmkid_list
.pmkids
.npmkid
- 1); i
++) {
2693 bcopy(&pmkid_list
.pmkids
.pmkid
[i
+ 1].BSSID
,
2694 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
,
2696 bcopy(&pmkid_list
.pmkids
.pmkid
[i
+ 1].PMKID
,
2697 &pmkid_list
.pmkids
.pmkid
[i
].PMKID
,
2700 pmkid_list
.pmkids
.npmkid
--;
2705 else if (iwpmksa
->cmd
== IW_PMKSA_ADD
) {
2706 for (i
= 0; i
< pmkid_list
.pmkids
.npmkid
; i
++)
2708 (&iwpmksa
->bssid
.sa_data
[0],
2709 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
, ETHER_ADDR_LEN
))
2712 bcopy(&iwpmksa
->bssid
.sa_data
[0],
2713 &pmkid_list
.pmkids
.pmkid
[i
].BSSID
,
2715 bcopy(&iwpmksa
->pmkid
[0],
2716 &pmkid_list
.pmkids
.pmkid
[i
].PMKID
,
2718 if (i
== pmkid_list
.pmkids
.npmkid
)
2719 pmkid_list
.pmkids
.npmkid
++;
2725 k
= pmkid_list
.pmkids
.npmkid
;
2726 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
2727 bcm_ether_ntoa(&pmkid_list
.pmkids
.pmkid
[k
].
2729 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++)
2731 pmkid_list
.pmkids
.pmkid
[k
].PMKID
[j
]));
2735 WL_WSEC(("PRINTING pmkid LIST - No of elements %d\n",
2736 pmkid_list
.pmkids
.npmkid
));
2737 for (i
= 0; i
< pmkid_list
.pmkids
.npmkid
; i
++) {
2739 WL_WSEC(("PMKID[%d]: %s = ", i
,
2740 bcm_ether_ntoa(&pmkid_list
.pmkids
.pmkid
[i
].BSSID
,
2742 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++)
2743 WL_WSEC(("%02x ", pmkid_list
.pmkids
.pmkid
[i
].PMKID
[j
]));
2749 ret
= dev_wlc_bufvar_set(dev
, "pmkid_info", (char *)&pmkid_list
,
2750 sizeof(pmkid_list
));
2753 #endif /* BCMWPA2 */
2754 #endif /* WIRELESS_EXT > 17 */
2757 wl_iw_get_encodeext(struct net_device
*dev
,
2758 struct iw_request_info
*info
,
2759 struct iw_param
*vwrq
, char *extra
)
2761 WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev
->name
));
2766 wl_iw_set_wpaauth(struct net_device
*dev
,
2767 struct iw_request_info
*info
,
2768 struct iw_param
*vwrq
, char *extra
)
2774 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
2776 WL_TRACE(("%s: SIOCSIWAUTH\n", dev
->name
));
2778 paramid
= vwrq
->flags
& IW_AUTH_INDEX
;
2779 paramval
= vwrq
->value
;
2781 WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
2782 dev
->name
, paramid
, paramval
));
2785 case IW_AUTH_WPA_VERSION
:
2786 if (paramval
& IW_AUTH_WPA_VERSION_DISABLED
)
2787 val
= WPA_AUTH_DISABLED
;
2788 else if (paramval
& (IW_AUTH_WPA_VERSION_WPA
))
2789 val
= WPA_AUTH_PSK
| WPA_AUTH_UNSPECIFIED
;
2791 else if (paramval
& IW_AUTH_WPA_VERSION_WPA2
)
2792 val
= WPA2_AUTH_PSK
| WPA2_AUTH_UNSPECIFIED
;
2794 WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __func__
,
2796 error
= dev_wlc_intvar_set(dev
, "wpa_auth", val
);
2800 case IW_AUTH_CIPHER_PAIRWISE
:
2801 case IW_AUTH_CIPHER_GROUP
:
2802 if (paramval
& (IW_AUTH_CIPHER_WEP40
| IW_AUTH_CIPHER_WEP104
))
2804 if (paramval
& IW_AUTH_CIPHER_TKIP
)
2806 if (paramval
& IW_AUTH_CIPHER_CCMP
)
2809 if (paramid
== IW_AUTH_CIPHER_PAIRWISE
) {
2817 if (iw
->privacy_invoked
&& !val
) {
2818 WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing "
2819 "wsec, assuming " "we're a WPS enrollee\n",
2820 dev
->name
, __func__
));
2821 error
= dev_wlc_intvar_set(dev
, "is_WPS_enrollee",
2824 WL_WSEC(("Failed to set is_WPS_enrollee\n"));
2828 error
= dev_wlc_intvar_set(dev
, "is_WPS_enrollee",
2831 WL_WSEC(("Failed to clear is_WPS_enrollee\n"));
2836 error
= dev_wlc_intvar_set(dev
, "wsec", val
);
2842 case IW_AUTH_KEY_MGMT
:
2843 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
2847 if (val
& (WPA_AUTH_PSK
| WPA_AUTH_UNSPECIFIED
)) {
2848 if (paramval
& IW_AUTH_KEY_MGMT_PSK
)
2851 val
= WPA_AUTH_UNSPECIFIED
;
2854 else if (val
& (WPA2_AUTH_PSK
| WPA2_AUTH_UNSPECIFIED
)) {
2855 if (paramval
& IW_AUTH_KEY_MGMT_PSK
)
2856 val
= WPA2_AUTH_PSK
;
2858 val
= WPA2_AUTH_UNSPECIFIED
;
2861 WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __func__
,
2863 error
= dev_wlc_intvar_set(dev
, "wpa_auth", val
);
2868 case IW_AUTH_TKIP_COUNTERMEASURES
:
2869 dev_wlc_bufvar_set(dev
, "tkip_countermeasures",
2870 (char *)¶mval
, 1);
2873 case IW_AUTH_80211_AUTH_ALG
:
2874 WL_INFORM(("Setting the D11auth %d\n", paramval
));
2875 if (paramval
== IW_AUTH_ALG_OPEN_SYSTEM
)
2877 else if (paramval
== IW_AUTH_ALG_SHARED_KEY
)
2879 else if (paramval
==
2880 (IW_AUTH_ALG_OPEN_SYSTEM
| IW_AUTH_ALG_SHARED_KEY
))
2885 error
= dev_wlc_intvar_set(dev
, "auth", val
);
2891 case IW_AUTH_WPA_ENABLED
:
2892 if (paramval
== 0) {
2895 error
= dev_wlc_intvar_get(dev
, "wsec", &val
);
2898 if (val
& (TKIP_ENABLED
| AES_ENABLED
)) {
2899 val
&= ~(TKIP_ENABLED
| AES_ENABLED
);
2900 dev_wlc_intvar_set(dev
, "wsec", val
);
2903 WL_INFORM(("%s: %d: setting wpa_auth to %d\n",
2904 __func__
, __LINE__
, val
));
2905 dev_wlc_intvar_set(dev
, "wpa_auth", 0);
2910 case IW_AUTH_DROP_UNENCRYPTED
:
2911 dev_wlc_bufvar_set(dev
, "wsec_restrict", (char *)¶mval
, 1);
2914 case IW_AUTH_RX_UNENCRYPTED_EAPOL
:
2915 dev_wlc_bufvar_set(dev
, "rx_unencrypted_eapol",
2916 (char *)¶mval
, 1);
2919 #if WIRELESS_EXT > 17
2920 case IW_AUTH_ROAMING_CONTROL
:
2921 WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__
));
2923 case IW_AUTH_PRIVACY_INVOKED
:
2927 if (paramval
== 0) {
2928 iw
->privacy_invoked
= FALSE
;
2929 error
= dev_wlc_intvar_set(dev
,
2930 "is_WPS_enrollee", FALSE
);
2932 WL_WSEC(("Failed to clear iovar "
2933 "is_WPS_enrollee\n"));
2937 iw
->privacy_invoked
= TRUE
;
2938 error
= dev_wlc_intvar_get(dev
, "wsec", &wsec
);
2942 if (!(IW_WSEC_ENABLED(wsec
))) {
2943 error
= dev_wlc_intvar_set(dev
,
2947 WL_WSEC(("Failed to set iovar "
2948 "is_WPS_enrollee\n"));
2952 error
= dev_wlc_intvar_set(dev
,
2956 WL_WSEC(("Failed to clear "
2957 "is_WPS_enrollee\n"));
2964 #endif /* WIRELESS_EXT > 17 */
2972 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
2974 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK))
2978 wl_iw_get_wpaauth(struct net_device
*dev
,
2979 struct iw_request_info
*info
,
2980 struct iw_param
*vwrq
, char *extra
)
2986 wl_iw_t
*iw
= *(wl_iw_t
**) netdev_priv(dev
);
2988 WL_TRACE(("%s: SIOCGIWAUTH\n", dev
->name
));
2990 paramid
= vwrq
->flags
& IW_AUTH_INDEX
;
2993 case IW_AUTH_WPA_VERSION
:
2994 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
2997 if (val
& (WPA_AUTH_NONE
| WPA_AUTH_DISABLED
))
2998 paramval
= IW_AUTH_WPA_VERSION_DISABLED
;
2999 else if (val
& (WPA_AUTH_PSK
| WPA_AUTH_UNSPECIFIED
))
3000 paramval
= IW_AUTH_WPA_VERSION_WPA
;
3002 else if (val
& (WPA2_AUTH_PSK
| WPA2_AUTH_UNSPECIFIED
))
3003 paramval
= IW_AUTH_WPA_VERSION_WPA2
;
3006 case IW_AUTH_CIPHER_PAIRWISE
:
3007 case IW_AUTH_CIPHER_GROUP
:
3008 if (paramid
== IW_AUTH_CIPHER_PAIRWISE
)
3015 if (val
& WEP_ENABLED
)
3017 (IW_AUTH_CIPHER_WEP40
|
3018 IW_AUTH_CIPHER_WEP104
);
3019 if (val
& TKIP_ENABLED
)
3020 paramval
|= (IW_AUTH_CIPHER_TKIP
);
3021 if (val
& AES_ENABLED
)
3022 paramval
|= (IW_AUTH_CIPHER_CCMP
);
3024 paramval
= IW_AUTH_CIPHER_NONE
;
3026 case IW_AUTH_KEY_MGMT
:
3027 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
3031 paramval
= IW_AUTH_KEY_MGMT_PSK
;
3033 paramval
= IW_AUTH_KEY_MGMT_802_1X
;
3036 case IW_AUTH_TKIP_COUNTERMEASURES
:
3037 dev_wlc_bufvar_get(dev
, "tkip_countermeasures",
3038 (char *)¶mval
, 1);
3041 case IW_AUTH_DROP_UNENCRYPTED
:
3042 dev_wlc_bufvar_get(dev
, "wsec_restrict", (char *)¶mval
, 1);
3045 case IW_AUTH_RX_UNENCRYPTED_EAPOL
:
3046 dev_wlc_bufvar_get(dev
, "rx_unencrypted_eapol",
3047 (char *)¶mval
, 1);
3050 case IW_AUTH_80211_AUTH_ALG
:
3051 error
= dev_wlc_intvar_get(dev
, "auth", &val
);
3055 paramval
= IW_AUTH_ALG_OPEN_SYSTEM
;
3057 paramval
= IW_AUTH_ALG_SHARED_KEY
;
3059 case IW_AUTH_WPA_ENABLED
:
3060 error
= dev_wlc_intvar_get(dev
, "wpa_auth", &val
);
3068 #if WIRELESS_EXT > 17
3069 case IW_AUTH_ROAMING_CONTROL
:
3070 WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__
));
3072 case IW_AUTH_PRIVACY_INVOKED
:
3073 paramval
= iw
->privacy_invoked
;
3078 vwrq
->value
= paramval
;
3081 #endif /* WIRELESS_EXT > 17 */
3083 static const iw_handler wl_iw_handler
[] = {
3084 (iw_handler
) wl_iw_config_commit
,
3085 (iw_handler
) wl_iw_get_name
,
3088 (iw_handler
) wl_iw_set_freq
,
3089 (iw_handler
) wl_iw_get_freq
,
3090 (iw_handler
) wl_iw_set_mode
,
3091 (iw_handler
) wl_iw_get_mode
,
3095 (iw_handler
) wl_iw_get_range
,
3100 (iw_handler
) wl_iw_set_spy
,
3101 (iw_handler
) wl_iw_get_spy
,
3104 (iw_handler
) wl_iw_set_wap
,
3105 (iw_handler
) wl_iw_get_wap
,
3106 #if WIRELESS_EXT > 17
3107 (iw_handler
) wl_iw_mlme
,
3111 #if defined(WL_IW_USE_ISCAN)
3112 (iw_handler
) wl_iw_iscan_get_aplist
,
3114 (iw_handler
) wl_iw_get_aplist
,
3116 #if WIRELESS_EXT > 13
3117 #if defined(WL_IW_USE_ISCAN)
3118 (iw_handler
) wl_iw_iscan_set_scan
,
3119 (iw_handler
) wl_iw_iscan_get_scan
,
3121 (iw_handler
) wl_iw_set_scan
,
3122 (iw_handler
) wl_iw_get_scan
,
3127 #endif /* WIRELESS_EXT > 13 */
3128 (iw_handler
) wl_iw_set_essid
,
3129 (iw_handler
) wl_iw_get_essid
,
3130 (iw_handler
) wl_iw_set_nick
,
3131 (iw_handler
) wl_iw_get_nick
,
3134 (iw_handler
) wl_iw_set_rate
,
3135 (iw_handler
) wl_iw_get_rate
,
3136 (iw_handler
) wl_iw_set_rts
,
3137 (iw_handler
) wl_iw_get_rts
,
3138 (iw_handler
) wl_iw_set_frag
,
3139 (iw_handler
) wl_iw_get_frag
,
3140 (iw_handler
) wl_iw_set_txpow
,
3141 (iw_handler
) wl_iw_get_txpow
,
3142 #if WIRELESS_EXT > 10
3143 (iw_handler
) wl_iw_set_retry
,
3144 (iw_handler
) wl_iw_get_retry
,
3146 (iw_handler
) wl_iw_set_encode
,
3147 (iw_handler
) wl_iw_get_encode
,
3148 (iw_handler
) wl_iw_set_power
,
3149 (iw_handler
) wl_iw_get_power
,
3150 #if WIRELESS_EXT > 17
3153 (iw_handler
) wl_iw_set_wpaie
,
3154 (iw_handler
) wl_iw_get_wpaie
,
3155 (iw_handler
) wl_iw_set_wpaauth
,
3156 (iw_handler
) wl_iw_get_wpaauth
,
3157 (iw_handler
) wl_iw_set_encodeext
,
3158 (iw_handler
) wl_iw_get_encodeext
,
3160 (iw_handler
) wl_iw_set_pmksa
,
3162 #endif /* WIRELESS_EXT > 17 */
3165 #if WIRELESS_EXT > 12
3167 const struct iw_handler_def wl_iw_handler_def
= {
3168 .num_standard
= ARRAYSIZE(wl_iw_handler
),
3169 .standard
= (iw_handler
*) wl_iw_handler
,
3171 .num_private_args
= 0,
3175 #if WIRELESS_EXT >= 19
3176 .get_wireless_stats
= dhd_get_wireless_stats
,
3179 #endif /* WIRELESS_EXT > 12 */
3181 int wl_iw_ioctl(struct net_device
*dev
, struct ifreq
*rq
, int cmd
)
3183 struct iwreq
*wrq
= (struct iwreq
*)rq
;
3184 struct iw_request_info info
;
3187 int token_size
= 1, max_tokens
= 0, ret
= 0;
3189 WL_TRACE(("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
3191 if (cmd
< SIOCIWFIRST
||
3192 IW_IOCTL_IDX(cmd
) >= ARRAYSIZE(wl_iw_handler
)) {
3193 WL_ERROR(("%s: error in cmd=%x : out of range\n", __func__
,
3198 handler
= wl_iw_handler
[IW_IOCTL_IDX(cmd
)];
3200 WL_ERROR(("%s: error in cmd=%x : not supported\n",
3211 max_tokens
= IW_ESSID_MAX_SIZE
+ 1;
3216 #if WIRELESS_EXT > 17
3217 case SIOCSIWENCODEEXT
:
3218 case SIOCGIWENCODEEXT
:
3220 max_tokens
= wrq
->u
.data
.length
;
3224 max_tokens
= sizeof(struct iw_range
) + 500;
3229 sizeof(struct sockaddr
) + sizeof(struct iw_quality
);
3230 max_tokens
= IW_MAX_AP
;
3233 #if WIRELESS_EXT > 13
3235 #if defined(WL_IW_USE_ISCAN)
3237 max_tokens
= wrq
->u
.data
.length
;
3240 max_tokens
= IW_SCAN_MAX_DATA
;
3242 #endif /* WIRELESS_EXT > 13 */
3245 token_size
= sizeof(struct sockaddr
);
3246 max_tokens
= IW_MAX_SPY
;
3251 sizeof(struct sockaddr
) + sizeof(struct iw_quality
);
3252 max_tokens
= IW_MAX_SPY
;
3255 #if WIRELESS_EXT > 17
3260 max_tokens
= wrq
->u
.data
.length
;
3264 if (max_tokens
&& wrq
->u
.data
.pointer
) {
3265 if (wrq
->u
.data
.length
> max_tokens
) {
3266 WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d "
3267 "> max_tokens=%d\n",
3268 __func__
, cmd
, wrq
->u
.data
.length
, max_tokens
));
3271 extra
= kmalloc(max_tokens
* token_size
, GFP_KERNEL
);
3276 (extra
, wrq
->u
.data
.pointer
,
3277 wrq
->u
.data
.length
* token_size
)) {
3286 ret
= handler(dev
, &info
, &wrq
->u
, extra
);
3290 (wrq
->u
.data
.pointer
, extra
,
3291 wrq
->u
.data
.length
* token_size
)) {
3303 wl_iw_conn_status_str(uint32 event_type
, uint32 status
, uint32 reason
,
3304 char *stringBuf
, uint buflen
)
3306 typedef struct conn_fail_event_map_t
{
3310 const char *outName
;
3311 const char *outCause
;
3312 } conn_fail_event_map_t
;
3314 #define WL_IW_DONT_CARE 9999
3315 const conn_fail_event_map_t event_map
[] = {
3316 {WLC_E_SET_SSID
, WLC_E_STATUS_SUCCESS
, WL_IW_DONT_CARE
,
3318 {WLC_E_SET_SSID
, WLC_E_STATUS_NO_NETWORKS
, WL_IW_DONT_CARE
,
3319 "Conn", "NoNetworks"},
3320 {WLC_E_SET_SSID
, WLC_E_STATUS_FAIL
, WL_IW_DONT_CARE
,
3321 "Conn", "ConfigMismatch"},
3322 {WLC_E_PRUNE
, WL_IW_DONT_CARE
, WLC_E_PRUNE_ENCR_MISMATCH
,
3323 "Conn", "EncrypMismatch"},
3324 {WLC_E_PRUNE
, WL_IW_DONT_CARE
, WLC_E_RSN_MISMATCH
,
3325 "Conn", "RsnMismatch"},
3326 {WLC_E_AUTH
, WLC_E_STATUS_TIMEOUT
, WL_IW_DONT_CARE
,
3327 "Conn", "AuthTimeout"},
3328 {WLC_E_AUTH
, WLC_E_STATUS_FAIL
, WL_IW_DONT_CARE
,
3329 "Conn", "AuthFail"},
3330 {WLC_E_AUTH
, WLC_E_STATUS_NO_ACK
, WL_IW_DONT_CARE
,
3331 "Conn", "AuthNoAck"},
3332 {WLC_E_REASSOC
, WLC_E_STATUS_FAIL
, WL_IW_DONT_CARE
,
3333 "Conn", "ReassocFail"},
3334 {WLC_E_REASSOC
, WLC_E_STATUS_TIMEOUT
, WL_IW_DONT_CARE
,
3335 "Conn", "ReassocTimeout"},
3336 {WLC_E_REASSOC
, WLC_E_STATUS_ABORT
, WL_IW_DONT_CARE
,
3337 "Conn", "ReassocAbort"},
3338 {WLC_E_PSK_SUP
, WLC_SUP_KEYED
, WL_IW_DONT_CARE
,
3339 "Sup", "ConnSuccess"},
3340 {WLC_E_PSK_SUP
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3341 "Sup", "WpaHandshakeFail"},
3342 {WLC_E_DEAUTH_IND
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3344 {WLC_E_DISASSOC_IND
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3345 "Conn", "DisassocInd"},
3346 {WLC_E_DISASSOC
, WL_IW_DONT_CARE
, WL_IW_DONT_CARE
,
3350 const char *name
= "";
3351 const char *cause
= NULL
;
3354 for (i
= 0; i
< sizeof(event_map
) / sizeof(event_map
[0]); i
++) {
3355 const conn_fail_event_map_t
*row
= &event_map
[i
];
3356 if (row
->inEvent
== event_type
&&
3357 (row
->inStatus
== status
3358 || row
->inStatus
== WL_IW_DONT_CARE
)
3359 && (row
->inReason
== reason
3360 || row
->inReason
== WL_IW_DONT_CARE
)) {
3361 name
= row
->outName
;
3362 cause
= row
->outCause
;
3368 memset(stringBuf
, 0, buflen
);
3369 snprintf(stringBuf
, buflen
, "%s %s %02d %02d",
3370 name
, cause
, status
, reason
);
3371 WL_INFORM(("Connection status: %s\n", stringBuf
));
3378 #if WIRELESS_EXT > 14
3381 wl_iw_check_conn_fail(wl_event_msg_t
*e
, char *stringBuf
, uint buflen
)
3383 uint32 event
= ntoh32(e
->event_type
);
3384 uint32 status
= ntoh32(e
->status
);
3385 uint32 reason
= ntoh32(e
->reason
);
3387 if (wl_iw_conn_status_str(event
, status
, reason
, stringBuf
, buflen
)) {
3394 #ifndef IW_CUSTOM_MAX
3395 #define IW_CUSTOM_MAX 256
3398 void wl_iw_event(struct net_device
*dev
, wl_event_msg_t
*e
, void *data
)
3400 #if WIRELESS_EXT > 13
3401 union iwreq_data wrqu
;
3402 char extra
[IW_CUSTOM_MAX
+ 1];
3404 uint32 event_type
= ntoh32(e
->event_type
);
3405 uint16 flags
= ntoh16(e
->flags
);
3406 uint32 datalen
= ntoh32(e
->datalen
);
3407 uint32 status
= ntoh32(e
->status
);
3410 memset(&wrqu
, 0, sizeof(wrqu
));
3411 memset(extra
, 0, sizeof(extra
));
3415 WL_ERROR(("%s: dev is null\n", __func__
));
3419 iw
= *(wl_iw_t
**) netdev_priv(dev
);
3421 WL_TRACE(("%s: dev=%s event=%d\n", __func__
, dev
->name
, event_type
));
3423 switch (event_type
) {
3426 memcpy(wrqu
.addr
.sa_data
, &e
->addr
, ETHER_ADDR_LEN
);
3427 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3429 #if WIRELESS_EXT > 14
3431 case WLC_E_ASSOC_IND
:
3432 case WLC_E_REASSOC_IND
:
3433 memcpy(wrqu
.addr
.sa_data
, &e
->addr
, ETHER_ADDR_LEN
);
3434 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3435 cmd
= IWEVREGISTERED
;
3437 case WLC_E_DEAUTH_IND
:
3438 case WLC_E_DISASSOC_IND
:
3440 bzero(wrqu
.addr
.sa_data
, ETHER_ADDR_LEN
);
3441 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3442 bzero(&extra
, ETHER_ADDR_LEN
);
3445 case WLC_E_NDIS_LINK
:
3447 if (!(flags
& WLC_EVENT_MSG_LINK
)) {
3448 bzero(wrqu
.addr
.sa_data
, ETHER_ADDR_LEN
);
3449 bzero(&extra
, ETHER_ADDR_LEN
);
3450 WAKE_LOCK_TIMEOUT(iw
->pub
, WAKE_LOCK_LINK_DOWN_TMOUT
,
3453 memcpy(wrqu
.addr
.sa_data
, &e
->addr
, ETHER_ADDR_LEN
);
3454 WL_TRACE(("Link UP\n"));
3457 wrqu
.addr
.sa_family
= ARPHRD_ETHER
;
3459 case WLC_E_ACTION_FRAME
:
3461 if (datalen
+ 1 <= sizeof(extra
)) {
3462 wrqu
.data
.length
= datalen
+ 1;
3463 extra
[0] = WLC_E_ACTION_FRAME
;
3464 memcpy(&extra
[1], data
, datalen
);
3465 WL_TRACE(("WLC_E_ACTION_FRAME len %d \n",
3470 case WLC_E_ACTION_FRAME_COMPLETE
:
3472 memcpy(&toto
, data
, 4);
3473 if (sizeof(status
) + 1 <= sizeof(extra
)) {
3474 wrqu
.data
.length
= sizeof(status
) + 1;
3475 extra
[0] = WLC_E_ACTION_FRAME_COMPLETE
;
3476 memcpy(&extra
[1], &status
, sizeof(status
));
3477 printf("wl_iw_event status %d PacketId %d\n", status
,
3479 printf("WLC_E_ACTION_FRAME_COMPLETE len %d\n",
3483 #endif /* WIRELESS_EXT > 14 */
3484 #if WIRELESS_EXT > 17
3485 case WLC_E_MIC_ERROR
:
3487 struct iw_michaelmicfailure
*micerrevt
=
3488 (struct iw_michaelmicfailure
*)&extra
;
3489 cmd
= IWEVMICHAELMICFAILURE
;
3490 wrqu
.data
.length
= sizeof(struct iw_michaelmicfailure
);
3491 if (flags
& WLC_EVENT_MSG_GROUP
)
3492 micerrevt
->flags
|= IW_MICFAILURE_GROUP
;
3494 micerrevt
->flags
|= IW_MICFAILURE_PAIRWISE
;
3495 memcpy(micerrevt
->src_addr
.sa_data
, &e
->addr
,
3497 micerrevt
->src_addr
.sa_family
= ARPHRD_ETHER
;
3502 case WLC_E_PMKID_CACHE
:
3505 struct iw_pmkid_cand
*iwpmkidcand
=
3506 (struct iw_pmkid_cand
*)&extra
;
3507 pmkid_cand_list_t
*pmkcandlist
;
3508 pmkid_cand_t
*pmkidcand
;
3511 cmd
= IWEVPMKIDCAND
;
3515 pmkcandlist
->npmkid_cand
);
3517 wrqu
.data
.length
= sizeof(struct iw_pmkid_cand
);
3518 pmkidcand
= pmkcandlist
->pmkid_cand
;
3521 sizeof(struct iw_pmkid_cand
));
3522 if (pmkidcand
->preauth
)
3523 iwpmkidcand
->flags
|=
3524 IW_PMKID_CAND_PREAUTH
;
3525 bcopy(&pmkidcand
->BSSID
,
3526 &iwpmkidcand
->bssid
.sa_data
,
3529 wireless_send_event(dev
, cmd
, &wrqu
,
3538 #endif /* BCMWPA2 */
3539 #endif /* WIRELESS_EXT > 17 */
3541 case WLC_E_SCAN_COMPLETE
:
3542 #if defined(WL_IW_USE_ISCAN)
3543 if ((g_iscan
) && (g_iscan
->sysioc_pid
> 0) &&
3544 (g_iscan
->iscan_state
!= ISCAN_STATE_IDLE
)) {
3545 up(&g_iscan
->sysioc_sem
);
3548 wrqu
.data
.length
= strlen(extra
);
3549 WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific "
3550 "scan %d\n", g_iscan
->iscan_state
));
3554 wrqu
.data
.length
= strlen(extra
);
3555 WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
3559 case WLC_E_PFN_NET_FOUND
:
3562 ssid
= (wlc_ssid_t
*) data
;
3563 WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : "
3564 "find %s len=%d\n", __func__
, PNO_EVENT_UP
,
3565 ssid
->SSID
, ssid
->SSID_len
));
3566 WAKE_LOCK_TIMEOUT(iw
->pub
, WAKE_LOCK_PNO_FIND_TMOUT
,
3569 memset(&wrqu
, 0, sizeof(wrqu
));
3570 strcpy(extra
, PNO_EVENT_UP
);
3571 wrqu
.data
.length
= strlen(extra
);
3576 WL_TRACE(("Unknown Event %d: ignoring\n", event_type
));
3581 if (cmd
== SIOCGIWSCAN
)
3582 wireless_send_event(dev
, cmd
, &wrqu
, NULL
);
3584 wireless_send_event(dev
, cmd
, &wrqu
, extra
);
3588 #if WIRELESS_EXT > 14
3589 memset(extra
, 0, sizeof(extra
));
3590 if (wl_iw_check_conn_fail(e
, extra
, sizeof(extra
))) {
3592 wrqu
.data
.length
= strlen(extra
);
3594 wireless_send_event(dev
, cmd
, &wrqu
, extra
);
3597 #endif /* WIRELESS_EXT > 14 */
3598 #endif /* WIRELESS_EXT > 13 */
3602 wl_iw_get_wireless_stats(struct net_device
*dev
, struct iw_statistics
*wstats
)
3611 res
= dev_wlc_ioctl(dev
, WLC_GET_PHY_NOISE
, &phy_noise
,
3616 phy_noise
= dtoh32(phy_noise
);
3617 WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise
));
3619 bzero(&scb_val
, sizeof(scb_val_t
));
3620 res
= dev_wlc_ioctl(dev
, WLC_GET_RSSI
, &scb_val
, sizeof(scb_val_t
));
3624 rssi
= dtoh32(scb_val
.val
);
3625 WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi
));
3626 if (rssi
<= WL_IW_RSSI_NO_SIGNAL
)
3627 wstats
->qual
.qual
= 0;
3628 else if (rssi
<= WL_IW_RSSI_VERY_LOW
)
3629 wstats
->qual
.qual
= 1;
3630 else if (rssi
<= WL_IW_RSSI_LOW
)
3631 wstats
->qual
.qual
= 2;
3632 else if (rssi
<= WL_IW_RSSI_GOOD
)
3633 wstats
->qual
.qual
= 3;
3634 else if (rssi
<= WL_IW_RSSI_VERY_GOOD
)
3635 wstats
->qual
.qual
= 4;
3637 wstats
->qual
.qual
= 5;
3639 wstats
->qual
.level
= 0x100 + rssi
;
3640 wstats
->qual
.noise
= 0x100 + phy_noise
;
3641 #if WIRELESS_EXT > 18
3642 wstats
->qual
.updated
|= (IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
);
3644 wstats
->qual
.updated
|= 7;
3647 #if WIRELESS_EXT > 11
3648 WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n",
3649 (int)sizeof(wl_cnt_t
)));
3651 memset(&cnt
, 0, sizeof(wl_cnt_t
));
3653 dev_wlc_bufvar_get(dev
, "counters", (char *)&cnt
, sizeof(wl_cnt_t
));
3655 WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n",
3660 cnt
.version
= dtoh16(cnt
.version
);
3661 if (cnt
.version
!= WL_CNT_T_VERSION
) {
3662 WL_TRACE(("\tIncorrect version of counters struct: expected "
3664 WL_CNT_T_VERSION
, cnt
.version
));
3668 wstats
->discard
.nwid
= 0;
3669 wstats
->discard
.code
= dtoh32(cnt
.rxundec
);
3670 wstats
->discard
.fragment
= dtoh32(cnt
.rxfragerr
);
3671 wstats
->discard
.retries
= dtoh32(cnt
.txfail
);
3672 wstats
->discard
.misc
= dtoh32(cnt
.rxrunt
) + dtoh32(cnt
.rxgiant
);
3673 wstats
->miss
.beacon
= 0;
3675 WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
3676 dtoh32(cnt
.txframe
), dtoh32(cnt
.txbyte
)));
3677 WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n",
3678 dtoh32(cnt
.rxfrmtoolong
)));
3679 WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n",
3680 dtoh32(cnt
.rxbadplcp
)));
3681 WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n",
3682 dtoh32(cnt
.rxundec
)));
3683 WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n",
3684 dtoh32(cnt
.rxfragerr
)));
3685 WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n",
3686 dtoh32(cnt
.txfail
)));
3687 WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n",
3688 dtoh32(cnt
.rxrunt
)));
3689 WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n",
3690 dtoh32(cnt
.rxgiant
)));
3691 #endif /* WIRELESS_EXT > 11 */
3697 int wl_iw_attach(struct net_device
*dev
, void *dhdp
)
3701 #if defined(WL_IW_USE_ISCAN)
3702 iscan_info_t
*iscan
= NULL
;
3707 memset(&g_wl_iw_params
, 0, sizeof(wl_iw_extra_params_t
));
3711 (WL_SCAN_PARAMS_FIXED_SIZE
+ OFFSETOF(wl_iscan_params_t
, params
)) +
3712 (WL_NUMCHANNELS
* sizeof(uint16
)) +
3713 WL_SCAN_PARAMS_SSID_MAX
* sizeof(wlc_ssid_t
);
3716 (WL_SCAN_PARAMS_FIXED_SIZE
+ OFFSETOF(wl_iscan_params_t
, params
));
3718 iscan
= kmalloc(sizeof(iscan_info_t
), GFP_KERNEL
);
3722 memset(iscan
, 0, sizeof(iscan_info_t
));
3724 iscan
->iscan_ex_params_p
=
3725 (wl_iscan_params_t
*) kmalloc(params_size
, GFP_KERNEL
);
3726 if (!iscan
->iscan_ex_params_p
)
3728 iscan
->iscan_ex_param_size
= params_size
;
3729 iscan
->sysioc_pid
= -1;
3733 iscan
->iscan_state
= ISCAN_STATE_IDLE
;
3735 iscan
->timer_ms
= 3000;
3736 init_timer(&iscan
->timer
);
3737 iscan
->timer
.data
= (unsigned long) iscan
;
3738 iscan
->timer
.function
= wl_iw_timerfunc
;
3740 sema_init(&iscan
->sysioc_sem
, 0);
3741 init_completion(&iscan
->sysioc_exited
);
3742 iscan
->sysioc_pid
= kernel_thread(_iscan_sysioc_thread
, iscan
, 0);
3743 if (iscan
->sysioc_pid
< 0)
3745 #endif /* defined(WL_IW_USE_ISCAN) */
3747 iw
= *(wl_iw_t
**) netdev_priv(dev
);
3748 iw
->pub
= (dhd_pub_t
*) dhdp
;
3749 MUTEX_LOCK_INIT(iw
->pub
);
3750 MUTEX_LOCK_WL_SCAN_SET_INIT();
3753 MUTEX_LOCK_SOFTAP_SET_INIT(iw
->pub
);
3757 g_scan
= (void *)kmalloc(G_SCAN_RESULTS
, GFP_KERNEL
);
3761 memset(g_scan
, 0, G_SCAN_RESULTS
);
3762 g_scan_specified_ssid
= 0;
3767 void wl_iw_detach(void)
3769 #if defined(WL_IW_USE_ISCAN)
3771 iscan_info_t
*iscan
= g_iscan
;
3775 if (iscan
->sysioc_pid
>= 0) {
3776 KILL_PROC(iscan
->sysioc_pid
, SIGTERM
);
3777 wait_for_completion(&iscan
->sysioc_exited
);
3779 MUTEX_LOCK_WL_SCAN_SET();
3780 while (iscan
->list_hdr
) {
3781 buf
= iscan
->list_hdr
->next
;
3782 kfree(iscan
->list_hdr
);
3783 iscan
->list_hdr
= buf
;
3785 MUTEX_UNLOCK_WL_SCAN_SET();
3786 kfree(iscan
->iscan_ex_params_p
);
3789 #endif /* WL_IW_USE_ISCAN */