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
;
237 if ((left
= recv(sock
, buf
, sizeof buf
, 0)) < 0)
240 wpa_hexdump(MSG_DEBUG
, "RECEIVE EVENT", (u8
*) buf
, left
);
242 if ((size_t) left
< sizeof(wl_wpa_header_t
))
245 wwh
= (wl_wpa_header_t
*) buf
;
247 if (wwh
->snap
.type
!= WL_WPA_ETHER_TYPE
)
249 if (os_memcmp(&wwh
->snap
, wl_wpa_snap_template
, 6) != 0)
252 os_memset(&data
, 0, sizeof(data
));
256 left
-= WL_WPA_HEADER_LEN
;
257 wpa_printf(MSG_DEBUG
, "BROADCOM: ASSOC MESSAGE (left: %d)",
260 data
.assoc_info
.resp_ies
= os_malloc(left
);
261 if (data
.assoc_info
.resp_ies
== NULL
)
263 os_memcpy(data
.assoc_info
.resp_ies
,
264 buf
+ WL_WPA_HEADER_LEN
, left
);
265 data
.assoc_info
.resp_ies_len
= left
;
266 wpa_hexdump(MSG_MSGDUMP
, "BROADCOM: copying %d bytes "
268 data
.assoc_info
.resp_ies
, left
);
270 /* data.assoc_info.req_ies = NULL; */
271 /* data.assoc_info.req_ies_len = 0; */
273 wpa_supplicant_event(ctx
, EVENT_ASSOCINFO
, &data
);
274 wpa_supplicant_event(ctx
, EVENT_ASSOC
, NULL
);
276 case WLC_DISASSOC_MSG
:
277 wpa_printf(MSG_DEBUG
, "BROADCOM: DISASSOC MESSAGE");
278 wpa_supplicant_event(ctx
, EVENT_DISASSOC
, NULL
);
280 case WLC_PTK_MIC_MSG
:
281 wpa_printf(MSG_DEBUG
, "BROADCOM: PTK MIC MSG MESSAGE");
282 data
.michael_mic_failure
.unicast
= 1;
283 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
285 case WLC_GTK_MIC_MSG
:
286 wpa_printf(MSG_DEBUG
, "BROADCOM: GTK MIC MSG MESSAGE");
287 data
.michael_mic_failure
.unicast
= 0;
288 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
291 wpa_printf(MSG_DEBUG
, "BROADCOM: UNKNOWN MESSAGE (%d)",
295 os_free(data
.assoc_info
.resp_ies
);
298 static void * wpa_driver_broadcom_init(void *ctx
, const char *ifname
)
301 struct sockaddr_ll ll
;
302 struct wpa_driver_broadcom_data
*drv
;
305 /* open socket to kernel */
306 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
311 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
312 if (ioctl(s
, SIOCGIFINDEX
, &ifr
) < 0) {
313 perror(ifr
.ifr_name
);
318 drv
= os_zalloc(sizeof(*drv
));
322 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
325 s
= socket(PF_PACKET
, SOCK_RAW
, ntohs(ETH_P_802_2
));
327 perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
328 close(drv
->ioctl_sock
);
333 os_memset(&ll
, 0, sizeof(ll
));
334 ll
.sll_family
= AF_PACKET
;
335 ll
.sll_protocol
= ntohs(ETH_P_802_2
);
336 ll
.sll_ifindex
= ifr
.ifr_ifindex
;
338 ll
.sll_pkttype
= PACKET_HOST
;
341 if (bind(s
, (struct sockaddr
*) &ll
, sizeof(ll
)) < 0) {
342 perror("bind(netlink)");
344 close(drv
->ioctl_sock
);
349 eloop_register_read_sock(s
, wpa_driver_broadcom_event_receive
, ctx
,
352 wpa_driver_broadcom_set_wpa(drv
, 1);
357 static void wpa_driver_broadcom_deinit(void *priv
)
359 struct wpa_driver_broadcom_data
*drv
= priv
;
360 wpa_driver_broadcom_set_wpa(drv
, 0);
361 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout
, drv
, drv
->ctx
);
362 eloop_unregister_read_sock(drv
->event_sock
);
363 close(drv
->event_sock
);
364 close(drv
->ioctl_sock
);
368 static int wpa_driver_broadcom_set_countermeasures(void *priv
,
372 struct wpa_driver_broadcom_data
*drv
= priv
;
374 return broadcom_ioctl(drv
, WLC_SET_TKIP_COUNTERMEASURES
, &enabled
,
381 static int wpa_driver_broadcom_set_drop_unencrypted(void *priv
, int enabled
)
383 struct wpa_driver_broadcom_data
*drv
= priv
;
384 /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
385 int _restrict
= (enabled
? 1 : 0);
387 if (broadcom_ioctl(drv
, WLC_SET_WEP_RESTRICT
,
388 &_restrict
, sizeof(_restrict
)) < 0 ||
389 broadcom_ioctl(drv
, WLC_SET_EAP_RESTRICT
,
390 &_restrict
, sizeof(_restrict
)) < 0)
396 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx
,
399 wpa_printf(MSG_DEBUG
, "Scan timeout - try to get results");
400 wpa_supplicant_event(timeout_ctx
, EVENT_SCAN_RESULTS
, NULL
);
403 static int wpa_driver_broadcom_scan(void *priv
,
404 struct wpa_driver_scan_params
*params
)
406 struct wpa_driver_broadcom_data
*drv
= priv
;
407 wlc_ssid_t wst
= { 0, "" };
408 const u8
*ssid
= params
->ssids
[0].ssid
;
409 size_t ssid_len
= params
->ssids
[0].ssid_len
;
411 if (ssid
&& ssid_len
> 0 && ssid_len
<= sizeof(wst
.SSID
)) {
412 wst
.SSID_len
= ssid_len
;
413 os_memcpy(wst
.SSID
, ssid
, ssid_len
);
416 if (broadcom_ioctl(drv
, WLC_SCAN
, &wst
, sizeof(wst
)) < 0)
419 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout
, drv
, drv
->ctx
);
420 eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout
, drv
,
426 static const int frequency_list
[] = {
427 2412, 2417, 2422, 2427, 2432, 2437, 2442,
428 2447, 2452, 2457, 2462, 2467, 2472, 2484
437 } __attribute__ ((packed
));
439 static struct wpa_scan_results
*
440 wpa_driver_broadcom_get_scan_results(void *priv
)
442 struct wpa_driver_broadcom_data
*drv
= priv
;
444 wl_scan_results_t
*wsr
;
447 struct wpa_scan_results
*res
;
449 buf
= os_malloc(WLC_IOCTL_MAXLEN
);
453 wsr
= (wl_scan_results_t
*) buf
;
455 wsr
->buflen
= WLC_IOCTL_MAXLEN
- sizeof(wsr
);
459 if (broadcom_ioctl(drv
, WLC_SCAN_RESULTS
, buf
, WLC_IOCTL_MAXLEN
) < 0) {
464 res
= os_zalloc(sizeof(*res
));
470 res
->res
= os_zalloc(wsr
->count
* sizeof(struct wpa_scan_res
*));
471 if (res
->res
== NULL
) {
477 for (ap_num
= 0, wbi
= wsr
->bss_info
; ap_num
< wsr
->count
; ++ap_num
) {
478 struct wpa_scan_res
*r
;
479 r
= os_malloc(sizeof(*r
) + wbi
->ie_length
);
482 res
->res
[res
->num
++] = r
;
484 os_memcpy(r
->bssid
, &wbi
->BSSID
, ETH_ALEN
);
485 r
->freq
= frequency_list
[wbi
->channel
- 1];
487 os_memcpy(r
+ 1, wbi
+ 1, wbi
->ie_length
);
488 r
->ie_len
= wbi
->ie_length
;
490 wbi
= (wl_bss_info_t
*) ((u8
*) wbi
+ wbi
->length
);
493 wpa_printf(MSG_MSGDUMP
, "Received %d bytes of scan results (%lu "
495 wsr
->buflen
, (unsigned long) ap_num
);
501 static int wpa_driver_broadcom_deauthenticate(void *priv
, const u8
*addr
,
504 struct wpa_driver_broadcom_data
*drv
= priv
;
506 wdt
.val
= reason_code
;
507 os_memcpy(&wdt
.ea
, addr
, sizeof wdt
.ea
);
509 return broadcom_ioctl(drv
, WLC_DEAUTHENTICATE_WITH_REASON
, &wdt
,
513 static int wpa_driver_broadcom_disassociate(void *priv
, const u8
*addr
,
516 struct wpa_driver_broadcom_data
*drv
= priv
;
517 return broadcom_ioctl(drv
, WLC_DISASSOC
, NULL
, 0);
521 wpa_driver_broadcom_associate(void *priv
,
522 struct wpa_driver_associate_params
*params
)
524 struct wpa_driver_broadcom_data
*drv
= priv
;
533 ret
= wpa_driver_broadcom_set_drop_unencrypted(
534 drv
, params
->drop_unencrypted
);
536 s
.SSID_len
= params
->ssid_len
;
537 os_memcpy(s
.SSID
, params
->ssid
, params
->ssid_len
);
539 switch (params
->pairwise_suite
) {
558 switch (params
->key_mgmt_suite
) {
559 case KEY_MGMT_802_1X
:
572 /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
573 * group_suite, key_mgmt_suite);
574 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
575 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
577 if (broadcom_ioctl(drv
, WLC_SET_WSEC
, &wsec
, sizeof(wsec
)) < 0 ||
578 broadcom_ioctl(drv
, WLC_SET_WPA_AUTH
, &wpa_auth
,
579 sizeof(wpa_auth
)) < 0 ||
580 broadcom_ioctl(drv
, WLC_GET_WEP
, &dummy
, sizeof(dummy
)) < 0 ||
581 broadcom_ioctl(drv
, WLC_SET_INFRA
, &infra
, sizeof(infra
)) < 0 ||
582 broadcom_ioctl(drv
, WLC_SET_AUTH
, &auth
, sizeof(auth
)) < 0 ||
583 broadcom_ioctl(drv
, WLC_SET_WEP
, &wsec
, sizeof(wsec
)) < 0 ||
584 broadcom_ioctl(drv
, WLC_SET_SSID
, &s
, sizeof(s
)) < 0)
590 const struct wpa_driver_ops wpa_driver_broadcom_ops
= {
592 .desc
= "Broadcom wl.o driver",
593 .get_bssid
= wpa_driver_broadcom_get_bssid
,
594 .get_ssid
= wpa_driver_broadcom_get_ssid
,
595 .set_key
= wpa_driver_broadcom_set_key
,
596 .init
= wpa_driver_broadcom_init
,
597 .deinit
= wpa_driver_broadcom_deinit
,
598 .set_countermeasures
= wpa_driver_broadcom_set_countermeasures
,
599 .scan2
= wpa_driver_broadcom_scan
,
600 .get_scan_results2
= wpa_driver_broadcom_get_scan_results
,
601 .deauthenticate
= wpa_driver_broadcom_deauthenticate
,
602 .disassociate
= wpa_driver_broadcom_disassociate
,
603 .associate
= wpa_driver_broadcom_associate
,