Home | History | Annotate | Download | only in drivers
      1 /*
      2  * WPA Supplicant - driver interaction with BSD net80211 layer
      3  * Copyright (c) 2004, Sam Leffler <sam (at) errno.com>
      4  *
      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.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 #include <sys/ioctl.h>
     17 
     18 #include "common.h"
     19 #include "driver.h"
     20 #include "eloop.h"
     21 #include "ieee802_11_defs.h"
     22 
     23 #include <net/if.h>
     24 
     25 #ifdef __NetBSD__
     26 #include <net/if_ether.h>
     27 #define COMPAT_FREEBSD_NET80211
     28 #else
     29 #include <net/ethernet.h>
     30 #endif
     31 
     32 #include <net80211/ieee80211.h>
     33 #include <net80211/ieee80211_crypto.h>
     34 #include <net80211/ieee80211_ioctl.h>
     35 
     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 */
     40 	unsigned int ifindex;		/* interface index */
     41 	void	*ctx;
     42 	int	prev_roaming;		/* roaming state to restore on deinit */
     43 	int	prev_privacy;		/* privacy state to restore on deinit */
     44 	int	prev_wpa;		/* wpa state to restore on deinit */
     45 };
     46 
     47 static int
     48 set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
     49 {
     50 	struct ieee80211req ireq;
     51 
     52 	os_memset(&ireq, 0, sizeof(ireq));
     53 	os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
     54 	ireq.i_type = op;
     55 	ireq.i_len = arg_len;
     56 	ireq.i_data = (void *) arg;
     57 
     58 	if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
     59 		fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n",
     60 			op, arg_len, strerror(errno));
     61 		return -1;
     62 	}
     63 	return 0;
     64 }
     65 
     66 static int
     67 get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
     68 {
     69 	struct ieee80211req ireq;
     70 
     71 	os_memset(&ireq, 0, sizeof(ireq));
     72 	os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
     73 	ireq.i_type = op;
     74 	ireq.i_len = arg_len;
     75 	ireq.i_data = arg;
     76 
     77 	if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
     78 		fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n",
     79 			op, arg_len, strerror(errno));
     80 		return -1;
     81 	}
     82 	return ireq.i_len;
     83 }
     84 
     85 static int
     86 set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
     87 {
     88 	struct ieee80211req ireq;
     89 
     90 	os_memset(&ireq, 0, sizeof(ireq));
     91 	os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
     92 	ireq.i_type = op;
     93 	ireq.i_val = arg;
     94 
     95 	if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
     96 		fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
     97 			op, arg, strerror(errno));
     98 		return -1;
     99 	}
    100 	return 0;
    101 }
    102 
    103 static int
    104 get80211param(struct wpa_driver_bsd_data *drv, int op)
    105 {
    106 	struct ieee80211req ireq;
    107 
    108 	os_memset(&ireq, 0, sizeof(ireq));
    109 	os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
    110 	ireq.i_type = op;
    111 
    112 	if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
    113 		fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
    114 			op, strerror(errno));
    115 		return -1;
    116 	}
    117 	return ireq.i_val;
    118 }
    119 
    120 static int
    121 getifflags(struct wpa_driver_bsd_data *drv, int *flags)
    122 {
    123 	struct ifreq ifr;
    124 
    125 	os_memset(&ifr, 0, sizeof(ifr));
    126 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
    127 	if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
    128 		perror("SIOCGIFFLAGS");
    129 		return errno;
    130 	}
    131 	*flags = ifr.ifr_flags & 0xffff;
    132 	return 0;
    133 }
    134 
    135 static int
    136 setifflags(struct wpa_driver_bsd_data *drv, int flags)
    137 {
    138 	struct ifreq ifr;
    139 
    140 	os_memset(&ifr, 0, sizeof(ifr));
    141 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
    142 	ifr.ifr_flags = flags & 0xffff;
    143 	if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
    144 		perror("SIOCSIFFLAGS");
    145 		return errno;
    146 	}
    147 	return 0;
    148 }
    149 
    150 static int
    151 wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
    152 {
    153 	struct wpa_driver_bsd_data *drv = priv;
    154 
    155 	return get80211var(drv, IEEE80211_IOC_BSSID,
    156 		bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
    157 }
    158 
    159 #if 0
    160 static int
    161 wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
    162 {
    163 	struct wpa_driver_bsd_data *drv = priv;
    164 
    165 	return set80211var(drv, IEEE80211_IOC_BSSID,
    166 		bssid, IEEE80211_ADDR_LEN);
    167 }
    168 #endif
    169 
    170 static int
    171 wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
    172 {
    173 	struct wpa_driver_bsd_data *drv = priv;
    174 
    175 	return get80211var(drv, IEEE80211_IOC_SSID,
    176 		ssid, IEEE80211_NWID_LEN);
    177 }
    178 
    179 static int
    180 wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid,
    181 			     size_t ssid_len)
    182 {
    183 	struct wpa_driver_bsd_data *drv = priv;
    184 
    185 	return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
    186 }
    187 
    188 static int
    189 wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
    190 	const u8 *wpa_ie, size_t wpa_ie_len)
    191 {
    192 	return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
    193 }
    194 
    195 static int
    196 wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
    197 {
    198 	struct wpa_driver_bsd_data *drv = priv;
    199 	int ret = 0;
    200 
    201 	wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
    202 		__FUNCTION__, wpa, privacy);
    203 
    204 	if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
    205 		ret = -1;
    206 	if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
    207 		ret = -1;
    208 	if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
    209 		ret = -1;
    210 
    211 	return ret;
    212 }
    213 
    214 static int
    215 wpa_driver_bsd_set_wpa(void *priv, int enabled)
    216 {
    217 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
    218 
    219 	return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
    220 }
    221 
    222 static int
    223 wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
    224 		       const unsigned char *addr)
    225 {
    226 	struct ieee80211req_del_key wk;
    227 
    228 	os_memset(&wk, 0, sizeof(wk));
    229 	if (addr != NULL &&
    230 	    bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
    231 		struct ether_addr ea;
    232 
    233 		os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
    234 		wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
    235 			__func__, ether_ntoa(&ea), key_idx);
    236 		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
    237 		wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
    238 	} else {
    239 		wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
    240 		wk.idk_keyix = key_idx;
    241 	}
    242 	return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
    243 }
    244 
    245 static int
    246 wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
    247 		       const unsigned char *addr, int key_idx, int set_tx,
    248 		       const u8 *seq, size_t seq_len,
    249 		       const u8 *key, size_t key_len)
    250 {
    251 	struct wpa_driver_bsd_data *drv = priv;
    252 	struct ieee80211req_key wk;
    253 	struct ether_addr ea;
    254 	char *alg_name;
    255 	u_int8_t cipher;
    256 
    257 	if (alg == WPA_ALG_NONE)
    258 		return wpa_driver_bsd_del_key(drv, key_idx, addr);
    259 
    260 	switch (alg) {
    261 	case WPA_ALG_WEP:
    262 		alg_name = "WEP";
    263 		cipher = IEEE80211_CIPHER_WEP;
    264 		break;
    265 	case WPA_ALG_TKIP:
    266 		alg_name = "TKIP";
    267 		cipher = IEEE80211_CIPHER_TKIP;
    268 		break;
    269 	case WPA_ALG_CCMP:
    270 		alg_name = "CCMP";
    271 		cipher = IEEE80211_CIPHER_AES_CCM;
    272 		break;
    273 	default:
    274 		wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
    275 			__func__, alg);
    276 		return -1;
    277 	}
    278 
    279 	os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
    280 	wpa_printf(MSG_DEBUG,
    281 		"%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
    282 		__func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
    283 		seq_len, key_len);
    284 
    285 	if (seq_len > sizeof(u_int64_t)) {
    286 		wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
    287 			__func__, seq_len);
    288 		return -2;
    289 	}
    290 	if (key_len > sizeof(wk.ik_keydata)) {
    291 		wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
    292 			__func__, key_len);
    293 		return -3;
    294 	}
    295 
    296 	os_memset(&wk, 0, sizeof(wk));
    297 	wk.ik_type = cipher;
    298 	wk.ik_flags = IEEE80211_KEY_RECV;
    299 	if (set_tx)
    300 		wk.ik_flags |= IEEE80211_KEY_XMIT;
    301 	os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
    302 	/*
    303 	 * Deduce whether group/global or unicast key by checking
    304 	 * the address (yech).  Note also that we can only mark global
    305 	 * keys default; doing this for a unicast key is an error.
    306 	 */
    307 	if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
    308 		wk.ik_flags |= IEEE80211_KEY_GROUP;
    309 		wk.ik_keyix = key_idx;
    310 	} else {
    311 		wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
    312 	}
    313 	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
    314 		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
    315 	wk.ik_keylen = key_len;
    316 	os_memcpy(&wk.ik_keyrsc, seq, seq_len);
    317 	os_memcpy(wk.ik_keydata, key, key_len);
    318 
    319 	return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
    320 }
    321 
    322 static int
    323 wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
    324 {
    325 	struct wpa_driver_bsd_data *drv = priv;
    326 
    327 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
    328 	return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
    329 }
    330 
    331 
    332 static int
    333 wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
    334 {
    335 	struct wpa_driver_bsd_data *drv = priv;
    336 
    337 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
    338 	return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
    339 }
    340 
    341 static int
    342 wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
    343 {
    344 	struct wpa_driver_bsd_data *drv = priv;
    345 	struct ieee80211req_mlme mlme;
    346 
    347 	wpa_printf(MSG_DEBUG, "%s", __func__);
    348 	os_memset(&mlme, 0, sizeof(mlme));
    349 	mlme.im_op = IEEE80211_MLME_DEAUTH;
    350 	mlme.im_reason = reason_code;
    351 	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
    352 	return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
    353 }
    354 
    355 static int
    356 wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
    357 {
    358 	struct wpa_driver_bsd_data *drv = priv;
    359 	struct ieee80211req_mlme mlme;
    360 
    361 	wpa_printf(MSG_DEBUG, "%s", __func__);
    362 	os_memset(&mlme, 0, sizeof(mlme));
    363 	mlme.im_op = IEEE80211_MLME_DISASSOC;
    364 	mlme.im_reason = reason_code;
    365 	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
    366 	return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
    367 }
    368 
    369 static int
    370 wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
    371 {
    372 	struct wpa_driver_bsd_data *drv = priv;
    373 	struct ieee80211req_mlme mlme;
    374 	int privacy;
    375 
    376 	wpa_printf(MSG_DEBUG,
    377 		"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
    378 		, __func__
    379 		, params->ssid_len, params->ssid
    380 		, params->wpa_ie_len
    381 		, params->pairwise_suite
    382 		, params->group_suite
    383 		, params->key_mgmt_suite
    384 	);
    385 
    386 	/* XXX error handling is wrong but unclear what to do... */
    387 	if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
    388 		return -1;
    389 
    390 	privacy = !(params->pairwise_suite == CIPHER_NONE &&
    391 	    params->group_suite == CIPHER_NONE &&
    392 	    params->key_mgmt_suite == KEY_MGMT_NONE &&
    393 	    params->wpa_ie_len == 0);
    394 	wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
    395 
    396 	if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
    397 		return -1;
    398 
    399 	if (params->wpa_ie_len &&
    400 	    set80211param(drv, IEEE80211_IOC_WPA,
    401 			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
    402 		return -1;
    403 
    404 	os_memset(&mlme, 0, sizeof(mlme));
    405 	mlme.im_op = IEEE80211_MLME_ASSOC;
    406 	if (params->ssid != NULL)
    407 		os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
    408 	mlme.im_ssid_len = params->ssid_len;
    409 	if (params->bssid != NULL)
    410 		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
    411 	if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
    412 		return -1;
    413 	return 0;
    414 }
    415 
    416 static int
    417 wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
    418 {
    419 	struct wpa_driver_bsd_data *drv = priv;
    420 	int authmode;
    421 
    422 	if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
    423 	    (auth_alg & AUTH_ALG_SHARED_KEY))
    424 		authmode = IEEE80211_AUTH_AUTO;
    425 	else if (auth_alg & AUTH_ALG_SHARED_KEY)
    426 		authmode = IEEE80211_AUTH_SHARED;
    427 	else
    428 		authmode = IEEE80211_AUTH_OPEN;
    429 
    430 	return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
    431 }
    432 
    433 static int
    434 wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
    435 {
    436 	struct wpa_driver_bsd_data *drv = priv;
    437 	int flags;
    438 
    439 	/* NB: interface must be marked UP to do a scan */
    440 	if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
    441 		return -1;
    442 
    443 	/* set desired ssid before scan */
    444 	if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
    445 		return -1;
    446 
    447 	/* NB: net80211 delivers a scan complete event so no need to poll */
    448 	return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
    449 }
    450 
    451 #include <net/route.h>
    452 #if __FreeBSD__
    453 #include <net80211/ieee80211_freebsd.h>
    454 #endif
    455 #if __NetBSD__
    456 #include <net80211/ieee80211_netbsd.h>
    457 #endif
    458 
    459 static void
    460 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
    461 {
    462 	struct wpa_driver_bsd_data *drv = sock_ctx;
    463 	char buf[2048];
    464 	struct if_announcemsghdr *ifan;
    465 	struct if_msghdr *ifm;
    466 	struct rt_msghdr *rtm;
    467 	union wpa_event_data event;
    468 	struct ieee80211_michael_event *mic;
    469 	int n;
    470 
    471 	n = read(sock, buf, sizeof(buf));
    472 	if (n < 0) {
    473 		if (errno != EINTR && errno != EAGAIN)
    474 			perror("read(PF_ROUTE)");
    475 		return;
    476 	}
    477 
    478 	rtm = (struct rt_msghdr *) buf;
    479 	if (rtm->rtm_version != RTM_VERSION) {
    480 		wpa_printf(MSG_DEBUG, "Routing message version %d not "
    481 			"understood\n", rtm->rtm_version);
    482 		return;
    483 	}
    484 	os_memset(&event, 0, sizeof(event));
    485 	switch (rtm->rtm_type) {
    486 	case RTM_IFANNOUNCE:
    487 		ifan = (struct if_announcemsghdr *) rtm;
    488 		if (ifan->ifan_index != drv->ifindex)
    489 			break;
    490 		strlcpy(event.interface_status.ifname, drv->ifname,
    491 			sizeof(event.interface_status.ifname));
    492 		switch (ifan->ifan_what) {
    493 		case IFAN_DEPARTURE:
    494 			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
    495 		default:
    496 			return;
    497 		}
    498 		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
    499 			   event.interface_status.ifname,
    500 			   ifan->ifan_what == IFAN_DEPARTURE ?
    501 				"removed" : "added");
    502 		wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
    503 		break;
    504 	case RTM_IEEE80211:
    505 		ifan = (struct if_announcemsghdr *) rtm;
    506 		if (ifan->ifan_index != drv->ifindex)
    507 			break;
    508 		switch (ifan->ifan_what) {
    509 		case RTM_IEEE80211_ASSOC:
    510 		case RTM_IEEE80211_REASSOC:
    511 			wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
    512 			break;
    513 		case RTM_IEEE80211_DISASSOC:
    514 			wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
    515 			break;
    516 		case RTM_IEEE80211_SCAN:
    517 			wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
    518 			break;
    519 		case RTM_IEEE80211_REPLAY:
    520 			/* ignore */
    521 			break;
    522 		case RTM_IEEE80211_MICHAEL:
    523 			mic = (struct ieee80211_michael_event *) &ifan[1];
    524 			wpa_printf(MSG_DEBUG,
    525 				"Michael MIC failure wireless event: "
    526 				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
    527 				MAC2STR(mic->iev_src));
    528 
    529 			os_memset(&event, 0, sizeof(event));
    530 			event.michael_mic_failure.unicast =
    531 				!IEEE80211_IS_MULTICAST(mic->iev_dst);
    532 			wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
    533 				&event);
    534 			break;
    535 		}
    536 		break;
    537 	case RTM_IFINFO:
    538 		ifm = (struct if_msghdr *) rtm;
    539 		if (ifm->ifm_index != drv->ifindex)
    540 			break;
    541 		if ((rtm->rtm_flags & RTF_UP) == 0) {
    542 			strlcpy(event.interface_status.ifname, drv->ifname,
    543 				sizeof(event.interface_status.ifname));
    544 			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
    545 			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
    546 				   event.interface_status.ifname);
    547 			wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
    548 		}
    549 		break;
    550 	}
    551 }
    552 
    553 /* Compare function for sorting scan results. Return >0 if @b is consider
    554  * better. */
    555 static int
    556 wpa_scan_result_compar(const void *a, const void *b)
    557 {
    558 	const struct wpa_scan_result *wa = a;
    559 	const struct wpa_scan_result *wb = b;
    560 
    561 	/* WPA/WPA2 support preferred */
    562 	if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
    563 	    !(wa->wpa_ie_len || wa->rsn_ie_len))
    564 		return 1;
    565 	if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
    566 	    (wa->wpa_ie_len || wa->rsn_ie_len))
    567 		return -1;
    568 
    569 	/* privacy support preferred */
    570 	if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
    571 	    (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
    572 		return 1;
    573 	if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
    574 	    (wb->caps & IEEE80211_CAPINFO_PRIVACY))
    575 		return -1;
    576 
    577 	/* best/max rate preferred if signal level close enough XXX */
    578 	if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
    579 		return wb->maxrate - wa->maxrate;
    580 
    581 	/* use freq for channel preference */
    582 
    583 	/* all things being equal, use signal level */
    584 	return wb->level - wa->level;
    585 }
    586 
    587 static int
    588 getmaxrate(uint8_t rates[15], uint8_t nrates)
    589 {
    590 	int i, maxrate = -1;
    591 
    592 	for (i = 0; i < nrates; i++) {
    593 		int rate = rates[i] & IEEE80211_RATE_VAL;
    594 		if (rate > maxrate)
    595 			rate = maxrate;
    596 	}
    597 	return maxrate;
    598 }
    599 
    600 /* unalligned little endian access */
    601 #define LE_READ_4(p)					\
    602 	((u_int32_t)					\
    603 	 ((((const u_int8_t *)(p))[0]      ) |		\
    604 	  (((const u_int8_t *)(p))[1] <<  8) |		\
    605 	  (((const u_int8_t *)(p))[2] << 16) |		\
    606 	  (((const u_int8_t *)(p))[3] << 24)))
    607 
    608 static int __inline
    609 iswpaoui(const u_int8_t *frm)
    610 {
    611 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
    612 }
    613 
    614 static int
    615 wpa_driver_bsd_get_scan_results(void *priv,
    616 				     struct wpa_scan_result *results,
    617 				     size_t max_size)
    618 {
    619 #define	min(a,b)	((a)>(b)?(b):(a))
    620 	struct wpa_driver_bsd_data *drv = priv;
    621 	uint8_t buf[24*1024];
    622 	uint8_t *cp, *vp;
    623 	struct ieee80211req_scan_result *sr;
    624 	struct wpa_scan_result *wsr;
    625 	int len, ielen;
    626 
    627 	os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
    628 
    629 	len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
    630 	if (len < 0)
    631 		return -1;
    632 	cp = buf;
    633 	wsr = results;
    634 	while (len >= sizeof(struct ieee80211req_scan_result)) {
    635 		sr = (struct ieee80211req_scan_result *) cp;
    636 		os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
    637 		wsr->ssid_len = sr->isr_ssid_len;
    638 		wsr->freq = sr->isr_freq;
    639 		wsr->noise = sr->isr_noise;
    640 		wsr->qual = sr->isr_rssi;
    641 		wsr->level = 0;		/* XXX? */
    642 		wsr->caps = sr->isr_capinfo;
    643 		wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
    644 		vp = (u_int8_t *)(sr+1);
    645 		os_memcpy(wsr->ssid, vp, sr->isr_ssid_len);
    646 		if (sr->isr_ie_len > 0) {
    647 			vp += sr->isr_ssid_len;
    648 			ielen = sr->isr_ie_len;
    649 			while (ielen > 0) {
    650 				switch (vp[0]) {
    651 				case IEEE80211_ELEMID_VENDOR:
    652 					if (!iswpaoui(vp))
    653 						break;
    654 					wsr->wpa_ie_len =
    655 					    min(2+vp[1], SSID_MAX_WPA_IE_LEN);
    656 					os_memcpy(wsr->wpa_ie, vp,
    657 						  wsr->wpa_ie_len);
    658 					break;
    659 				case IEEE80211_ELEMID_RSN:
    660 					wsr->rsn_ie_len =
    661 					    min(2+vp[1], SSID_MAX_WPA_IE_LEN);
    662 					os_memcpy(wsr->rsn_ie, vp,
    663 						  wsr->rsn_ie_len);
    664 					break;
    665 				}
    666 				ielen -= 2+vp[1];
    667 				vp += 2+vp[1];
    668 			}
    669 		}
    670 
    671 		cp += sr->isr_len, len -= sr->isr_len;
    672 		wsr++;
    673 	}
    674 	qsort(results, wsr - results, sizeof(struct wpa_scan_result),
    675 	      wpa_scan_result_compar);
    676 
    677 	wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
    678 		   len, wsr - results);
    679 
    680 	return wsr - results;
    681 #undef min
    682 }
    683 
    684 static void *
    685 wpa_driver_bsd_init(void *ctx, const char *ifname)
    686 {
    687 #define	GETPARAM(drv, param, v) \
    688 	(((v) = get80211param(drv, param)) != -1)
    689 	struct wpa_driver_bsd_data *drv;
    690 
    691 	drv = os_zalloc(sizeof(*drv));
    692 	if (drv == NULL)
    693 		return NULL;
    694 	/*
    695 	 * NB: We require the interface name be mappable to an index.
    696 	 *     This implies we do not support having wpa_supplicant
    697 	 *     wait for an interface to appear.  This seems ok; that
    698 	 *     doesn't belong here; it's really the job of devd.
    699 	 */
    700 	drv->ifindex = if_nametoindex(ifname);
    701 	if (drv->ifindex == 0) {
    702 		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
    703 			   __func__, ifname);
    704 		goto fail1;
    705 	}
    706 	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
    707 	if (drv->sock < 0)
    708 		goto fail1;
    709 	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
    710 	if (drv->route < 0)
    711 		goto fail;
    712 	eloop_register_read_sock(drv->route,
    713 		wpa_driver_bsd_event_receive, ctx, drv);
    714 
    715 	drv->ctx = ctx;
    716 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
    717 
    718 	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
    719 		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
    720 			__func__, strerror(errno));
    721 		goto fail;
    722 	}
    723 	if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
    724 		wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
    725 			__func__, strerror(errno));
    726 		goto fail;
    727 	}
    728 	if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
    729 		wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
    730 			__func__, strerror(errno));
    731 		goto fail;
    732 	}
    733 	if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
    734 		wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
    735 			   "roaming: %s", __func__, strerror(errno));
    736 		goto fail;
    737 	}
    738 
    739 	if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
    740 		wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
    741 			   __func__, strerror(errno));
    742 		goto fail;
    743 	}
    744 
    745 	return drv;
    746 fail:
    747 	close(drv->sock);
    748 fail1:
    749 	os_free(drv);
    750 	return NULL;
    751 #undef GETPARAM
    752 }
    753 
    754 static void
    755 wpa_driver_bsd_deinit(void *priv)
    756 {
    757 	struct wpa_driver_bsd_data *drv = priv;
    758 	int flags;
    759 
    760 	eloop_unregister_read_sock(drv->route);
    761 
    762 	/* NB: mark interface down */
    763 	if (getifflags(drv, &flags) == 0)
    764 		(void) setifflags(drv, flags &~ IFF_UP);
    765 
    766 	wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
    767 	if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
    768 		wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
    769 			__func__);
    770 
    771 	(void) close(drv->route);		/* ioctl socket */
    772 	(void) close(drv->sock);		/* event socket */
    773 	os_free(drv);
    774 }
    775 
    776 
    777 const struct wpa_driver_ops wpa_driver_bsd_ops = {
    778 	.name			= "bsd",
    779 	.desc			= "BSD 802.11 support (Atheros, etc.)",
    780 	.init			= wpa_driver_bsd_init,
    781 	.deinit			= wpa_driver_bsd_deinit,
    782 	.get_bssid		= wpa_driver_bsd_get_bssid,
    783 	.get_ssid		= wpa_driver_bsd_get_ssid,
    784 	.set_wpa		= wpa_driver_bsd_set_wpa,
    785 	.set_key		= wpa_driver_bsd_set_key,
    786 	.set_countermeasures	= wpa_driver_bsd_set_countermeasures,
    787 	.set_drop_unencrypted	= wpa_driver_bsd_set_drop_unencrypted,
    788 	.scan			= wpa_driver_bsd_scan,
    789 	.get_scan_results	= wpa_driver_bsd_get_scan_results,
    790 	.deauthenticate		= wpa_driver_bsd_deauthenticate,
    791 	.disassociate		= wpa_driver_bsd_disassociate,
    792 	.associate		= wpa_driver_bsd_associate,
    793 	.set_auth_alg		= wpa_driver_bsd_set_auth_alg,
    794 };
    795