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.
17
#include <sys/ioctl.h>
19
#include <netpacket/packet.h>
20
#include <net/ethernet.h> /* the L2 protocols */
22
#include <linux/if_packet.h>
23
#include <linux/if_ether.h> /* The L2 protocols */
28
/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
29
* WRT54G GPL tarball. */
35
#include "wpa_supplicant.h"
38
struct wpa_driver_broadcom_data {
42
char ifname[IFNAMSIZ + 1];
46
#ifndef WLC_DEAUTHENTICATE
47
#define WLC_DEAUTHENTICATE 143
49
#ifndef WLC_DEAUTHENTICATE_WITH_REASON
50
#define WLC_DEAUTHENTICATE_WITH_REASON 201
52
#ifndef WLC_SET_TKIP_COUNTERMEASURES
53
#define WLC_SET_TKIP_COUNTERMEASURES 202
56
#if !defined(PSK_ENABLED) /* NEW driver interface */
57
#define WL_VERSION 360130
58
/* wireless authentication bit vector */
62
#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
63
#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
64
#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
66
#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
68
typedef wl_wsec_key_t wsec_key_t;
78
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
81
static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
88
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
89
drv->ifname, cmd, len, buf);
90
/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
95
os_strncpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
96
ifr.ifr_data = (caddr_t) &ioc;
97
if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
98
if (cmd != WLC_GET_MAGIC)
100
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
107
static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
109
struct wpa_driver_broadcom_data *drv = priv;
110
if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
113
os_memset(bssid, 0, ETH_ALEN);
117
static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
119
struct wpa_driver_broadcom_data *drv = priv;
122
if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
125
os_memcpy(ssid, s.SSID, s.SSID_len);
129
static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
131
struct wpa_driver_broadcom_data *drv = priv;
132
unsigned int wauth, wsec;
133
struct ether_addr ea;
135
os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
136
if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
138
broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
146
wsec &= ~(TKIP_ENABLED | AES_ENABLED);
149
if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
151
broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
154
/* FIX: magic number / error handling? */
155
broadcom_ioctl(drv, 122, &ea, sizeof(ea));
160
static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg,
161
const u8 *addr, int key_idx, int set_tx,
162
const u8 *seq, size_t seq_len,
163
const u8 *key, size_t key_len)
165
struct wpa_driver_broadcom_data *drv = priv;
169
os_memset(&wkt, 0, sizeof wkt);
170
wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
171
set_tx ? "PRIMARY " : "", key_idx, alg);
172
if (key && key_len > 0)
173
wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
177
wkt.algo = CRYPTO_ALGO_OFF;
180
wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
183
wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
186
wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
187
* AES_OCB_MSDU, AES_OCB_MPDU? */
190
wkt.algo = CRYPTO_ALGO_NALG;
194
if (seq && seq_len > 0)
195
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
198
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
202
if (key && key_len > 0) {
203
os_memcpy(wkt.data, key, key_len);
205
/* hack hack hack XXX */
206
os_memcpy(&wkt.data[16], &key[24], 8);
207
os_memcpy(&wkt.data[24], &key[16], 8);
210
/* wkt.algo = CRYPTO_ALGO_...; */
211
wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
213
os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
214
ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
215
if (addr && set_tx) {
216
/* FIX: magic number / error handling? */
217
broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
223
static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
228
wl_wpa_header_t *wwh;
229
union wpa_event_data data;
231
if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
234
wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", buf, left);
236
if ((size_t) left < sizeof(wl_wpa_header_t))
239
wwh = (wl_wpa_header_t *) buf;
241
if (wwh->snap.type != WL_WPA_ETHER_TYPE)
243
if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
246
os_memset(&data, 0, sizeof(data));
250
left -= WL_WPA_HEADER_LEN;
251
wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
254
data.assoc_info.resp_ies = os_malloc(left);
255
if (data.assoc_info.resp_ies == NULL)
257
os_memcpy(data.assoc_info.resp_ies,
258
buf + WL_WPA_HEADER_LEN, left);
259
data.assoc_info.resp_ies_len = left;
260
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
262
data.assoc_info.resp_ies, left);
264
/* data.assoc_info.req_ies = NULL; */
265
/* data.assoc_info.req_ies_len = 0; */
267
wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
268
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
270
case WLC_DISASSOC_MSG:
271
wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
272
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
274
case WLC_PTK_MIC_MSG:
275
wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
276
data.michael_mic_failure.unicast = 1;
277
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
279
case WLC_GTK_MIC_MSG:
280
wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
281
data.michael_mic_failure.unicast = 0;
282
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
285
wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
289
os_free(data.assoc_info.resp_ies);
292
static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
295
struct sockaddr_ll ll;
296
struct wpa_driver_broadcom_data *drv;
299
/* open socket to kernel */
300
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
305
os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
306
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
307
perror(ifr.ifr_name);
312
drv = os_zalloc(sizeof(*drv));
316
os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
319
s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
321
perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
322
close(drv->ioctl_sock);
327
os_memset(&ll, 0, sizeof(ll));
328
ll.sll_family = AF_PACKET;
329
ll.sll_protocol = ntohs(ETH_P_802_2);
330
ll.sll_ifindex = ifr.ifr_ifindex;
332
ll.sll_pkttype = PACKET_HOST;
335
if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
336
perror("bind(netlink)");
338
close(drv->ioctl_sock);
343
eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
350
static void wpa_driver_broadcom_deinit(void *priv)
352
struct wpa_driver_broadcom_data *drv = priv;
353
eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
354
eloop_unregister_read_sock(drv->event_sock);
355
close(drv->event_sock);
356
close(drv->ioctl_sock);
360
static int wpa_driver_broadcom_set_countermeasures(void *priv,
364
struct wpa_driver_broadcom_data *drv = priv;
366
return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
373
static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
375
struct wpa_driver_broadcom_data *drv = priv;
376
/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
377
int restrict = (enabled ? 1 : 0);
379
if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
380
&restrict, sizeof(restrict)) < 0 ||
381
broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
382
&restrict, sizeof(restrict)) < 0)
388
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
391
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
392
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
395
static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid,
398
struct wpa_driver_broadcom_data *drv = priv;
399
wlc_ssid_t wst = { 0, "" };
401
if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
402
wst.SSID_len = ssid_len;
403
os_memcpy(wst.SSID, ssid, ssid_len);
406
if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
409
eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
415
static const int frequency_list[] = {
416
2412, 2417, 2422, 2427, 2432, 2437, 2442,
417
2447, 2452, 2457, 2462, 2467, 2472, 2484
426
} __attribute__ ((packed));
429
wpa_driver_broadcom_get_scan_results(void *priv,
430
struct wpa_scan_result *results,
433
struct wpa_driver_broadcom_data *drv = priv;
435
wl_scan_results_t *wsr = (wl_scan_results_t *) buf;
439
buf = os_malloc(WLC_IOCTL_MAXLEN);
443
wsr = (wl_scan_results_t *) buf;
445
wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
449
if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
454
os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
456
for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
458
struct bss_ie_hdr *ie;
460
os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
461
os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
462
results[ap_num].ssid_len = wbi->SSID_len;
463
results[ap_num].freq = frequency_list[wbi->channel - 1];
465
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs",
466
(u8 *) wbi + sizeof(*wbi), wbi->ie_length);
467
ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi));
468
for (left = wbi->ie_length; left > 0;
469
left -= (ie->len + 2), ie = (struct bss_ie_hdr *)
470
((u8 *) ie + 2 + ie->len)) {
471
wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d",
472
ie->elem_id, ie->len);
474
wpa_printf(MSG_MSGDUMP,
475
"BROADCOM: oui:%02x%02x%02x",
476
ie->oui[0], ie->oui[1], ie->oui[2]);
477
if (ie->elem_id != 0xdd ||
479
os_memcmp(ie->oui, WPA_OUI, 3) != 0)
481
os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2);
482
results[ap_num].wpa_ie_len = ie->len + 2;
486
wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
489
wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%d BSSes)",
490
wsr->buflen, 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, 0, 0);
516
wpa_driver_broadcom_associate(void *priv,
517
struct wpa_driver_associate_params *params)
519
struct wpa_driver_broadcom_data *drv = priv;
527
s.SSID_len = params->ssid_len;
528
os_memcpy(s.SSID, params->ssid, params->ssid_len);
530
switch (params->pairwise_suite) {
549
switch (params->key_mgmt_suite) {
550
case KEY_MGMT_802_1X:
563
/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
564
* group_suite, key_mgmt_suite);
565
* broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
566
* wl join uses wlc_sec_wep here, not wlc_set_wsec */
568
if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
569
broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
570
sizeof(wpa_auth)) < 0 ||
571
broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
572
broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
573
broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
574
broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
575
broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
581
const struct wpa_driver_ops wpa_driver_broadcom_ops = {
583
.desc = "Broadcom wl.o driver",
584
.get_bssid = wpa_driver_broadcom_get_bssid,
585
.get_ssid = wpa_driver_broadcom_get_ssid,
586
.set_wpa = wpa_driver_broadcom_set_wpa,
587
.set_key = wpa_driver_broadcom_set_key,
588
.init = wpa_driver_broadcom_init,
589
.deinit = wpa_driver_broadcom_deinit,
590
.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
591
.set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted,
592
.scan = wpa_driver_broadcom_scan,
593
.get_scan_results = wpa_driver_broadcom_get_scan_results,
594
.deauthenticate = wpa_driver_broadcom_deauthenticate,
595
.disassociate = wpa_driver_broadcom_disassociate,
596
.associate = wpa_driver_broadcom_associate,