2
* WPA Supplicant - driver interaction with BSD net80211 layer
3
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
9
* Alternatively, this software may be distributed under the terms of BSD
12
* See README and COPYING for more details.
19
#include <sys/ioctl.h>
24
#include "driver_wext.h"
26
#include "wpa_supplicant.h"
27
#include "l2_packet.h"
29
#include <sys/socket.h>
32
#include <net80211/ieee80211.h>
33
#include <net80211/ieee80211_crypto.h>
34
#include <net80211/ieee80211_ioctl.h>
36
struct wpa_driver_bsd_data {
37
int sock; /* open socket for 802.11 ioctls */
38
int route; /* routing socket for events */
39
char ifname[IFNAMSIZ+1]; /* interface name */
44
set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
46
struct ieee80211req ireq;
48
memset(&ireq, 0, sizeof(ireq));
49
strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
52
ireq.i_data = (void *) arg;
54
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
55
perror("ioctl[SIOCS80211]");
62
get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
64
struct ieee80211req ireq;
66
memset(&ireq, 0, sizeof(ireq));
67
strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
72
if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
73
perror("ioctl[SIOCG80211]");
80
set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
82
struct ieee80211req ireq;
84
memset(&ireq, 0, sizeof(ireq));
85
strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
89
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
90
perror("ioctl[SIOCS80211]");
97
getifflags(struct wpa_driver_bsd_data *drv, int *flags)
101
memset(&ifr, 0, sizeof(ifr));
102
strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
103
if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
104
perror("SIOCGIFFLAGS");
107
*flags = ifr.ifr_flags & 0xffff;
112
setifflags(struct wpa_driver_bsd_data *drv, int flags)
116
memset(&ifr, 0, sizeof(ifr));
117
strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
118
ifr.ifr_flags = flags & 0xffff;
119
if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
120
perror("SIOCSIFFLAGS");
127
wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
129
struct wpa_driver_bsd_data *drv = priv;
131
return get80211var(drv, IEEE80211_IOC_BSSID,
132
bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
137
wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
139
struct wpa_driver_bsd_data *drv = priv;
141
return set80211var(drv, IEEE80211_IOC_BSSID,
142
bssid, IEEE80211_ADDR_LEN);
147
wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
149
struct wpa_driver_bsd_data *drv = priv;
151
return get80211var(drv, IEEE80211_IOC_SSID,
152
ssid, IEEE80211_NWID_LEN);
156
wpa_driver_bsd_set_ssid(void *priv, const char *ssid,
159
struct wpa_driver_bsd_data *drv = priv;
161
return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
165
wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
166
const char *wpa_ie, size_t wpa_ie_len)
168
return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
172
wpa_driver_bsd_set_wpa(void *priv, int enabled)
174
struct wpa_driver_bsd_data *drv = priv;
177
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
179
if (!enabled && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
181
if (set80211param(drv, IEEE80211_IOC_ROAMING, enabled ? 2 : 0) < 0)
183
if (set80211param(drv, IEEE80211_IOC_PRIVACY, enabled) < 0)
185
if (set80211param(drv, IEEE80211_IOC_WPA, enabled ? 3 : 0) < 0)
192
wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
193
const unsigned char *addr)
195
struct ieee80211req_del_key wk;
197
wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
198
memset(&wk, 0, sizeof(wk));
199
wk.idk_keyix = key_idx;
201
memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
203
return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
207
wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
208
const unsigned char *addr, int key_idx, int set_tx,
209
const u8 *seq, size_t seq_len,
210
const u8 *key, size_t key_len)
212
struct wpa_driver_bsd_data *drv = priv;
213
struct ieee80211req_key wk;
217
if (alg == WPA_ALG_NONE)
218
return wpa_driver_bsd_del_key(drv, key_idx, addr);
223
cipher = IEEE80211_CIPHER_WEP;
227
cipher = IEEE80211_CIPHER_TKIP;
231
cipher = IEEE80211_CIPHER_AES_CCM;
234
wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
239
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%d "
240
"key_len=%d", __FUNCTION__, alg_name, key_idx, set_tx,
243
if (seq_len > sizeof(u_int64_t)) {
244
wpa_printf(MSG_DEBUG, "%s: seq_len %d too big",
245
__FUNCTION__, seq_len);
248
if (key_len > sizeof(wk.ik_keydata)) {
249
wpa_printf(MSG_DEBUG, "%s: key length %d too big",
250
__FUNCTION__, key_len);
254
memset(&wk, 0, sizeof(wk));
256
wk.ik_flags = IEEE80211_KEY_RECV;
258
wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
259
memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
261
memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
262
wk.ik_keyix = key_idx;
263
wk.ik_keylen = key_len;
264
memcpy(&wk.ik_keyrsc, seq, seq_len);
265
memcpy(wk.ik_keydata, key, key_len);
267
return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
271
wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
273
struct wpa_driver_bsd_data *drv = priv;
275
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
276
return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
281
wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
283
struct wpa_driver_bsd_data *drv = priv;
285
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
286
return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
290
wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
292
struct wpa_driver_bsd_data *drv = priv;
293
struct ieee80211req_mlme mlme;
295
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
296
mlme.im_op = IEEE80211_MLME_DEAUTH;
297
mlme.im_reason = reason_code;
298
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
299
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
303
wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
305
struct wpa_driver_bsd_data *drv = priv;
306
struct ieee80211req_mlme mlme;
308
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
309
mlme.im_op = IEEE80211_MLME_DISASSOC;
310
mlme.im_reason = reason_code;
311
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
312
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
316
wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
318
struct wpa_driver_bsd_data *drv = priv;
319
struct ieee80211req_mlme mlme;
323
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
326
* NB: Don't need to set the freq or cipher-related state as
327
* this is implied by the bssid which is used to locate
328
* the scanned node state which holds it. The ssid is
329
* needed to disambiguate an AP that broadcasts multiple
330
* ssid's but uses the same bssid.
332
/* XXX error handling is wrong but unclear what to do... */
333
if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
335
if (wpa_driver_bsd_set_ssid(drv, params->ssid, params->ssid_len) < 0)
337
memset(&mlme, 0, sizeof(mlme));
338
mlme.im_op = IEEE80211_MLME_ASSOC;
339
memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
340
if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
347
wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
349
struct wpa_driver_bsd_data *drv = priv;
352
/* NB: interface must be marked UP to do a scan */
353
if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
356
/* set desired ssid before scan */
357
if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
360
/* NB: net80211 delivers a scan complete event so no need to poll */
361
return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
364
#include <net/route.h>
365
#include <net80211/ieee80211_freebsd.h>
368
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
371
struct if_announcemsghdr *ifan;
372
struct rt_msghdr *rtm;
373
union wpa_event_data event;
374
struct ieee80211_michael_event *mic;
377
n = read(sock, buf, sizeof(buf));
379
if (errno != EINTR && errno != EAGAIN)
380
perror("read(PF_ROUTE)");
384
rtm = (struct rt_msghdr *) buf;
385
if (rtm->rtm_version != RTM_VERSION) {
386
wpa_printf(MSG_DEBUG, "Routing message version %d not "
387
"understood\n", rtm->rtm_version);
390
ifan = (struct if_announcemsghdr *) rtm;
391
switch (rtm->rtm_type) {
393
memset(&event, 0, sizeof(event));
394
/* XXX name buffer must be >= IFNAMSIZ */
395
/* XXX check return value */
396
if_indextoname(ifan->ifan_index, event.interface_status.ifname);
397
switch (ifan->ifan_what) {
399
event.interface_status.ievent = EVENT_INTERFACE_ADDED;
402
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
406
wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
407
event.interface_status.ifname,
408
ifan->ifan_what == IFAN_DEPARTURE ?
409
"removed" : "added");
410
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
413
switch (ifan->ifan_what) {
414
case RTM_IEEE80211_ASSOC:
415
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
417
case RTM_IEEE80211_DISASSOC:
418
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
420
case RTM_IEEE80211_SCAN:
421
wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
423
case RTM_IEEE80211_REASSOC:
424
case RTM_IEEE80211_REPLAY:
427
case RTM_IEEE80211_MICHAEL:
428
mic = (struct ieee80211_michael_event *) &ifan[1];
429
wpa_printf(MSG_DEBUG,
430
"Michael MIC failure wireless event: "
431
"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
432
MAC2STR(mic->iev_src));
434
memset(&event, 0, sizeof(event));
435
event.michael_mic_failure.unicast =
436
!IEEE80211_IS_MULTICAST(mic->iev_dst);
437
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
445
/* Compare function for sorting scan results. Return >0 if @b is consider
448
wpa_scan_result_compar(const void *a, const void *b)
450
const struct wpa_scan_result *wa = a;
451
const struct wpa_scan_result *wb = b;
453
/* WPA/WPA2 support preferred */
454
if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
455
!(wa->wpa_ie_len || wa->rsn_ie_len))
457
if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
458
(wa->wpa_ie_len || wa->rsn_ie_len))
461
/* privacy support preferred */
462
if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
463
(wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
465
if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
466
(wb->caps & IEEE80211_CAPINFO_PRIVACY))
469
/* best/max rate preferred if signal level close enough XXX */
470
if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
471
return wb->maxrate - wa->maxrate;
473
/* use freq for channel preference */
475
/* all things being equal, use signal level */
476
return wb->level - wa->level;
480
getmaxrate(uint8_t rates[15], uint8_t nrates)
484
for (i = 0; i < nrates; i++) {
485
int rate = rates[i] & IEEE80211_RATE_VAL;
492
/* unalligned little endian access */
493
#define LE_READ_4(p) \
495
((((const u_int8_t *)(p))[0] ) | \
496
(((const u_int8_t *)(p))[1] << 8) | \
497
(((const u_int8_t *)(p))[2] << 16) | \
498
(((const u_int8_t *)(p))[3] << 24)))
501
iswpaoui(const u_int8_t *frm)
503
return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
507
wpa_driver_bsd_get_scan_results(void *priv,
508
struct wpa_scan_result *results,
511
#define min(a,b) ((a)>(b)?(b):(a))
512
struct wpa_driver_bsd_data *drv = priv;
513
uint8_t buf[24*1024];
515
struct ieee80211req_scan_result *sr;
516
struct wpa_scan_result *wsr;
519
memset(results, 0, max_size * sizeof(struct wpa_scan_result));
521
len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
526
while (len >= sizeof(struct ieee80211req_scan_result)) {
527
sr = (struct ieee80211req_scan_result *) cp;
528
memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
529
wsr->ssid_len = sr->isr_ssid_len;
530
wsr->freq = sr->isr_freq;
531
wsr->noise = sr->isr_noise;
532
wsr->qual = sr->isr_rssi;
533
wsr->level = 0; /* XXX? */
534
wsr->caps = sr->isr_capinfo;
535
wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
536
vp = (u_int8_t *)(sr+1);
537
memcpy(wsr->ssid, vp, sr->isr_ssid_len);
538
if (sr->isr_ie_len > 0) {
539
vp += sr->isr_ssid_len;
540
ielen = sr->isr_ie_len;
543
case IEEE80211_ELEMID_VENDOR:
547
min(2+vp[1], SSID_MAX_WPA_IE_LEN);
548
memcpy(wsr->wpa_ie, vp, wsr->wpa_ie_len);
550
case IEEE80211_ELEMID_RSN:
552
min(2+vp[1], SSID_MAX_WPA_IE_LEN);
553
memcpy(wsr->rsn_ie, vp, wsr->rsn_ie_len);
561
cp += sr->isr_len, len -= sr->isr_len;
564
qsort(results, wsr - results, sizeof(struct wpa_scan_result),
565
wpa_scan_result_compar);
567
wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
570
return wsr - results;
575
wpa_driver_bsd_init(void *ctx, const char *ifname)
577
struct wpa_driver_bsd_data *drv;
579
drv = malloc(sizeof(*drv));
582
memset(drv, 0, sizeof(*drv));
583
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
588
drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
589
if (drv->route < 0) {
594
eloop_register_read_sock(drv->route,
595
wpa_driver_bsd_event_receive, ctx, NULL);
598
strncpy(drv->ifname, ifname, sizeof(drv->ifname));
604
wpa_driver_bsd_deinit(void *priv)
606
struct wpa_driver_bsd_data *drv = priv;
609
/* NB: mark interface down */
610
if (getifflags(drv, &flags) == 0)
611
(void) setifflags(drv, flags &~ IFF_UP);
613
(void) close(drv->route); /* ioctl socket */
614
(void) close(drv->sock); /* event socket */
619
struct wpa_driver_ops wpa_driver_bsd_ops = {
621
.desc = "BSD 802.11 support (Atheros, etc.)",
622
.init = wpa_driver_bsd_init,
623
.deinit = wpa_driver_bsd_deinit,
624
.get_bssid = wpa_driver_bsd_get_bssid,
625
.get_ssid = wpa_driver_bsd_get_ssid,
626
.set_wpa = wpa_driver_bsd_set_wpa,
627
.set_key = wpa_driver_bsd_set_key,
628
.set_countermeasures = wpa_driver_bsd_set_countermeasures,
629
.set_drop_unencrypted = wpa_driver_bsd_set_drop_unencrypted,
630
.scan = wpa_driver_bsd_scan,
631
.get_scan_results = wpa_driver_bsd_get_scan_results,
632
.deauthenticate = wpa_driver_bsd_deauthenticate,
633
.disassociate = wpa_driver_bsd_disassociate,
634
.associate = wpa_driver_bsd_associate,