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(void *priv
, wpa_alg alg
,
166 const u8
*addr
, int key_idx
, int set_tx
,
167 const u8
*seq
, size_t seq_len
,
168 const u8
*key
, size_t key_len
)
170 struct wpa_driver_broadcom_data
*drv
= priv
;
174 os_memset(&wkt
, 0, sizeof wkt
);
175 wpa_printf(MSG_MSGDUMP
, "BROADCOM: SET %sKEY[%d] alg=%d",
176 set_tx
? "PRIMARY " : "", key_idx
, alg
);
177 if (key
&& key_len
> 0)
178 wpa_hexdump_key(MSG_MSGDUMP
, "BROADCOM: key", key
, key_len
);
182 wkt
.algo
= CRYPTO_ALGO_OFF
;
185 wkt
.algo
= CRYPTO_ALGO_WEP128
; /* CRYPTO_ALGO_WEP1? */
188 wkt
.algo
= 0; /* CRYPTO_ALGO_TKIP? */
191 wkt
.algo
= 0; /* CRYPTO_ALGO_AES_CCM;
192 * AES_OCB_MSDU, AES_OCB_MPDU? */
195 wkt
.algo
= CRYPTO_ALGO_NALG
;
199 if (seq
&& seq_len
> 0)
200 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: SEQ", seq
, seq_len
);
203 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: addr", addr
, ETH_ALEN
);
207 if (key
&& key_len
> 0) {
208 os_memcpy(wkt
.data
, key
, key_len
);
210 /* hack hack hack XXX */
211 os_memcpy(&wkt
.data
[16], &key
[24], 8);
212 os_memcpy(&wkt
.data
[24], &key
[16], 8);
215 /* wkt.algo = CRYPTO_ALGO_...; */
216 wkt
.flags
= set_tx
? 0 : WSEC_PRIMARY_KEY
;
218 os_memcpy(&wkt
.ea
, addr
, sizeof(wkt
.ea
));
219 ret
= broadcom_ioctl(drv
, WLC_SET_KEY
, &wkt
, sizeof(wkt
));
220 if (addr
&& set_tx
) {
221 /* FIX: magic number / error handling? */
222 broadcom_ioctl(drv
, 121, &wkt
.ea
, sizeof(wkt
.ea
));
228 static void wpa_driver_broadcom_event_receive(int sock
, void *ctx
,
233 wl_wpa_header_t
*wwh
;
234 union wpa_event_data data
;
236 if ((left
= recv(sock
, buf
, sizeof buf
, 0)) < 0)
239 wpa_hexdump(MSG_DEBUG
, "RECEIVE EVENT", (u8
*) buf
, left
);
241 if ((size_t) left
< sizeof(wl_wpa_header_t
))
244 wwh
= (wl_wpa_header_t
*) buf
;
246 if (wwh
->snap
.type
!= WL_WPA_ETHER_TYPE
)
248 if (os_memcmp(&wwh
->snap
, wl_wpa_snap_template
, 6) != 0)
251 os_memset(&data
, 0, sizeof(data
));
255 left
-= WL_WPA_HEADER_LEN
;
256 wpa_printf(MSG_DEBUG
, "BROADCOM: ASSOC MESSAGE (left: %d)",
259 data
.assoc_info
.resp_ies
= os_malloc(left
);
260 if (data
.assoc_info
.resp_ies
== NULL
)
262 os_memcpy(data
.assoc_info
.resp_ies
,
263 buf
+ WL_WPA_HEADER_LEN
, left
);
264 data
.assoc_info
.resp_ies_len
= left
;
265 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: copying %d bytes "
267 data
.assoc_info
.resp_ies
, left
);
269 /* data.assoc_info.req_ies = NULL; */
270 /* data.assoc_info.req_ies_len = 0; */
272 wpa_supplicant_event(ctx
, EVENT_ASSOCINFO
, &data
);
273 wpa_supplicant_event(ctx
, EVENT_ASSOC
, NULL
);
275 case WLC_DISASSOC_MSG
:
276 wpa_printf(MSG_DEBUG
, "BROADCOM: DISASSOC MESSAGE");
277 wpa_supplicant_event(ctx
, EVENT_DISASSOC
, NULL
);
279 case WLC_PTK_MIC_MSG
:
280 wpa_printf(MSG_DEBUG
, "BROADCOM: PTK MIC MSG MESSAGE");
281 data
.michael_mic_failure
.unicast
= 1;
282 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
284 case WLC_GTK_MIC_MSG
:
285 wpa_printf(MSG_DEBUG
, "BROADCOM: GTK MIC MSG MESSAGE");
286 data
.michael_mic_failure
.unicast
= 0;
287 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
290 wpa_printf(MSG_DEBUG
, "BROADCOM: UNKNOWN MESSAGE (%d)",
294 os_free(data
.assoc_info
.resp_ies
);
297 static void * wpa_driver_broadcom_init(void *ctx
, const char *ifname
)
300 struct sockaddr_ll ll
;
301 struct wpa_driver_broadcom_data
*drv
;
304 /* open socket to kernel */
305 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
310 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
311 if (ioctl(s
, SIOCGIFINDEX
, &ifr
) < 0) {
312 perror(ifr
.ifr_name
);
317 drv
= os_zalloc(sizeof(*drv
));
321 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
324 s
= socket(PF_PACKET
, SOCK_RAW
, ntohs(ETH_P_802_2
));
326 perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
327 close(drv
->ioctl_sock
);
332 os_memset(&ll
, 0, sizeof(ll
));
333 ll
.sll_family
= AF_PACKET
;
334 ll
.sll_protocol
= ntohs(ETH_P_802_2
);
335 ll
.sll_ifindex
= ifr
.ifr_ifindex
;
337 ll
.sll_pkttype
= PACKET_HOST
;
340 if (bind(s
, (struct sockaddr
*) &ll
, sizeof(ll
)) < 0) {
341 perror("bind(netlink)");
343 close(drv
->ioctl_sock
);
348 eloop_register_read_sock(s
, wpa_driver_broadcom_event_receive
, ctx
,
355 static void wpa_driver_broadcom_deinit(void *priv
)
357 struct wpa_driver_broadcom_data
*drv
= priv
;
358 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout
, drv
, drv
->ctx
);
359 eloop_unregister_read_sock(drv
->event_sock
);
360 close(drv
->event_sock
);
361 close(drv
->ioctl_sock
);
365 static int wpa_driver_broadcom_set_countermeasures(void *priv
,
369 struct wpa_driver_broadcom_data
*drv
= priv
;
371 return broadcom_ioctl(drv
, WLC_SET_TKIP_COUNTERMEASURES
, &enabled
,
378 static int wpa_driver_broadcom_set_drop_unencrypted(void *priv
, int enabled
)
380 struct wpa_driver_broadcom_data
*drv
= priv
;
381 /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
382 int restrict
= (enabled
? 1 : 0);
384 if (broadcom_ioctl(drv
, WLC_SET_WEP_RESTRICT
,
385 &restrict
, sizeof(restrict
)) < 0 ||
386 broadcom_ioctl(drv
, WLC_SET_EAP_RESTRICT
,
387 &restrict
, sizeof(restrict
)) < 0)
393 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx
,
396 wpa_printf(MSG_DEBUG
, "Scan timeout - try to get results");
397 wpa_supplicant_event(timeout_ctx
, EVENT_SCAN_RESULTS
, NULL
);
400 static int wpa_driver_broadcom_scan(void *priv
, const u8
*ssid
,
403 struct wpa_driver_broadcom_data
*drv
= priv
;
404 wlc_ssid_t wst
= { 0, "" };
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
));
435 wpa_driver_broadcom_get_scan_results(void *priv
,
436 struct wpa_scan_result
*results
,
439 struct wpa_driver_broadcom_data
*drv
= priv
;
441 wl_scan_results_t
*wsr
;
445 buf
= os_malloc(WLC_IOCTL_MAXLEN
);
449 wsr
= (wl_scan_results_t
*) buf
;
451 wsr
->buflen
= WLC_IOCTL_MAXLEN
- sizeof(wsr
);
455 if (broadcom_ioctl(drv
, WLC_SCAN_RESULTS
, buf
, WLC_IOCTL_MAXLEN
) < 0) {
460 os_memset(results
, 0, max_size
* sizeof(struct wpa_scan_result
));
462 for (ap_num
= 0, wbi
= wsr
->bss_info
; ap_num
< wsr
->count
; ++ap_num
) {
464 struct bss_ie_hdr
*ie
;
466 os_memcpy(results
[ap_num
].bssid
, &wbi
->BSSID
, ETH_ALEN
);
467 os_memcpy(results
[ap_num
].ssid
, wbi
->SSID
, wbi
->SSID_len
);
468 results
[ap_num
].ssid_len
= wbi
->SSID_len
;
469 results
[ap_num
].freq
= frequency_list
[wbi
->channel
- 1];
471 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: AP IEs",
472 (u8
*) wbi
+ sizeof(*wbi
), wbi
->ie_length
);
473 ie
= (struct bss_ie_hdr
*) ((u8
*) wbi
+ sizeof(*wbi
));
474 for (left
= wbi
->ie_length
; left
> 0;
475 left
-= (ie
->len
+ 2), ie
= (struct bss_ie_hdr
*)
476 ((u8
*) ie
+ 2 + ie
->len
)) {
477 wpa_printf(MSG_MSGDUMP
, "BROADCOM: IE: id:%x, len:%d",
478 ie
->elem_id
, ie
->len
);
480 wpa_printf(MSG_MSGDUMP
,
481 "BROADCOM: oui:%02x%02x%02x",
482 ie
->oui
[0], ie
->oui
[1], ie
->oui
[2]);
483 if (ie
->elem_id
!= 0xdd ||
485 os_memcmp(ie
->oui
, WPA_OUI
, 3) != 0)
487 os_memcpy(results
[ap_num
].wpa_ie
, ie
, ie
->len
+ 2);
488 results
[ap_num
].wpa_ie_len
= ie
->len
+ 2;
492 wbi
= (wl_bss_info_t
*) ((u8
*) wbi
+ wbi
->length
);
495 wpa_printf(MSG_MSGDUMP
, "Received %d bytes of scan results (%lu "
497 wsr
->buflen
, (unsigned long) ap_num
);
503 static int wpa_driver_broadcom_deauthenticate(void *priv
, const u8
*addr
,
506 struct wpa_driver_broadcom_data
*drv
= priv
;
508 wdt
.val
= reason_code
;
509 os_memcpy(&wdt
.ea
, addr
, sizeof wdt
.ea
);
511 return broadcom_ioctl(drv
, WLC_DEAUTHENTICATE_WITH_REASON
, &wdt
,
515 static int wpa_driver_broadcom_disassociate(void *priv
, const u8
*addr
,
518 struct wpa_driver_broadcom_data
*drv
= priv
;
519 return broadcom_ioctl(drv
, WLC_DISASSOC
, 0, 0);
523 wpa_driver_broadcom_associate(void *priv
,
524 struct wpa_driver_associate_params
*params
)
526 struct wpa_driver_broadcom_data
*drv
= priv
;
534 s
.SSID_len
= params
->ssid_len
;
535 os_memcpy(s
.SSID
, params
->ssid
, params
->ssid_len
);
537 switch (params
->pairwise_suite
) {
556 switch (params
->key_mgmt_suite
) {
557 case KEY_MGMT_802_1X
:
570 /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
571 * group_suite, key_mgmt_suite);
572 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
573 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
575 if (broadcom_ioctl(drv
, WLC_SET_WSEC
, &wsec
, sizeof(wsec
)) < 0 ||
576 broadcom_ioctl(drv
, WLC_SET_WPA_AUTH
, &wpa_auth
,
577 sizeof(wpa_auth
)) < 0 ||
578 broadcom_ioctl(drv
, WLC_GET_WEP
, &dummy
, sizeof(dummy
)) < 0 ||
579 broadcom_ioctl(drv
, WLC_SET_INFRA
, &infra
, sizeof(infra
)) < 0 ||
580 broadcom_ioctl(drv
, WLC_SET_AUTH
, &auth
, sizeof(auth
)) < 0 ||
581 broadcom_ioctl(drv
, WLC_SET_WEP
, &wsec
, sizeof(wsec
)) < 0 ||
582 broadcom_ioctl(drv
, WLC_SET_SSID
, &s
, sizeof(s
)) < 0)
588 const struct wpa_driver_ops wpa_driver_broadcom_ops
= {
590 .desc
= "Broadcom wl.o driver",
591 .get_bssid
= wpa_driver_broadcom_get_bssid
,
592 .get_ssid
= wpa_driver_broadcom_get_ssid
,
593 .set_wpa
= wpa_driver_broadcom_set_wpa
,
594 .set_key
= wpa_driver_broadcom_set_key
,
595 .init
= wpa_driver_broadcom_init
,
596 .deinit
= wpa_driver_broadcom_deinit
,
597 .set_countermeasures
= wpa_driver_broadcom_set_countermeasures
,
598 .set_drop_unencrypted
= wpa_driver_broadcom_set_drop_unencrypted
,
599 .scan
= wpa_driver_broadcom_scan
,
600 .get_scan_results
= wpa_driver_broadcom_get_scan_results
,
601 .deauthenticate
= wpa_driver_broadcom_deauthenticate
,
602 .disassociate
= wpa_driver_broadcom_disassociate
,
603 .associate
= wpa_driver_broadcom_associate
,