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