2 * WPA Supplicant - driver interaction with old Broadcom wl.o driver
3 * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
4 * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
15 * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
16 * Linux wireless extensions and does not need (or even work) with this old
17 * driver wrapper. Use driver_wext.c with that driver.
22 #include <sys/ioctl.h>
27 #include <netpacket/packet.h>
28 #include <net/ethernet.h> /* the L2 protocols */
30 #include <linux/if_packet.h>
31 #include <linux/if_ether.h> /* The L2 protocols */
36 /* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
37 * WRT54G GPL tarball. */
43 struct wpa_driver_broadcom_data
{
47 char ifname
[IFNAMSIZ
+ 1];
51 #ifndef WLC_DEAUTHENTICATE
52 #define WLC_DEAUTHENTICATE 143
54 #ifndef WLC_DEAUTHENTICATE_WITH_REASON
55 #define WLC_DEAUTHENTICATE_WITH_REASON 201
57 #ifndef WLC_SET_TKIP_COUNTERMEASURES
58 #define WLC_SET_TKIP_COUNTERMEASURES 202
61 #if !defined(PSK_ENABLED) /* NEW driver interface */
62 #define WL_VERSION 360130
63 /* wireless authentication bit vector */
67 #define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
68 #define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
69 #define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
71 #define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
73 typedef wl_wsec_key_t wsec_key_t
;
83 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx
,
86 static int broadcom_ioctl(struct wpa_driver_broadcom_data
*drv
, int cmd
,
93 wpa_printf(MSG_MSGDUMP
, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
94 drv
->ifname
, cmd
, len
, buf
);
95 /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
100 os_strlcpy(ifr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
101 ifr
.ifr_data
= (caddr_t
) &ioc
;
102 if ((ret
= ioctl(drv
->ioctl_sock
, SIOCDEVPRIVATE
, &ifr
)) < 0) {
103 if (cmd
!= WLC_GET_MAGIC
)
104 perror(ifr
.ifr_name
);
105 wpa_printf(MSG_MSGDUMP
, "BROADCOM: wlioctl cmd=%d res=%d",
112 static int wpa_driver_broadcom_get_bssid(void *priv
, u8
*bssid
)
114 struct wpa_driver_broadcom_data
*drv
= priv
;
115 if (broadcom_ioctl(drv
, WLC_GET_BSSID
, bssid
, ETH_ALEN
) == 0)
118 os_memset(bssid
, 0, ETH_ALEN
);
122 static int wpa_driver_broadcom_get_ssid(void *priv
, u8
*ssid
)
124 struct wpa_driver_broadcom_data
*drv
= priv
;
127 if (broadcom_ioctl(drv
, WLC_GET_SSID
, &s
, sizeof(s
)) == -1)
130 os_memcpy(ssid
, s
.SSID
, s
.SSID_len
);
134 static int wpa_driver_broadcom_set_wpa(void *priv
, int enable
)
136 struct wpa_driver_broadcom_data
*drv
= priv
;
137 unsigned int wauth
, wsec
;
138 struct ether_addr ea
;
140 os_memset(&ea
, enable
? 0xff : 0, sizeof(ea
));
141 if (broadcom_ioctl(drv
, WLC_GET_WPA_AUTH
, &wauth
, sizeof(wauth
)) ==
143 broadcom_ioctl(drv
, WLC_GET_WSEC
, &wsec
, sizeof(wsec
)) == -1)
151 wsec
&= ~(TKIP_ENABLED
| AES_ENABLED
);
154 if (broadcom_ioctl(drv
, WLC_SET_WPA_AUTH
, &wauth
, sizeof(wauth
)) ==
156 broadcom_ioctl(drv
, WLC_SET_WSEC
, &wsec
, sizeof(wsec
)) == -1)
159 /* FIX: magic number / error handling? */
160 broadcom_ioctl(drv
, 122, &ea
, sizeof(ea
));
165 static int wpa_driver_broadcom_set_key(const char *ifname
, void *priv
,
167 const u8
*addr
, int key_idx
, int set_tx
,
168 const u8
*seq
, size_t seq_len
,
169 const u8
*key
, size_t key_len
)
171 struct wpa_driver_broadcom_data
*drv
= priv
;
175 os_memset(&wkt
, 0, sizeof wkt
);
176 wpa_printf(MSG_MSGDUMP
, "BROADCOM: SET %sKEY[%d] alg=%d",
177 set_tx
? "PRIMARY " : "", key_idx
, alg
);
178 if (key
&& key_len
> 0)
179 wpa_hexdump_key(MSG_MSGDUMP
, "BROADCOM: key", key
, key_len
);
183 wkt
.algo
= CRYPTO_ALGO_OFF
;
186 wkt
.algo
= CRYPTO_ALGO_WEP128
; /* CRYPTO_ALGO_WEP1? */
189 wkt
.algo
= 0; /* CRYPTO_ALGO_TKIP? */
192 wkt
.algo
= 0; /* CRYPTO_ALGO_AES_CCM;
193 * AES_OCB_MSDU, AES_OCB_MPDU? */
196 wkt
.algo
= CRYPTO_ALGO_NALG
;
200 if (seq
&& seq_len
> 0)
201 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: SEQ", seq
, seq_len
);
204 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: addr", addr
, ETH_ALEN
);
208 if (key
&& key_len
> 0) {
209 os_memcpy(wkt
.data
, key
, key_len
);
211 /* hack hack hack XXX */
212 os_memcpy(&wkt
.data
[16], &key
[24], 8);
213 os_memcpy(&wkt
.data
[24], &key
[16], 8);
216 /* wkt.algo = CRYPTO_ALGO_...; */
217 wkt
.flags
= set_tx
? 0 : WSEC_PRIMARY_KEY
;
219 os_memcpy(&wkt
.ea
, addr
, sizeof(wkt
.ea
));
220 ret
= broadcom_ioctl(drv
, WLC_SET_KEY
, &wkt
, sizeof(wkt
));
221 if (addr
&& set_tx
) {
222 /* FIX: magic number / error handling? */
223 broadcom_ioctl(drv
, 121, &wkt
.ea
, sizeof(wkt
.ea
));
229 static void wpa_driver_broadcom_event_receive(int sock
, void *ctx
,
234 wl_wpa_header_t
*wwh
;
235 union wpa_event_data data
;
238 if ((left
= recv(sock
, buf
, sizeof buf
, 0)) < 0)
241 wpa_hexdump(MSG_DEBUG
, "RECEIVE EVENT", (u8
*) buf
, left
);
243 if ((size_t) left
< sizeof(wl_wpa_header_t
))
246 wwh
= (wl_wpa_header_t
*) buf
;
248 if (wwh
->snap
.type
!= WL_WPA_ETHER_TYPE
)
250 if (os_memcmp(&wwh
->snap
, wl_wpa_snap_template
, 6) != 0)
253 os_memset(&data
, 0, sizeof(data
));
257 left
-= WL_WPA_HEADER_LEN
;
258 wpa_printf(MSG_DEBUG
, "BROADCOM: ASSOC MESSAGE (left: %d)",
261 resp_ies
= os_malloc(left
);
262 if (resp_ies
== NULL
)
264 os_memcpy(resp_ies
, buf
+ WL_WPA_HEADER_LEN
, left
);
265 data
.assoc_info
.resp_ies
= resp_ies
;
266 data
.assoc_info
.resp_ies_len
= left
;
269 wpa_supplicant_event(ctx
, EVENT_ASSOC
, &data
);
272 case WLC_DISASSOC_MSG
:
273 wpa_printf(MSG_DEBUG
, "BROADCOM: DISASSOC MESSAGE");
274 wpa_supplicant_event(ctx
, EVENT_DISASSOC
, NULL
);
276 case WLC_PTK_MIC_MSG
:
277 wpa_printf(MSG_DEBUG
, "BROADCOM: PTK MIC MSG MESSAGE");
278 data
.michael_mic_failure
.unicast
= 1;
279 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
281 case WLC_GTK_MIC_MSG
:
282 wpa_printf(MSG_DEBUG
, "BROADCOM: GTK MIC MSG MESSAGE");
283 data
.michael_mic_failure
.unicast
= 0;
284 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
287 wpa_printf(MSG_DEBUG
, "BROADCOM: UNKNOWN MESSAGE (%d)",
293 static void * wpa_driver_broadcom_init(void *ctx
, const char *ifname
)
296 struct sockaddr_ll ll
;
297 struct wpa_driver_broadcom_data
*drv
;
300 /* open socket to kernel */
301 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
306 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
307 if (ioctl(s
, SIOCGIFINDEX
, &ifr
) < 0) {
308 perror(ifr
.ifr_name
);
313 drv
= os_zalloc(sizeof(*drv
));
317 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
320 s
= socket(PF_PACKET
, SOCK_RAW
, ntohs(ETH_P_802_2
));
322 perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
323 close(drv
->ioctl_sock
);
328 os_memset(&ll
, 0, sizeof(ll
));
329 ll
.sll_family
= AF_PACKET
;
330 ll
.sll_protocol
= ntohs(ETH_P_802_2
);
331 ll
.sll_ifindex
= ifr
.ifr_ifindex
;
333 ll
.sll_pkttype
= PACKET_HOST
;
336 if (bind(s
, (struct sockaddr
*) &ll
, sizeof(ll
)) < 0) {
337 perror("bind(netlink)");
339 close(drv
->ioctl_sock
);
344 eloop_register_read_sock(s
, wpa_driver_broadcom_event_receive
, ctx
,
347 wpa_driver_broadcom_set_wpa(drv
, 1);
352 static void wpa_driver_broadcom_deinit(void *priv
)
354 struct wpa_driver_broadcom_data
*drv
= priv
;
355 wpa_driver_broadcom_set_wpa(drv
, 0);
356 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout
, drv
, drv
->ctx
);
357 eloop_unregister_read_sock(drv
->event_sock
);
358 close(drv
->event_sock
);
359 close(drv
->ioctl_sock
);
363 static int wpa_driver_broadcom_set_countermeasures(void *priv
,
367 struct wpa_driver_broadcom_data
*drv
= priv
;
369 return broadcom_ioctl(drv
, WLC_SET_TKIP_COUNTERMEASURES
, &enabled
,
376 static int wpa_driver_broadcom_set_drop_unencrypted(void *priv
, int enabled
)
378 struct wpa_driver_broadcom_data
*drv
= priv
;
379 /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
380 int _restrict
= (enabled
? 1 : 0);
382 if (broadcom_ioctl(drv
, WLC_SET_WEP_RESTRICT
,
383 &_restrict
, sizeof(_restrict
)) < 0 ||
384 broadcom_ioctl(drv
, WLC_SET_EAP_RESTRICT
,
385 &_restrict
, sizeof(_restrict
)) < 0)
391 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx
,
394 wpa_printf(MSG_DEBUG
, "Scan timeout - try to get results");
395 wpa_supplicant_event(timeout_ctx
, EVENT_SCAN_RESULTS
, NULL
);
398 static int wpa_driver_broadcom_scan(void *priv
,
399 struct wpa_driver_scan_params
*params
)
401 struct wpa_driver_broadcom_data
*drv
= priv
;
402 wlc_ssid_t wst
= { 0, "" };
403 const u8
*ssid
= params
->ssids
[0].ssid
;
404 size_t ssid_len
= params
->ssids
[0].ssid_len
;
406 if (ssid
&& ssid_len
> 0 && ssid_len
<= sizeof(wst
.SSID
)) {
407 wst
.SSID_len
= ssid_len
;
408 os_memcpy(wst
.SSID
, ssid
, ssid_len
);
411 if (broadcom_ioctl(drv
, WLC_SCAN
, &wst
, sizeof(wst
)) < 0)
414 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout
, drv
, drv
->ctx
);
415 eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout
, drv
,
421 static const int frequency_list
[] = {
422 2412, 2417, 2422, 2427, 2432, 2437, 2442,
423 2447, 2452, 2457, 2462, 2467, 2472, 2484
432 } __attribute__ ((packed
));
434 static struct wpa_scan_results
*
435 wpa_driver_broadcom_get_scan_results(void *priv
)
437 struct wpa_driver_broadcom_data
*drv
= priv
;
439 wl_scan_results_t
*wsr
;
442 struct wpa_scan_results
*res
;
444 buf
= os_malloc(WLC_IOCTL_MAXLEN
);
448 wsr
= (wl_scan_results_t
*) buf
;
450 wsr
->buflen
= WLC_IOCTL_MAXLEN
- sizeof(wsr
);
454 if (broadcom_ioctl(drv
, WLC_SCAN_RESULTS
, buf
, WLC_IOCTL_MAXLEN
) < 0) {
459 res
= os_zalloc(sizeof(*res
));
465 res
->res
= os_zalloc(wsr
->count
* sizeof(struct wpa_scan_res
*));
466 if (res
->res
== NULL
) {
472 for (ap_num
= 0, wbi
= wsr
->bss_info
; ap_num
< wsr
->count
; ++ap_num
) {
473 struct wpa_scan_res
*r
;
474 r
= os_malloc(sizeof(*r
) + wbi
->ie_length
);
477 res
->res
[res
->num
++] = r
;
479 os_memcpy(r
->bssid
, &wbi
->BSSID
, ETH_ALEN
);
480 r
->freq
= frequency_list
[wbi
->channel
- 1];
482 os_memcpy(r
+ 1, wbi
+ 1, wbi
->ie_length
);
483 r
->ie_len
= wbi
->ie_length
;
485 wbi
= (wl_bss_info_t
*) ((u8
*) wbi
+ wbi
->length
);
488 wpa_printf(MSG_MSGDUMP
, "Received %d bytes of scan results (%lu "
490 wsr
->buflen
, (unsigned long) ap_num
);
496 static int wpa_driver_broadcom_deauthenticate(void *priv
, const u8
*addr
,
499 struct wpa_driver_broadcom_data
*drv
= priv
;
501 wdt
.val
= reason_code
;
502 os_memcpy(&wdt
.ea
, addr
, sizeof wdt
.ea
);
504 return broadcom_ioctl(drv
, WLC_DEAUTHENTICATE_WITH_REASON
, &wdt
,
508 static int wpa_driver_broadcom_disassociate(void *priv
, const u8
*addr
,
511 struct wpa_driver_broadcom_data
*drv
= priv
;
512 return broadcom_ioctl(drv
, WLC_DISASSOC
, NULL
, 0);
516 wpa_driver_broadcom_associate(void *priv
,
517 struct wpa_driver_associate_params
*params
)
519 struct wpa_driver_broadcom_data
*drv
= priv
;
528 ret
= wpa_driver_broadcom_set_drop_unencrypted(
529 drv
, params
->drop_unencrypted
);
531 s
.SSID_len
= params
->ssid_len
;
532 os_memcpy(s
.SSID
, params
->ssid
, params
->ssid_len
);
534 switch (params
->pairwise_suite
) {
553 switch (params
->key_mgmt_suite
) {
554 case KEY_MGMT_802_1X
:
567 /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
568 * group_suite, key_mgmt_suite);
569 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
570 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
572 if (broadcom_ioctl(drv
, WLC_SET_WSEC
, &wsec
, sizeof(wsec
)) < 0 ||
573 broadcom_ioctl(drv
, WLC_SET_WPA_AUTH
, &wpa_auth
,
574 sizeof(wpa_auth
)) < 0 ||
575 broadcom_ioctl(drv
, WLC_GET_WEP
, &dummy
, sizeof(dummy
)) < 0 ||
576 broadcom_ioctl(drv
, WLC_SET_INFRA
, &infra
, sizeof(infra
)) < 0 ||
577 broadcom_ioctl(drv
, WLC_SET_AUTH
, &auth
, sizeof(auth
)) < 0 ||
578 broadcom_ioctl(drv
, WLC_SET_WEP
, &wsec
, sizeof(wsec
)) < 0 ||
579 broadcom_ioctl(drv
, WLC_SET_SSID
, &s
, sizeof(s
)) < 0)
585 const struct wpa_driver_ops wpa_driver_broadcom_ops
= {
587 .desc
= "Broadcom wl.o driver",
588 .get_bssid
= wpa_driver_broadcom_get_bssid
,
589 .get_ssid
= wpa_driver_broadcom_get_ssid
,
590 .set_key
= wpa_driver_broadcom_set_key
,
591 .init
= wpa_driver_broadcom_init
,
592 .deinit
= wpa_driver_broadcom_deinit
,
593 .set_countermeasures
= wpa_driver_broadcom_set_countermeasures
,
594 .scan2
= wpa_driver_broadcom_scan
,
595 .get_scan_results2
= wpa_driver_broadcom_get_scan_results
,
596 .deauthenticate
= wpa_driver_broadcom_deauthenticate
,
597 .disassociate
= wpa_driver_broadcom_disassociate
,
598 .associate
= wpa_driver_broadcom_associate
,