2 * WPA Supplicant - driver interaction with 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.
18 #include <sys/ioctl.h>
23 #include <netpacket/packet.h>
24 #include <net/ethernet.h> /* the L2 protocols */
26 #include <linux/if_packet.h>
27 #include <linux/if_ether.h> /* The L2 protocols */
32 /* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
33 * WRT54G GPL tarball. */
39 struct wpa_driver_broadcom_data
{
43 char ifname
[IFNAMSIZ
+ 1];
47 #ifndef WLC_DEAUTHENTICATE
48 #define WLC_DEAUTHENTICATE 143
50 #ifndef WLC_DEAUTHENTICATE_WITH_REASON
51 #define WLC_DEAUTHENTICATE_WITH_REASON 201
53 #ifndef WLC_SET_TKIP_COUNTERMEASURES
54 #define WLC_SET_TKIP_COUNTERMEASURES 202
57 #if !defined(PSK_ENABLED) /* NEW driver interface */
58 #define WL_VERSION 360130
59 /* wireless authentication bit vector */
63 #define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
64 #define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
65 #define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
67 #define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
69 typedef wl_wsec_key_t wsec_key_t
;
79 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx
,
82 static int broadcom_ioctl(struct wpa_driver_broadcom_data
*drv
, int cmd
,
89 wpa_printf(MSG_MSGDUMP
, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
90 drv
->ifname
, cmd
, len
, buf
);
91 /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
96 os_strlcpy(ifr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
97 ifr
.ifr_data
= (caddr_t
) &ioc
;
98 if ((ret
= ioctl(drv
->ioctl_sock
, SIOCDEVPRIVATE
, &ifr
)) < 0) {
99 if (cmd
!= WLC_GET_MAGIC
)
100 perror(ifr
.ifr_name
);
101 wpa_printf(MSG_MSGDUMP
, "BROADCOM: wlioctl cmd=%d res=%d",
108 static int wpa_driver_broadcom_get_bssid(void *priv
, u8
*bssid
)
110 struct wpa_driver_broadcom_data
*drv
= priv
;
111 if (broadcom_ioctl(drv
, WLC_GET_BSSID
, bssid
, ETH_ALEN
) == 0)
114 os_memset(bssid
, 0, ETH_ALEN
);
118 static int wpa_driver_broadcom_get_ssid(void *priv
, u8
*ssid
)
120 struct wpa_driver_broadcom_data
*drv
= priv
;
123 if (broadcom_ioctl(drv
, WLC_GET_SSID
, &s
, sizeof(s
)) == -1)
126 os_memcpy(ssid
, s
.SSID
, s
.SSID_len
);
130 static int wpa_driver_broadcom_set_wpa(void *priv
, int enable
)
132 struct wpa_driver_broadcom_data
*drv
= priv
;
133 unsigned int wauth
, wsec
;
134 struct ether_addr ea
;
136 os_memset(&ea
, enable
? 0xff : 0, sizeof(ea
));
137 if (broadcom_ioctl(drv
, WLC_GET_WPA_AUTH
, &wauth
, sizeof(wauth
)) ==
139 broadcom_ioctl(drv
, WLC_GET_WSEC
, &wsec
, sizeof(wsec
)) == -1)
147 wsec
&= ~(TKIP_ENABLED
| AES_ENABLED
);
150 if (broadcom_ioctl(drv
, WLC_SET_WPA_AUTH
, &wauth
, sizeof(wauth
)) ==
152 broadcom_ioctl(drv
, WLC_SET_WSEC
, &wsec
, sizeof(wsec
)) == -1)
155 /* FIX: magic number / error handling? */
156 broadcom_ioctl(drv
, 122, &ea
, sizeof(ea
));
161 static int wpa_driver_broadcom_set_key(void *priv
, wpa_alg alg
,
162 const u8
*addr
, int key_idx
, int set_tx
,
163 const u8
*seq
, size_t seq_len
,
164 const u8
*key
, size_t key_len
)
166 struct wpa_driver_broadcom_data
*drv
= priv
;
170 os_memset(&wkt
, 0, sizeof wkt
);
171 wpa_printf(MSG_MSGDUMP
, "BROADCOM: SET %sKEY[%d] alg=%d",
172 set_tx
? "PRIMARY " : "", key_idx
, alg
);
173 if (key
&& key_len
> 0)
174 wpa_hexdump_key(MSG_MSGDUMP
, "BROADCOM: key", key
, key_len
);
178 wkt
.algo
= CRYPTO_ALGO_OFF
;
181 wkt
.algo
= CRYPTO_ALGO_WEP128
; /* CRYPTO_ALGO_WEP1? */
184 wkt
.algo
= 0; /* CRYPTO_ALGO_TKIP? */
187 wkt
.algo
= 0; /* CRYPTO_ALGO_AES_CCM;
188 * AES_OCB_MSDU, AES_OCB_MPDU? */
191 wkt
.algo
= CRYPTO_ALGO_NALG
;
195 if (seq
&& seq_len
> 0)
196 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: SEQ", seq
, seq_len
);
199 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: addr", addr
, ETH_ALEN
);
203 if (key
&& key_len
> 0) {
204 os_memcpy(wkt
.data
, key
, key_len
);
206 /* hack hack hack XXX */
207 os_memcpy(&wkt
.data
[16], &key
[24], 8);
208 os_memcpy(&wkt
.data
[24], &key
[16], 8);
211 /* wkt.algo = CRYPTO_ALGO_...; */
212 wkt
.flags
= set_tx
? 0 : WSEC_PRIMARY_KEY
;
214 os_memcpy(&wkt
.ea
, addr
, sizeof(wkt
.ea
));
215 ret
= broadcom_ioctl(drv
, WLC_SET_KEY
, &wkt
, sizeof(wkt
));
216 if (addr
&& set_tx
) {
217 /* FIX: magic number / error handling? */
218 broadcom_ioctl(drv
, 121, &wkt
.ea
, sizeof(wkt
.ea
));
224 static void wpa_driver_broadcom_event_receive(int sock
, void *ctx
,
229 wl_wpa_header_t
*wwh
;
230 union wpa_event_data data
;
232 if ((left
= recv(sock
, buf
, sizeof buf
, 0)) < 0)
235 wpa_hexdump(MSG_DEBUG
, "RECEIVE EVENT", (u8
*) buf
, left
);
237 if ((size_t) left
< sizeof(wl_wpa_header_t
))
240 wwh
= (wl_wpa_header_t
*) buf
;
242 if (wwh
->snap
.type
!= WL_WPA_ETHER_TYPE
)
244 if (os_memcmp(&wwh
->snap
, wl_wpa_snap_template
, 6) != 0)
247 os_memset(&data
, 0, sizeof(data
));
251 left
-= WL_WPA_HEADER_LEN
;
252 wpa_printf(MSG_DEBUG
, "BROADCOM: ASSOC MESSAGE (left: %d)",
255 data
.assoc_info
.resp_ies
= os_malloc(left
);
256 if (data
.assoc_info
.resp_ies
== NULL
)
258 os_memcpy(data
.assoc_info
.resp_ies
,
259 buf
+ WL_WPA_HEADER_LEN
, left
);
260 data
.assoc_info
.resp_ies_len
= left
;
261 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: copying %d bytes "
263 data
.assoc_info
.resp_ies
, left
);
265 /* data.assoc_info.req_ies = NULL; */
266 /* data.assoc_info.req_ies_len = 0; */
268 wpa_supplicant_event(ctx
, EVENT_ASSOCINFO
, &data
);
269 wpa_supplicant_event(ctx
, EVENT_ASSOC
, NULL
);
271 case WLC_DISASSOC_MSG
:
272 wpa_printf(MSG_DEBUG
, "BROADCOM: DISASSOC MESSAGE");
273 wpa_supplicant_event(ctx
, EVENT_DISASSOC
, NULL
);
275 case WLC_PTK_MIC_MSG
:
276 wpa_printf(MSG_DEBUG
, "BROADCOM: PTK MIC MSG MESSAGE");
277 data
.michael_mic_failure
.unicast
= 1;
278 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
280 case WLC_GTK_MIC_MSG
:
281 wpa_printf(MSG_DEBUG
, "BROADCOM: GTK MIC MSG MESSAGE");
282 data
.michael_mic_failure
.unicast
= 0;
283 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
286 wpa_printf(MSG_DEBUG
, "BROADCOM: UNKNOWN MESSAGE (%d)",
290 os_free(data
.assoc_info
.resp_ies
);
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
,
351 static void wpa_driver_broadcom_deinit(void *priv
)
353 struct wpa_driver_broadcom_data
*drv
= priv
;
354 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout
, drv
, drv
->ctx
);
355 eloop_unregister_read_sock(drv
->event_sock
);
356 close(drv
->event_sock
);
357 close(drv
->ioctl_sock
);
361 static int wpa_driver_broadcom_set_countermeasures(void *priv
,
365 struct wpa_driver_broadcom_data
*drv
= priv
;
367 return broadcom_ioctl(drv
, WLC_SET_TKIP_COUNTERMEASURES
, &enabled
,
374 static int wpa_driver_broadcom_set_drop_unencrypted(void *priv
, int enabled
)
376 struct wpa_driver_broadcom_data
*drv
= priv
;
377 /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
378 int restrict
= (enabled
? 1 : 0);
380 if (broadcom_ioctl(drv
, WLC_SET_WEP_RESTRICT
,
381 &restrict
, sizeof(restrict
)) < 0 ||
382 broadcom_ioctl(drv
, WLC_SET_EAP_RESTRICT
,
383 &restrict
, sizeof(restrict
)) < 0)
389 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx
,
392 wpa_printf(MSG_DEBUG
, "Scan timeout - try to get results");
393 wpa_supplicant_event(timeout_ctx
, EVENT_SCAN_RESULTS
, NULL
);
396 static int wpa_driver_broadcom_scan(void *priv
, const u8
*ssid
,
399 struct wpa_driver_broadcom_data
*drv
= priv
;
400 wlc_ssid_t wst
= { 0, "" };
402 if (ssid
&& ssid_len
> 0 && ssid_len
<= sizeof(wst
.SSID
)) {
403 wst
.SSID_len
= ssid_len
;
404 os_memcpy(wst
.SSID
, ssid
, ssid_len
);
407 if (broadcom_ioctl(drv
, WLC_SCAN
, &wst
, sizeof(wst
)) < 0)
410 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout
, drv
, drv
->ctx
);
411 eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout
, drv
,
417 static const int frequency_list
[] = {
418 2412, 2417, 2422, 2427, 2432, 2437, 2442,
419 2447, 2452, 2457, 2462, 2467, 2472, 2484
428 } __attribute__ ((packed
));
431 wpa_driver_broadcom_get_scan_results(void *priv
,
432 struct wpa_scan_result
*results
,
435 struct wpa_driver_broadcom_data
*drv
= priv
;
437 wl_scan_results_t
*wsr
;
441 buf
= os_malloc(WLC_IOCTL_MAXLEN
);
445 wsr
= (wl_scan_results_t
*) buf
;
447 wsr
->buflen
= WLC_IOCTL_MAXLEN
- sizeof(wsr
);
451 if (broadcom_ioctl(drv
, WLC_SCAN_RESULTS
, buf
, WLC_IOCTL_MAXLEN
) < 0) {
456 os_memset(results
, 0, max_size
* sizeof(struct wpa_scan_result
));
458 for (ap_num
= 0, wbi
= wsr
->bss_info
; ap_num
< wsr
->count
; ++ap_num
) {
460 struct bss_ie_hdr
*ie
;
462 os_memcpy(results
[ap_num
].bssid
, &wbi
->BSSID
, ETH_ALEN
);
463 os_memcpy(results
[ap_num
].ssid
, wbi
->SSID
, wbi
->SSID_len
);
464 results
[ap_num
].ssid_len
= wbi
->SSID_len
;
465 results
[ap_num
].freq
= frequency_list
[wbi
->channel
- 1];
467 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: AP IEs",
468 (u8
*) wbi
+ sizeof(*wbi
), wbi
->ie_length
);
469 ie
= (struct bss_ie_hdr
*) ((u8
*) wbi
+ sizeof(*wbi
));
470 for (left
= wbi
->ie_length
; left
> 0;
471 left
-= (ie
->len
+ 2), ie
= (struct bss_ie_hdr
*)
472 ((u8
*) ie
+ 2 + ie
->len
)) {
473 wpa_printf(MSG_MSGDUMP
, "BROADCOM: IE: id:%x, len:%d",
474 ie
->elem_id
, ie
->len
);
476 wpa_printf(MSG_MSGDUMP
,
477 "BROADCOM: oui:%02x%02x%02x",
478 ie
->oui
[0], ie
->oui
[1], ie
->oui
[2]);
479 if (ie
->elem_id
!= 0xdd ||
481 os_memcmp(ie
->oui
, WPA_OUI
, 3) != 0)
483 os_memcpy(results
[ap_num
].wpa_ie
, ie
, ie
->len
+ 2);
484 results
[ap_num
].wpa_ie_len
= ie
->len
+ 2;
488 wbi
= (wl_bss_info_t
*) ((u8
*) wbi
+ wbi
->length
);
491 wpa_printf(MSG_MSGDUMP
, "Received %d bytes of scan results (%d BSSes)",
492 wsr
->buflen
, ap_num
);
498 static int wpa_driver_broadcom_deauthenticate(void *priv
, const u8
*addr
,
501 struct wpa_driver_broadcom_data
*drv
= priv
;
503 wdt
.val
= reason_code
;
504 os_memcpy(&wdt
.ea
, addr
, sizeof wdt
.ea
);
506 return broadcom_ioctl(drv
, WLC_DEAUTHENTICATE_WITH_REASON
, &wdt
,
510 static int wpa_driver_broadcom_disassociate(void *priv
, const u8
*addr
,
513 struct wpa_driver_broadcom_data
*drv
= priv
;
514 return broadcom_ioctl(drv
, WLC_DISASSOC
, 0, 0);
518 wpa_driver_broadcom_associate(void *priv
,
519 struct wpa_driver_associate_params
*params
)
521 struct wpa_driver_broadcom_data
*drv
= priv
;
529 s
.SSID_len
= params
->ssid_len
;
530 os_memcpy(s
.SSID
, params
->ssid
, params
->ssid_len
);
532 switch (params
->pairwise_suite
) {
551 switch (params
->key_mgmt_suite
) {
552 case KEY_MGMT_802_1X
:
565 /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
566 * group_suite, key_mgmt_suite);
567 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
568 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
570 if (broadcom_ioctl(drv
, WLC_SET_WSEC
, &wsec
, sizeof(wsec
)) < 0 ||
571 broadcom_ioctl(drv
, WLC_SET_WPA_AUTH
, &wpa_auth
,
572 sizeof(wpa_auth
)) < 0 ||
573 broadcom_ioctl(drv
, WLC_GET_WEP
, &dummy
, sizeof(dummy
)) < 0 ||
574 broadcom_ioctl(drv
, WLC_SET_INFRA
, &infra
, sizeof(infra
)) < 0 ||
575 broadcom_ioctl(drv
, WLC_SET_AUTH
, &auth
, sizeof(auth
)) < 0 ||
576 broadcom_ioctl(drv
, WLC_SET_WEP
, &wsec
, sizeof(wsec
)) < 0 ||
577 broadcom_ioctl(drv
, WLC_SET_SSID
, &s
, sizeof(s
)) < 0)
583 const struct wpa_driver_ops wpa_driver_broadcom_ops
= {
585 .desc
= "Broadcom wl.o driver",
586 .get_bssid
= wpa_driver_broadcom_get_bssid
,
587 .get_ssid
= wpa_driver_broadcom_get_ssid
,
588 .set_wpa
= wpa_driver_broadcom_set_wpa
,
589 .set_key
= wpa_driver_broadcom_set_key
,
590 .init
= wpa_driver_broadcom_init
,
591 .deinit
= wpa_driver_broadcom_deinit
,
592 .set_countermeasures
= wpa_driver_broadcom_set_countermeasures
,
593 .set_drop_unencrypted
= wpa_driver_broadcom_set_drop_unencrypted
,
594 .scan
= wpa_driver_broadcom_scan
,
595 .get_scan_results
= wpa_driver_broadcom_get_scan_results
,
596 .deauthenticate
= wpa_driver_broadcom_deauthenticate
,
597 .disassociate
= wpa_driver_broadcom_disassociate
,
598 .associate
= wpa_driver_broadcom_associate
,