driver_bsd.c revision 252190
1209139Srpaulo/*
2209139Srpaulo * WPA Supplicant - driver interaction with BSD net80211 layer
3209139Srpaulo * Copyright (c) 2004, Sam Leffler <sam@errno.com>
4214501Srpaulo * Copyright (c) 2004, 2Wire, Inc
5209139Srpaulo *
6252190Srpaulo * This software may be distributed under the terms of the BSD license.
7252190Srpaulo * See README for more details.
8209139Srpaulo */
9209139Srpaulo
10209139Srpaulo#include "includes.h"
11209139Srpaulo#include <sys/ioctl.h>
12252190Srpaulo#include <sys/sysctl.h>
13209139Srpaulo
14209139Srpaulo#include "common.h"
15209139Srpaulo#include "driver.h"
16209139Srpaulo#include "eloop.h"
17214501Srpaulo#include "common/ieee802_11_defs.h"
18252190Srpaulo#include "common/wpa_common.h"
19209139Srpaulo
20209139Srpaulo#include <net/if.h>
21214501Srpaulo#include <net/if_media.h>
22209139Srpaulo
23209139Srpaulo#ifdef __NetBSD__
24209139Srpaulo#include <net/if_ether.h>
25209139Srpaulo#else
26209139Srpaulo#include <net/ethernet.h>
27209139Srpaulo#endif
28214501Srpaulo#include <net/route.h>
29209139Srpaulo
30214501Srpaulo#ifdef __DragonFly__
31214501Srpaulo#include <netproto/802_11/ieee80211_ioctl.h>
32214501Srpaulo#include <netproto/802_11/ieee80211_dragonfly.h>
33214501Srpaulo#else /* __DragonFly__ */
34214501Srpaulo#ifdef __GLIBC__
35214501Srpaulo#include <netinet/ether.h>
36214501Srpaulo#endif /* __GLIBC__ */
37209139Srpaulo#include <net80211/ieee80211.h>
38214501Srpaulo#include <net80211/ieee80211_ioctl.h>
39209139Srpaulo#include <net80211/ieee80211_crypto.h>
40214501Srpaulo#endif /* __DragonFly__ || __GLIBC__ */
41214501Srpaulo#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
42214501Srpaulo#include <net80211/ieee80211_freebsd.h>
43214501Srpaulo#endif
44214501Srpaulo#if __NetBSD__
45214501Srpaulo#include <net80211/ieee80211_netbsd.h>
46214501Srpaulo#endif
47209139Srpaulo
48214501Srpaulo#include "l2_packet/l2_packet.h"
49214501Srpaulo
50214501Srpaulostruct bsd_driver_data {
51214501Srpaulo	struct hostapd_data *hapd;	/* back pointer */
52214501Srpaulo
53209139Srpaulo	int	sock;			/* open socket for 802.11 ioctls */
54214501Srpaulo	struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
55209139Srpaulo	int	route;			/* routing socket for events */
56209139Srpaulo	char	ifname[IFNAMSIZ+1];	/* interface name */
57209139Srpaulo	unsigned int ifindex;		/* interface index */
58209139Srpaulo	void	*ctx;
59214501Srpaulo	struct wpa_driver_capa capa;	/* driver capability */
60214501Srpaulo	int	is_ap;			/* Access point mode */
61214501Srpaulo	int	prev_roaming;	/* roaming state to restore on deinit */
62214501Srpaulo	int	prev_privacy;	/* privacy state to restore on deinit */
63214501Srpaulo	int	prev_wpa;	/* wpa state to restore on deinit */
64209139Srpaulo};
65209139Srpaulo
66214501Srpaulo/* Generic functions for hostapd and wpa_supplicant */
67214501Srpaulo
68209139Srpaulostatic int
69214501Srpaulobsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
70209139Srpaulo{
71214501Srpaulo	struct bsd_driver_data *drv = priv;
72209139Srpaulo	struct ieee80211req ireq;
73209139Srpaulo
74209139Srpaulo	os_memset(&ireq, 0, sizeof(ireq));
75214501Srpaulo	os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
76209139Srpaulo	ireq.i_type = op;
77214501Srpaulo	ireq.i_val = val;
78214501Srpaulo	ireq.i_data = (void *) arg;
79209139Srpaulo	ireq.i_len = arg_len;
80209139Srpaulo
81209139Srpaulo	if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
82214501Srpaulo		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
83214501Srpaulo			   "arg_len=%u]: %s", op, val, arg_len,
84214501Srpaulo			   strerror(errno));
85209139Srpaulo		return -1;
86209139Srpaulo	}
87209139Srpaulo	return 0;
88209139Srpaulo}
89209139Srpaulo
90209139Srpaulostatic int
91214501Srpaulobsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
92214501Srpaulo	     int arg_len)
93209139Srpaulo{
94214501Srpaulo	struct bsd_driver_data *drv = priv;
95209139Srpaulo
96214501Srpaulo	os_memset(ireq, 0, sizeof(*ireq));
97214501Srpaulo	os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name));
98214501Srpaulo	ireq->i_type = op;
99214501Srpaulo	ireq->i_len = arg_len;
100214501Srpaulo	ireq->i_data = arg;
101209139Srpaulo
102214501Srpaulo	if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
103214501Srpaulo		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
104214501Srpaulo			   "arg_len=%u]: %s", op, arg_len, strerror(errno));
105209139Srpaulo		return -1;
106209139Srpaulo	}
107214501Srpaulo	return 0;
108209139Srpaulo}
109209139Srpaulo
110209139Srpaulostatic int
111214501Srpauloget80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
112209139Srpaulo{
113209139Srpaulo	struct ieee80211req ireq;
114209139Srpaulo
115214501Srpaulo	if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0)
116209139Srpaulo		return -1;
117214501Srpaulo	return ireq.i_len;
118209139Srpaulo}
119209139Srpaulo
120209139Srpaulostatic int
121214501Srpauloset80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
122209139Srpaulo{
123214501Srpaulo	return bsd_set80211(drv, op, 0, arg, arg_len);
124214501Srpaulo}
125209139Srpaulo
126214501Srpaulostatic int
127214501Srpauloset80211param(struct bsd_driver_data *drv, int op, int arg)
128214501Srpaulo{
129214501Srpaulo	return bsd_set80211(drv, op, arg, NULL, 0);
130209139Srpaulo}
131209139Srpaulo
132209139Srpaulostatic int
133214501Srpaulobsd_get_ssid(void *priv, u8 *ssid, int len)
134209139Srpaulo{
135214501Srpaulo	struct bsd_driver_data *drv = priv;
136214501Srpaulo#ifdef SIOCG80211NWID
137214501Srpaulo	struct ieee80211_nwid nwid;
138209139Srpaulo	struct ifreq ifr;
139209139Srpaulo
140209139Srpaulo	os_memset(&ifr, 0, sizeof(ifr));
141209139Srpaulo	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
142214501Srpaulo	ifr.ifr_data = (void *)&nwid;
143214501Srpaulo	if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
144214501Srpaulo	    nwid.i_len > IEEE80211_NWID_LEN)
145214501Srpaulo		return -1;
146214501Srpaulo	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
147214501Srpaulo	return nwid.i_len;
148214501Srpaulo#else
149214501Srpaulo	return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN);
150214501Srpaulo#endif
151209139Srpaulo}
152209139Srpaulo
153209139Srpaulostatic int
154214501Srpaulobsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
155209139Srpaulo{
156214501Srpaulo	struct bsd_driver_data *drv = priv;
157214501Srpaulo#ifdef SIOCS80211NWID
158214501Srpaulo	struct ieee80211_nwid nwid;
159209139Srpaulo	struct ifreq ifr;
160209139Srpaulo
161214501Srpaulo	os_memcpy(nwid.i_nwid, ssid, ssid_len);
162214501Srpaulo	nwid.i_len = ssid_len;
163209139Srpaulo	os_memset(&ifr, 0, sizeof(ifr));
164209139Srpaulo	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
165214501Srpaulo	ifr.ifr_data = (void *)&nwid;
166214501Srpaulo	return ioctl(drv->sock, SIOCS80211NWID, &ifr);
167214501Srpaulo#else
168214501Srpaulo	return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
169214501Srpaulo#endif
170209139Srpaulo}
171209139Srpaulo
172209139Srpaulostatic int
173214501Srpaulobsd_get_if_media(void *priv)
174209139Srpaulo{
175214501Srpaulo	struct bsd_driver_data *drv = priv;
176214501Srpaulo	struct ifmediareq ifmr;
177209139Srpaulo
178214501Srpaulo	os_memset(&ifmr, 0, sizeof(ifmr));
179214501Srpaulo	os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
180209139Srpaulo
181214501Srpaulo	if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
182214501Srpaulo		wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
183214501Srpaulo			   strerror(errno));
184214501Srpaulo		return -1;
185214501Srpaulo	}
186209139Srpaulo
187214501Srpaulo	return ifmr.ifm_current;
188209139Srpaulo}
189209139Srpaulo
190209139Srpaulostatic int
191214501Srpaulobsd_set_if_media(void *priv, int media)
192209139Srpaulo{
193214501Srpaulo	struct bsd_driver_data *drv = priv;
194214501Srpaulo	struct ifreq ifr;
195209139Srpaulo
196214501Srpaulo	os_memset(&ifr, 0, sizeof(ifr));
197214501Srpaulo	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
198214501Srpaulo	ifr.ifr_media = media;
199209139Srpaulo
200214501Srpaulo	if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
201214501Srpaulo		wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
202214501Srpaulo			   strerror(errno));
203214501Srpaulo		return -1;
204214501Srpaulo	}
205209139Srpaulo
206214501Srpaulo	return 0;
207209139Srpaulo}
208209139Srpaulo
209209139Srpaulostatic int
210214501Srpaulobsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode)
211209139Srpaulo{
212214501Srpaulo	int media = bsd_get_if_media(priv);
213214501Srpaulo
214214501Srpaulo	if (media < 0)
215214501Srpaulo		return -1;
216214501Srpaulo	media &= ~mask;
217214501Srpaulo	media |= mode;
218214501Srpaulo	if (bsd_set_if_media(priv, media) < 0)
219214501Srpaulo		return -1;
220214501Srpaulo	return 0;
221209139Srpaulo}
222209139Srpaulo
223209139Srpaulostatic int
224214501Srpaulobsd_del_key(void *priv, const u8 *addr, int key_idx)
225209139Srpaulo{
226214501Srpaulo	struct ieee80211req_del_key wk;
227209139Srpaulo
228214501Srpaulo	os_memset(&wk, 0, sizeof(wk));
229214501Srpaulo	if (addr == NULL) {
230214501Srpaulo		wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx);
231214501Srpaulo		wk.idk_keyix = key_idx;
232214501Srpaulo	} else {
233214501Srpaulo		wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__,
234214501Srpaulo			   MAC2STR(addr));
235214501Srpaulo		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
236214501Srpaulo		wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE;	/* XXX */
237214501Srpaulo	}
238209139Srpaulo
239214501Srpaulo	return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
240209139Srpaulo}
241209139Srpaulo
242209139Srpaulostatic int
243214501Srpaulobsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr)
244209139Srpaulo{
245214501Srpaulo	struct ieee80211req_mlme mlme;
246209139Srpaulo
247214501Srpaulo	os_memset(&mlme, 0, sizeof(mlme));
248214501Srpaulo	mlme.im_op = op;
249214501Srpaulo	mlme.im_reason = reason;
250214501Srpaulo	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
251214501Srpaulo	return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
252209139Srpaulo}
253209139Srpaulo
254209139Srpaulostatic int
255214501Srpaulobsd_ctrl_iface(void *priv, int enable)
256209139Srpaulo{
257214501Srpaulo	struct bsd_driver_data *drv = priv;
258214501Srpaulo	struct ifreq ifr;
259209139Srpaulo
260214501Srpaulo	os_memset(&ifr, 0, sizeof(ifr));
261214501Srpaulo	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
262209139Srpaulo
263214501Srpaulo	if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
264214501Srpaulo		perror("ioctl[SIOCGIFFLAGS]");
265214501Srpaulo		return -1;
266209139Srpaulo	}
267214501Srpaulo
268214501Srpaulo	if (enable)
269214501Srpaulo		ifr.ifr_flags |= IFF_UP;
270214501Srpaulo	else
271214501Srpaulo		ifr.ifr_flags &= ~IFF_UP;
272214501Srpaulo
273214501Srpaulo	if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
274214501Srpaulo		perror("ioctl[SIOCSIFFLAGS]");
275214501Srpaulo		return -1;
276214501Srpaulo	}
277214501Srpaulo
278214501Srpaulo	return 0;
279209139Srpaulo}
280209139Srpaulo
281209139Srpaulostatic int
282214501Srpaulobsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
283214501Srpaulo	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
284214501Srpaulo	    size_t seq_len, const u8 *key, size_t key_len)
285209139Srpaulo{
286209139Srpaulo	struct ieee80211req_key wk;
287209139Srpaulo
288214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
289214501Srpaulo		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
290214501Srpaulo		   set_tx, seq_len, key_len);
291209139Srpaulo
292214501Srpaulo	if (alg == WPA_ALG_NONE) {
293214501Srpaulo#ifndef HOSTAPD
294252190Srpaulo		if (addr == NULL || is_broadcast_ether_addr(addr))
295214501Srpaulo			return bsd_del_key(priv, NULL, key_idx);
296214501Srpaulo		else
297214501Srpaulo#endif /* HOSTAPD */
298214501Srpaulo			return bsd_del_key(priv, addr, key_idx);
299214501Srpaulo	}
300214501Srpaulo
301214501Srpaulo	os_memset(&wk, 0, sizeof(wk));
302209139Srpaulo	switch (alg) {
303209139Srpaulo	case WPA_ALG_WEP:
304214501Srpaulo		wk.ik_type = IEEE80211_CIPHER_WEP;
305209139Srpaulo		break;
306209139Srpaulo	case WPA_ALG_TKIP:
307214501Srpaulo		wk.ik_type = IEEE80211_CIPHER_TKIP;
308209139Srpaulo		break;
309209139Srpaulo	case WPA_ALG_CCMP:
310214501Srpaulo		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
311209139Srpaulo		break;
312209139Srpaulo	default:
313214501Srpaulo		wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg);
314209139Srpaulo		return -1;
315209139Srpaulo	}
316209139Srpaulo
317209139Srpaulo	wk.ik_flags = IEEE80211_KEY_RECV;
318209139Srpaulo	if (set_tx)
319209139Srpaulo		wk.ik_flags |= IEEE80211_KEY_XMIT;
320214501Srpaulo
321214501Srpaulo	if (addr == NULL) {
322214501Srpaulo		os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
323209139Srpaulo		wk.ik_keyix = key_idx;
324209139Srpaulo	} else {
325214501Srpaulo		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
326214501Srpaulo		/*
327214501Srpaulo		 * Deduce whether group/global or unicast key by checking
328214501Srpaulo		 * the address (yech).  Note also that we can only mark global
329214501Srpaulo		 * keys default; doing this for a unicast key is an error.
330214501Srpaulo		 */
331252190Srpaulo		if (is_broadcast_ether_addr(addr)) {
332214501Srpaulo			wk.ik_flags |= IEEE80211_KEY_GROUP;
333214501Srpaulo			wk.ik_keyix = key_idx;
334214501Srpaulo		} else {
335214501Srpaulo			wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE :
336214501Srpaulo				key_idx;
337214501Srpaulo		}
338209139Srpaulo	}
339209139Srpaulo	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
340209139Srpaulo		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
341209139Srpaulo	wk.ik_keylen = key_len;
342252190Srpaulo	if (seq) {
343252190Srpaulo#ifdef WORDS_BIGENDIAN
344252190Srpaulo		/*
345252190Srpaulo		 * wk.ik_keyrsc is in host byte order (big endian), need to
346252190Srpaulo		 * swap it to match with the byte order used in WPA.
347252190Srpaulo		 */
348252190Srpaulo		int i;
349252190Srpaulo		u8 *keyrsc = (u8 *) &wk.ik_keyrsc;
350252190Srpaulo		for (i = 0; i < seq_len; i++)
351252190Srpaulo			keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i];
352252190Srpaulo#else /* WORDS_BIGENDIAN */
353252190Srpaulo		os_memcpy(&wk.ik_keyrsc, seq, seq_len);
354252190Srpaulo#endif /* WORDS_BIGENDIAN */
355252190Srpaulo	}
356209139Srpaulo	os_memcpy(wk.ik_keydata, key, key_len);
357209139Srpaulo
358214501Srpaulo	return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
359209139Srpaulo}
360209139Srpaulo
361209139Srpaulostatic int
362214501Srpaulobsd_configure_wpa(void *priv, struct wpa_bss_params *params)
363209139Srpaulo{
364214501Srpaulo#ifndef IEEE80211_IOC_APPIE
365214501Srpaulo	static const char *ciphernames[] =
366214501Srpaulo		{ "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
367214501Srpaulo	int v;
368209139Srpaulo
369214501Srpaulo	switch (params->wpa_group) {
370214501Srpaulo	case WPA_CIPHER_CCMP:
371214501Srpaulo		v = IEEE80211_CIPHER_AES_CCM;
372214501Srpaulo		break;
373214501Srpaulo	case WPA_CIPHER_TKIP:
374214501Srpaulo		v = IEEE80211_CIPHER_TKIP;
375214501Srpaulo		break;
376214501Srpaulo	case WPA_CIPHER_WEP104:
377214501Srpaulo		v = IEEE80211_CIPHER_WEP;
378214501Srpaulo		break;
379214501Srpaulo	case WPA_CIPHER_WEP40:
380214501Srpaulo		v = IEEE80211_CIPHER_WEP;
381214501Srpaulo		break;
382214501Srpaulo	case WPA_CIPHER_NONE:
383214501Srpaulo		v = IEEE80211_CIPHER_NONE;
384214501Srpaulo		break;
385214501Srpaulo	default:
386214501Srpaulo		printf("Unknown group key cipher %u\n",
387214501Srpaulo			params->wpa_group);
388214501Srpaulo		return -1;
389214501Srpaulo	}
390214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
391214501Srpaulo		   __func__, ciphernames[v], v);
392214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
393214501Srpaulo		printf("Unable to set group key cipher to %u (%s)\n",
394214501Srpaulo			v, ciphernames[v]);
395214501Srpaulo		return -1;
396214501Srpaulo	}
397214501Srpaulo	if (v == IEEE80211_CIPHER_WEP) {
398214501Srpaulo		/* key length is done only for specific ciphers */
399214501Srpaulo		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
400214501Srpaulo		if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
401214501Srpaulo			printf("Unable to set group key length to %u\n", v);
402214501Srpaulo			return -1;
403214501Srpaulo		}
404214501Srpaulo	}
405214501Srpaulo
406214501Srpaulo	v = 0;
407214501Srpaulo	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
408214501Srpaulo		v |= 1<<IEEE80211_CIPHER_AES_CCM;
409214501Srpaulo	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
410214501Srpaulo		v |= 1<<IEEE80211_CIPHER_TKIP;
411214501Srpaulo	if (params->wpa_pairwise & WPA_CIPHER_NONE)
412214501Srpaulo		v |= 1<<IEEE80211_CIPHER_NONE;
413214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
414214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
415214501Srpaulo		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
416214501Srpaulo		return -1;
417214501Srpaulo	}
418214501Srpaulo
419214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
420214501Srpaulo		   __func__, params->wpa_key_mgmt);
421214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
422214501Srpaulo			  params->wpa_key_mgmt)) {
423214501Srpaulo		printf("Unable to set key management algorithms to 0x%x\n",
424214501Srpaulo			params->wpa_key_mgmt);
425214501Srpaulo		return -1;
426214501Srpaulo	}
427214501Srpaulo
428214501Srpaulo	v = 0;
429214501Srpaulo	if (params->rsn_preauth)
430214501Srpaulo		v |= BIT(0);
431214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
432214501Srpaulo		   __func__, params->rsn_preauth);
433214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
434214501Srpaulo		printf("Unable to set RSN capabilities to 0x%x\n", v);
435214501Srpaulo		return -1;
436214501Srpaulo	}
437214501Srpaulo#endif /* IEEE80211_IOC_APPIE */
438214501Srpaulo
439214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
440214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
441214501Srpaulo		printf("Unable to set WPA to %u\n", params->wpa);
442214501Srpaulo		return -1;
443214501Srpaulo	}
444214501Srpaulo	return 0;
445214501Srpaulo}
446214501Srpaulo
447214501Srpaulostatic int
448214501Srpaulobsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
449214501Srpaulo{
450214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
451214501Srpaulo
452214501Srpaulo	if (!params->enabled) {
453214501Srpaulo		/* XXX restore state */
454214501Srpaulo		return set80211param(priv, IEEE80211_IOC_AUTHMODE,
455214501Srpaulo				     IEEE80211_AUTH_AUTO);
456214501Srpaulo	}
457214501Srpaulo	if (!params->wpa && !params->ieee802_1x) {
458214501Srpaulo		wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled",
459214501Srpaulo			   __func__);
460214501Srpaulo		return -1;
461214501Srpaulo	}
462214501Srpaulo	if (params->wpa && bsd_configure_wpa(priv, params) != 0) {
463214501Srpaulo		wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state",
464214501Srpaulo			   __func__);
465214501Srpaulo		return -1;
466214501Srpaulo	}
467214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
468214501Srpaulo		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
469214501Srpaulo		wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X",
470214501Srpaulo			   __func__);
471214501Srpaulo		return -1;
472214501Srpaulo	}
473214501Srpaulo	return bsd_ctrl_iface(priv, 1);
474214501Srpaulo}
475214501Srpaulo
476214501Srpaulostatic int
477214501Srpaulobsd_set_sta_authorized(void *priv, const u8 *addr,
478214501Srpaulo		       int total_flags, int flags_or, int flags_and)
479214501Srpaulo{
480214501Srpaulo	int authorized = -1;
481214501Srpaulo
482214501Srpaulo	/* For now, only support setting Authorized flag */
483214501Srpaulo	if (flags_or & WPA_STA_AUTHORIZED)
484214501Srpaulo		authorized = 1;
485214501Srpaulo	if (!(flags_and & WPA_STA_AUTHORIZED))
486214501Srpaulo		authorized = 0;
487214501Srpaulo
488214501Srpaulo	if (authorized < 0)
489214501Srpaulo		return 0;
490214501Srpaulo
491214501Srpaulo	return bsd_send_mlme_param(priv, authorized ?
492214501Srpaulo				   IEEE80211_MLME_AUTHORIZE :
493214501Srpaulo				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
494214501Srpaulo}
495214501Srpaulo
496214501Srpaulostatic void
497214501Srpaulobsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
498214501Srpaulo{
499214501Srpaulo	struct ieee80211req_wpaie ie;
500214501Srpaulo	int ielen = 0;
501214501Srpaulo	u8 *iebuf = NULL;
502214501Srpaulo
503214501Srpaulo	/*
504214501Srpaulo	 * Fetch and validate any negotiated WPA/RSN parameters.
505214501Srpaulo	 */
506214501Srpaulo	memset(&ie, 0, sizeof(ie));
507214501Srpaulo	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
508214501Srpaulo	if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
509214501Srpaulo		printf("Failed to get WPA/RSN information element.\n");
510214501Srpaulo		goto no_ie;
511214501Srpaulo	}
512214501Srpaulo	iebuf = ie.wpa_ie;
513214501Srpaulo	ielen = ie.wpa_ie[1];
514214501Srpaulo	if (ielen == 0)
515214501Srpaulo		iebuf = NULL;
516214501Srpaulo	else
517214501Srpaulo		ielen += 2;
518214501Srpaulo
519214501Srpaulono_ie:
520252190Srpaulo	drv_event_assoc(ctx, addr, iebuf, ielen, 0);
521214501Srpaulo}
522214501Srpaulo
523214501Srpaulostatic int
524214501Srpaulobsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
525252190Srpaulo	       int encrypt, const u8 *own_addr, u32 flags)
526214501Srpaulo{
527214501Srpaulo	struct bsd_driver_data *drv = priv;
528214501Srpaulo
529214501Srpaulo	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len);
530214501Srpaulo
531214501Srpaulo	return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data,
532214501Srpaulo			      data_len);
533214501Srpaulo}
534214501Srpaulo
535214501Srpaulostatic int
536252190Srpaulobsd_set_freq(void *priv, struct hostapd_freq_params *freq)
537214501Srpaulo{
538214501Srpaulo	struct bsd_driver_data *drv = priv;
539214501Srpaulo#ifdef SIOCS80211CHANNEL
540214501Srpaulo	struct ieee80211chanreq creq;
541214501Srpaulo#endif /* SIOCS80211CHANNEL */
542214501Srpaulo	u32 mode;
543252190Srpaulo	int channel = freq->channel;
544214501Srpaulo
545252190Srpaulo	if (channel < 14) {
546252190Srpaulo		mode =
547252190Srpaulo#ifdef CONFIG_IEEE80211N
548252190Srpaulo			freq->ht_enabled ? IFM_IEEE80211_11NG :
549252190Srpaulo#endif /* CONFIG_IEEE80211N */
550252190Srpaulo		        IFM_IEEE80211_11G;
551252190Srpaulo	} else if (channel == 14) {
552214501Srpaulo		mode = IFM_IEEE80211_11B;
553252190Srpaulo	} else {
554252190Srpaulo		mode =
555252190Srpaulo#ifdef CONFIG_IEEE80211N
556252190Srpaulo			freq->ht_enabled ? IFM_IEEE80211_11NA :
557252190Srpaulo#endif /* CONFIG_IEEE80211N */
558252190Srpaulo			IFM_IEEE80211_11A;
559252190Srpaulo	}
560214501Srpaulo	if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
561214501Srpaulo		wpa_printf(MSG_ERROR, "%s: failed to set modulation mode",
562214501Srpaulo			   __func__);
563214501Srpaulo		return -1;
564214501Srpaulo	}
565214501Srpaulo
566214501Srpaulo#ifdef SIOCS80211CHANNEL
567214501Srpaulo	os_memset(&creq, 0, sizeof(creq));
568214501Srpaulo	os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
569252190Srpaulo	creq.i_channel = (u_int16_t)channel;
570214501Srpaulo	return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
571214501Srpaulo#else /* SIOCS80211CHANNEL */
572214501Srpaulo	return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
573214501Srpaulo#endif /* SIOCS80211CHANNEL */
574214501Srpaulo}
575214501Srpaulo
576214501Srpaulostatic int
577214501Srpaulobsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
578214501Srpaulo{
579214501Srpaulo#ifdef IEEE80211_IOC_APPIE
580214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__,
581214501Srpaulo		   (unsigned long)ie_len);
582214501Srpaulo	return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA,
583214501Srpaulo			    ie, ie_len);
584214501Srpaulo#endif /* IEEE80211_IOC_APPIE */
585214501Srpaulo	return 0;
586214501Srpaulo}
587214501Srpaulo
588252190Srpaulostatic int
589252190Srpaulortbuf_len(void)
590252190Srpaulo{
591252190Srpaulo	size_t len;
592214501Srpaulo
593252190Srpaulo	int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
594252190Srpaulo
595252190Srpaulo	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
596252190Srpaulo		wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__,
597252190Srpaulo			   strerror(errno));
598252190Srpaulo		len = 2048;
599252190Srpaulo	}
600252190Srpaulo
601252190Srpaulo	return len;
602252190Srpaulo}
603252190Srpaulo
604214501Srpaulo#ifdef HOSTAPD
605214501Srpaulo
606214501Srpaulo/*
607214501Srpaulo * Avoid conflicts with hostapd definitions by undefining couple of defines
608214501Srpaulo * from net80211 header files.
609214501Srpaulo */
610214501Srpaulo#undef RSN_VERSION
611214501Srpaulo#undef WPA_VERSION
612214501Srpaulo#undef WPA_OUI_TYPE
613214501Srpaulo
614214501Srpaulostatic int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
615214501Srpaulo			  int reason_code);
616214501Srpaulo
617214501Srpaulostatic const char *
618214501Srpauloether_sprintf(const u8 *addr)
619214501Srpaulo{
620214501Srpaulo	static char buf[sizeof(MACSTR)];
621214501Srpaulo
622214501Srpaulo	if (addr != NULL)
623214501Srpaulo		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
624214501Srpaulo	else
625214501Srpaulo		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
626214501Srpaulo	return buf;
627214501Srpaulo}
628214501Srpaulo
629214501Srpaulostatic int
630214501Srpaulobsd_set_privacy(void *priv, int enabled)
631214501Srpaulo{
632209139Srpaulo	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
633214501Srpaulo
634214501Srpaulo	return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled);
635209139Srpaulo}
636209139Srpaulo
637214501Srpaulostatic int
638214501Srpaulobsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
639214501Srpaulo	       u8 *seq)
640214501Srpaulo{
641214501Srpaulo	struct ieee80211req_key wk;
642209139Srpaulo
643214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
644214501Srpaulo		   __func__, ether_sprintf(addr), idx);
645214501Srpaulo
646214501Srpaulo	memset(&wk, 0, sizeof(wk));
647214501Srpaulo	if (addr == NULL)
648214501Srpaulo		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
649214501Srpaulo	else
650214501Srpaulo		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
651214501Srpaulo	wk.ik_keyix = idx;
652214501Srpaulo
653214501Srpaulo	if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
654214501Srpaulo		printf("Failed to get encryption.\n");
655214501Srpaulo		return -1;
656214501Srpaulo	}
657214501Srpaulo
658214501Srpaulo#ifdef WORDS_BIGENDIAN
659214501Srpaulo	{
660214501Srpaulo		/*
661214501Srpaulo		 * wk.ik_keytsc is in host byte order (big endian), need to
662214501Srpaulo		 * swap it to match with the byte order used in WPA.
663214501Srpaulo		 */
664214501Srpaulo		int i;
665214501Srpaulo		u8 tmp[WPA_KEY_RSC_LEN];
666214501Srpaulo		memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
667214501Srpaulo		for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
668214501Srpaulo			seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
669214501Srpaulo		}
670214501Srpaulo	}
671214501Srpaulo#else /* WORDS_BIGENDIAN */
672214501Srpaulo	memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
673214501Srpaulo#endif /* WORDS_BIGENDIAN */
674214501Srpaulo	return 0;
675214501Srpaulo}
676214501Srpaulo
677214501Srpaulo
678214501Srpaulostatic int
679214501Srpaulobsd_flush(void *priv)
680214501Srpaulo{
681214501Srpaulo	u8 allsta[IEEE80211_ADDR_LEN];
682214501Srpaulo
683214501Srpaulo	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
684214501Srpaulo	return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE);
685214501Srpaulo}
686214501Srpaulo
687214501Srpaulo
688209139Srpaulostatic int
689214501Srpaulobsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
690214501Srpaulo			 const u8 *addr)
691209139Srpaulo{
692214501Srpaulo	struct ieee80211req_sta_stats stats;
693209139Srpaulo
694214501Srpaulo	memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
695214501Srpaulo	if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats))
696214501Srpaulo	    > 0) {
697214501Srpaulo		/* XXX? do packets counts include non-data frames? */
698214501Srpaulo		data->rx_packets = stats.is_stats.ns_rx_data;
699214501Srpaulo		data->rx_bytes = stats.is_stats.ns_rx_bytes;
700214501Srpaulo		data->tx_packets = stats.is_stats.ns_tx_data;
701214501Srpaulo		data->tx_bytes = stats.is_stats.ns_tx_bytes;
702214501Srpaulo	}
703214501Srpaulo	return 0;
704214501Srpaulo}
705214501Srpaulo
706214501Srpaulostatic int
707214501Srpaulobsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
708214501Srpaulo{
709214501Srpaulo	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
710214501Srpaulo				   addr);
711214501Srpaulo}
712214501Srpaulo
713214501Srpaulostatic int
714214501Srpaulobsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
715214501Srpaulo		 int reason_code)
716214501Srpaulo{
717214501Srpaulo	return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
718214501Srpaulo				   addr);
719214501Srpaulo}
720214501Srpaulo
721214501Srpaulostatic void
722214501Srpaulobsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
723214501Srpaulo{
724214501Srpaulo	struct bsd_driver_data *drv = ctx;
725252190Srpaulo	char *buf;
726214501Srpaulo	struct if_announcemsghdr *ifan;
727214501Srpaulo	struct rt_msghdr *rtm;
728214501Srpaulo	struct ieee80211_michael_event *mic;
729214501Srpaulo	struct ieee80211_join_event *join;
730214501Srpaulo	struct ieee80211_leave_event *leave;
731252190Srpaulo	int n, len;
732214501Srpaulo	union wpa_event_data data;
733214501Srpaulo
734252190Srpaulo	len = rtbuf_len();
735252190Srpaulo
736252190Srpaulo	buf = os_malloc(len);
737252190Srpaulo	if (buf == NULL) {
738252190Srpaulo		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
739252190Srpaulo		return;
740252190Srpaulo	}
741252190Srpaulo
742252190Srpaulo	n = read(sock, buf, len);
743214501Srpaulo	if (n < 0) {
744214501Srpaulo		if (errno != EINTR && errno != EAGAIN)
745252190Srpaulo			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
746252190Srpaulo				   __func__, strerror(errno));
747252190Srpaulo		os_free(buf);
748214501Srpaulo		return;
749214501Srpaulo	}
750214501Srpaulo
751214501Srpaulo	rtm = (struct rt_msghdr *) buf;
752214501Srpaulo	if (rtm->rtm_version != RTM_VERSION) {
753252190Srpaulo		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
754252190Srpaulo			   rtm->rtm_version);
755252190Srpaulo		os_free(buf);
756214501Srpaulo		return;
757214501Srpaulo	}
758214501Srpaulo	ifan = (struct if_announcemsghdr *) rtm;
759214501Srpaulo	switch (rtm->rtm_type) {
760214501Srpaulo	case RTM_IEEE80211:
761214501Srpaulo		switch (ifan->ifan_what) {
762214501Srpaulo		case RTM_IEEE80211_ASSOC:
763214501Srpaulo		case RTM_IEEE80211_REASSOC:
764214501Srpaulo		case RTM_IEEE80211_DISASSOC:
765214501Srpaulo		case RTM_IEEE80211_SCAN:
766214501Srpaulo			break;
767214501Srpaulo		case RTM_IEEE80211_LEAVE:
768214501Srpaulo			leave = (struct ieee80211_leave_event *) &ifan[1];
769214501Srpaulo			drv_event_disassoc(drv->hapd, leave->iev_addr);
770214501Srpaulo			break;
771214501Srpaulo		case RTM_IEEE80211_JOIN:
772214501Srpaulo#ifdef RTM_IEEE80211_REJOIN
773214501Srpaulo		case RTM_IEEE80211_REJOIN:
774214501Srpaulo#endif
775214501Srpaulo			join = (struct ieee80211_join_event *) &ifan[1];
776214501Srpaulo			bsd_new_sta(drv, drv->hapd, join->iev_addr);
777214501Srpaulo			break;
778214501Srpaulo		case RTM_IEEE80211_REPLAY:
779214501Srpaulo			/* ignore */
780214501Srpaulo			break;
781214501Srpaulo		case RTM_IEEE80211_MICHAEL:
782214501Srpaulo			mic = (struct ieee80211_michael_event *) &ifan[1];
783214501Srpaulo			wpa_printf(MSG_DEBUG,
784214501Srpaulo				"Michael MIC failure wireless event: "
785214501Srpaulo				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
786214501Srpaulo				MAC2STR(mic->iev_src));
787214501Srpaulo			os_memset(&data, 0, sizeof(data));
788214501Srpaulo			data.michael_mic_failure.unicast = 1;
789214501Srpaulo			data.michael_mic_failure.src = mic->iev_src;
790214501Srpaulo			wpa_supplicant_event(drv->hapd,
791214501Srpaulo					     EVENT_MICHAEL_MIC_FAILURE, &data);
792214501Srpaulo			break;
793214501Srpaulo		}
794214501Srpaulo		break;
795214501Srpaulo	}
796252190Srpaulo	os_free(buf);
797214501Srpaulo}
798214501Srpaulo
799214501Srpaulostatic void
800214501Srpaulohandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
801214501Srpaulo{
802214501Srpaulo	struct bsd_driver_data *drv = ctx;
803214501Srpaulo	drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
804214501Srpaulo}
805214501Srpaulo
806214501Srpaulostatic void *
807214501Srpaulobsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
808214501Srpaulo{
809214501Srpaulo	struct bsd_driver_data *drv;
810214501Srpaulo
811214501Srpaulo	drv = os_zalloc(sizeof(struct bsd_driver_data));
812214501Srpaulo	if (drv == NULL) {
813214501Srpaulo		printf("Could not allocate memory for bsd driver data\n");
814214501Srpaulo		goto bad;
815214501Srpaulo	}
816214501Srpaulo
817214501Srpaulo	drv->hapd = hapd;
818214501Srpaulo	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
819214501Srpaulo	if (drv->sock < 0) {
820214501Srpaulo		perror("socket[PF_INET,SOCK_DGRAM]");
821214501Srpaulo		goto bad;
822214501Srpaulo	}
823214501Srpaulo	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
824214501Srpaulo
825214501Srpaulo	drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
826214501Srpaulo					handle_read, drv, 0);
827214501Srpaulo	if (drv->sock_xmit == NULL)
828214501Srpaulo		goto bad;
829214501Srpaulo	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
830214501Srpaulo		goto bad;
831214501Srpaulo
832214501Srpaulo	/* mark down during setup */
833214501Srpaulo	if (bsd_ctrl_iface(drv, 0) < 0)
834214501Srpaulo		goto bad;
835214501Srpaulo
836214501Srpaulo	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
837214501Srpaulo	if (drv->route < 0) {
838214501Srpaulo		perror("socket(PF_ROUTE,SOCK_RAW)");
839214501Srpaulo		goto bad;
840214501Srpaulo	}
841214501Srpaulo	eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
842214501Srpaulo				 NULL);
843214501Srpaulo
844214501Srpaulo	if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
845214501Srpaulo		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
846214501Srpaulo			   __func__);
847214501Srpaulo		goto bad;
848214501Srpaulo	}
849214501Srpaulo
850214501Srpaulo	return drv;
851214501Srpaulobad:
852214501Srpaulo	if (drv->sock_xmit != NULL)
853214501Srpaulo		l2_packet_deinit(drv->sock_xmit);
854214501Srpaulo	if (drv->sock >= 0)
855214501Srpaulo		close(drv->sock);
856214501Srpaulo	if (drv != NULL)
857214501Srpaulo		os_free(drv);
858214501Srpaulo	return NULL;
859214501Srpaulo}
860214501Srpaulo
861214501Srpaulo
862214501Srpaulostatic void
863214501Srpaulobsd_deinit(void *priv)
864214501Srpaulo{
865214501Srpaulo	struct bsd_driver_data *drv = priv;
866214501Srpaulo
867214501Srpaulo	if (drv->route >= 0) {
868214501Srpaulo		eloop_unregister_read_sock(drv->route);
869214501Srpaulo		close(drv->route);
870214501Srpaulo	}
871214501Srpaulo	bsd_ctrl_iface(drv, 0);
872214501Srpaulo	if (drv->sock >= 0)
873214501Srpaulo		close(drv->sock);
874214501Srpaulo	if (drv->sock_xmit != NULL)
875214501Srpaulo		l2_packet_deinit(drv->sock_xmit);
876214501Srpaulo	os_free(drv);
877214501Srpaulo}
878214501Srpaulo
879214501Srpaulo#else /* HOSTAPD */
880214501Srpaulo
881214501Srpaulostatic int
882214501Srpauloget80211param(struct bsd_driver_data *drv, int op)
883214501Srpaulo{
884214501Srpaulo	struct ieee80211req ireq;
885214501Srpaulo
886214501Srpaulo	if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0)
887214501Srpaulo		return -1;
888214501Srpaulo	return ireq.i_val;
889214501Srpaulo}
890214501Srpaulo
891214501Srpaulostatic int
892214501Srpaulowpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
893214501Srpaulo{
894214501Srpaulo	struct bsd_driver_data *drv = priv;
895214501Srpaulo#ifdef SIOCG80211BSSID
896214501Srpaulo	struct ieee80211_bssid bs;
897214501Srpaulo
898214501Srpaulo	os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
899214501Srpaulo	if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
900214501Srpaulo		return -1;
901214501Srpaulo	os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
902214501Srpaulo	return 0;
903214501Srpaulo#else
904214501Srpaulo	return get80211var(drv, IEEE80211_IOC_BSSID,
905214501Srpaulo		bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
906214501Srpaulo#endif
907214501Srpaulo}
908214501Srpaulo
909214501Srpaulostatic int
910214501Srpaulowpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
911214501Srpaulo{
912214501Srpaulo	struct bsd_driver_data *drv = priv;
913214501Srpaulo	return bsd_get_ssid(drv, ssid, 0);
914214501Srpaulo}
915214501Srpaulo
916214501Srpaulostatic int
917214501Srpaulowpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie,
918214501Srpaulo			  size_t wpa_ie_len)
919214501Srpaulo{
920214501Srpaulo#ifdef IEEE80211_IOC_APPIE
921214501Srpaulo	return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len);
922214501Srpaulo#else /* IEEE80211_IOC_APPIE */
923214501Srpaulo	return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
924214501Srpaulo#endif /* IEEE80211_IOC_APPIE */
925214501Srpaulo}
926214501Srpaulo
927214501Srpaulostatic int
928214501Srpaulowpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
929214501Srpaulo{
930214501Srpaulo	int ret = 0;
931214501Srpaulo
932214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
933214501Srpaulo		__FUNCTION__, wpa, privacy);
934214501Srpaulo
935214501Srpaulo	if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
936214501Srpaulo		ret = -1;
937214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0)
938214501Srpaulo		ret = -1;
939214501Srpaulo	if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0)
940214501Srpaulo		ret = -1;
941214501Srpaulo
942214501Srpaulo	return ret;
943214501Srpaulo}
944214501Srpaulo
945214501Srpaulostatic int
946214501Srpaulowpa_driver_bsd_set_wpa(void *priv, int enabled)
947214501Srpaulo{
948214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
949214501Srpaulo
950214501Srpaulo	return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
951214501Srpaulo}
952214501Srpaulo
953214501Srpaulostatic int
954214501Srpaulowpa_driver_bsd_set_countermeasures(void *priv, int enabled)
955214501Srpaulo{
956209139Srpaulo	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
957214501Srpaulo	return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled);
958209139Srpaulo}
959209139Srpaulo
960214501Srpaulo
961209139Srpaulostatic int
962214501Srpaulowpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
963214501Srpaulo{
964214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
965214501Srpaulo	return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
966214501Srpaulo}
967214501Srpaulo
968214501Srpaulostatic int
969209139Srpaulowpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
970209139Srpaulo{
971214501Srpaulo	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
972214501Srpaulo				   addr);
973209139Srpaulo}
974209139Srpaulo
975209139Srpaulostatic int
976214501Srpaulowpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
977214501Srpaulo{
978214501Srpaulo	int authmode;
979214501Srpaulo
980214501Srpaulo	if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
981214501Srpaulo	    (auth_alg & WPA_AUTH_ALG_SHARED))
982214501Srpaulo		authmode = IEEE80211_AUTH_AUTO;
983214501Srpaulo	else if (auth_alg & WPA_AUTH_ALG_SHARED)
984214501Srpaulo		authmode = IEEE80211_AUTH_SHARED;
985214501Srpaulo	else
986214501Srpaulo		authmode = IEEE80211_AUTH_OPEN;
987214501Srpaulo
988214501Srpaulo	return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode);
989209139Srpaulo}
990209139Srpaulo
991214501Srpaulostatic void
992214501Srpaulohandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
993214501Srpaulo{
994214501Srpaulo	struct bsd_driver_data *drv = ctx;
995214501Srpaulo
996214501Srpaulo	drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
997214501Srpaulo}
998214501Srpaulo
999209139Srpaulostatic int
1000209139Srpaulowpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
1001209139Srpaulo{
1002214501Srpaulo	struct bsd_driver_data *drv = priv;
1003209139Srpaulo	struct ieee80211req_mlme mlme;
1004214501Srpaulo	u32 mode;
1005209139Srpaulo	int privacy;
1006214501Srpaulo	int ret = 0;
1007209139Srpaulo
1008209139Srpaulo	wpa_printf(MSG_DEBUG,
1009209139Srpaulo		"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
1010209139Srpaulo		, __func__
1011214501Srpaulo		   , (unsigned int) params->ssid_len, params->ssid
1012214501Srpaulo		, (unsigned int) params->wpa_ie_len
1013209139Srpaulo		, params->pairwise_suite
1014209139Srpaulo		, params->group_suite
1015209139Srpaulo		, params->key_mgmt_suite
1016209139Srpaulo	);
1017209139Srpaulo
1018214501Srpaulo	switch (params->mode) {
1019214501Srpaulo	case IEEE80211_MODE_INFRA:
1020214501Srpaulo		mode = 0 /* STA */;
1021214501Srpaulo		break;
1022214501Srpaulo	case IEEE80211_MODE_IBSS:
1023214501Srpaulo		mode = IFM_IEEE80211_IBSS;
1024214501Srpaulo		break;
1025214501Srpaulo	case IEEE80211_MODE_AP:
1026214501Srpaulo		mode = IFM_IEEE80211_HOSTAP;
1027214501Srpaulo		break;
1028214501Srpaulo	default:
1029214501Srpaulo		wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__);
1030214501Srpaulo		return -1;
1031214501Srpaulo	}
1032214501Srpaulo	if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) {
1033214501Srpaulo		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
1034214501Srpaulo			   __func__);
1035214501Srpaulo		return -1;
1036214501Srpaulo	}
1037214501Srpaulo
1038214501Srpaulo	if (params->mode == IEEE80211_MODE_AP) {
1039214501Srpaulo		drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
1040214501Srpaulo						handle_read, drv, 0);
1041214501Srpaulo		if (drv->sock_xmit == NULL)
1042214501Srpaulo			return -1;
1043214501Srpaulo		drv->is_ap = 1;
1044214501Srpaulo		return 0;
1045214501Srpaulo	}
1046214501Srpaulo
1047214501Srpaulo	if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted)
1048214501Srpaulo	    < 0)
1049214501Srpaulo		ret = -1;
1050214501Srpaulo	if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0)
1051214501Srpaulo		ret = -1;
1052209139Srpaulo	/* XXX error handling is wrong but unclear what to do... */
1053209139Srpaulo	if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
1054209139Srpaulo		return -1;
1055209139Srpaulo
1056209139Srpaulo	privacy = !(params->pairwise_suite == CIPHER_NONE &&
1057209139Srpaulo	    params->group_suite == CIPHER_NONE &&
1058209139Srpaulo	    params->key_mgmt_suite == KEY_MGMT_NONE &&
1059209139Srpaulo	    params->wpa_ie_len == 0);
1060209139Srpaulo	wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
1061209139Srpaulo
1062209139Srpaulo	if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
1063209139Srpaulo		return -1;
1064209139Srpaulo
1065209139Srpaulo	if (params->wpa_ie_len &&
1066209139Srpaulo	    set80211param(drv, IEEE80211_IOC_WPA,
1067209139Srpaulo			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
1068209139Srpaulo		return -1;
1069209139Srpaulo
1070209139Srpaulo	os_memset(&mlme, 0, sizeof(mlme));
1071209139Srpaulo	mlme.im_op = IEEE80211_MLME_ASSOC;
1072209139Srpaulo	if (params->ssid != NULL)
1073209139Srpaulo		os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
1074209139Srpaulo	mlme.im_ssid_len = params->ssid_len;
1075209139Srpaulo	if (params->bssid != NULL)
1076209139Srpaulo		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
1077209139Srpaulo	if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
1078209139Srpaulo		return -1;
1079214501Srpaulo	return ret;
1080209139Srpaulo}
1081209139Srpaulo
1082209139Srpaulostatic int
1083214501Srpaulowpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
1084209139Srpaulo{
1085214501Srpaulo	struct bsd_driver_data *drv = priv;
1086214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID
1087214501Srpaulo	struct ieee80211_scan_req sr;
1088214501Srpaulo	int i;
1089214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
1090209139Srpaulo
1091214501Srpaulo	if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) {
1092214501Srpaulo		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
1093214501Srpaulo			   __func__);
1094214501Srpaulo		return -1;
1095214501Srpaulo	}
1096209139Srpaulo
1097214501Srpaulo	if (set80211param(drv, IEEE80211_IOC_ROAMING,
1098214501Srpaulo			  IEEE80211_ROAMING_MANUAL) < 0) {
1099214501Srpaulo		wpa_printf(MSG_ERROR, "%s: failed to set "
1100214501Srpaulo			   "wpa_supplicant-based roaming: %s", __func__,
1101214501Srpaulo			   strerror(errno));
1102214501Srpaulo		return -1;
1103214501Srpaulo	}
1104209139Srpaulo
1105214501Srpaulo	if (wpa_driver_bsd_set_wpa(drv, 1) < 0) {
1106214501Srpaulo		wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__,
1107214501Srpaulo			   strerror(errno));
1108214501Srpaulo		return -1;
1109214501Srpaulo	}
1110209139Srpaulo
1111209139Srpaulo	/* NB: interface must be marked UP to do a scan */
1112214501Srpaulo	if (bsd_ctrl_iface(drv, 1) < 0)
1113209139Srpaulo		return -1;
1114209139Srpaulo
1115214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID
1116214501Srpaulo	os_memset(&sr, 0, sizeof(sr));
1117214501Srpaulo	sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE |
1118214501Srpaulo		IEEE80211_IOC_SCAN_NOJOIN;
1119214501Srpaulo	sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
1120214501Srpaulo	if (params->num_ssids > 0) {
1121214501Srpaulo		sr.sr_nssid = params->num_ssids;
1122214501Srpaulo#if 0
1123214501Srpaulo		/* Boundary check is done by upper layer */
1124214501Srpaulo		if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID)
1125214501Srpaulo			sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID;
1126214501Srpaulo#endif
1127214501Srpaulo
1128214501Srpaulo		/* NB: check scan cache first */
1129214501Srpaulo		sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK;
1130214501Srpaulo	}
1131214501Srpaulo	for (i = 0; i < sr.sr_nssid; i++) {
1132214501Srpaulo		sr.sr_ssid[i].len = params->ssids[i].ssid_len;
1133214501Srpaulo		os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid,
1134214501Srpaulo			  sr.sr_ssid[i].len);
1135214501Srpaulo	}
1136214501Srpaulo
1137214501Srpaulo	/* NB: net80211 delivers a scan complete event so no need to poll */
1138214501Srpaulo	return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr));
1139214501Srpaulo#else /* IEEE80211_IOC_SCAN_MAX_SSID */
1140209139Srpaulo	/* set desired ssid before scan */
1141214501Srpaulo	if (bsd_set_ssid(drv, params->ssids[0].ssid,
1142214501Srpaulo			 params->ssids[0].ssid_len) < 0)
1143209139Srpaulo		return -1;
1144209139Srpaulo
1145209139Srpaulo	/* NB: net80211 delivers a scan complete event so no need to poll */
1146209139Srpaulo	return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
1147214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
1148209139Srpaulo}
1149209139Srpaulo
1150209139Srpaulostatic void
1151209139Srpaulowpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
1152209139Srpaulo{
1153214501Srpaulo	struct bsd_driver_data *drv = sock_ctx;
1154252190Srpaulo	char *buf;
1155209139Srpaulo	struct if_announcemsghdr *ifan;
1156209139Srpaulo	struct if_msghdr *ifm;
1157209139Srpaulo	struct rt_msghdr *rtm;
1158209139Srpaulo	union wpa_event_data event;
1159209139Srpaulo	struct ieee80211_michael_event *mic;
1160214501Srpaulo	struct ieee80211_leave_event *leave;
1161214501Srpaulo	struct ieee80211_join_event *join;
1162252190Srpaulo	int n, len;
1163209139Srpaulo
1164252190Srpaulo	len = rtbuf_len();
1165252190Srpaulo
1166252190Srpaulo	buf = os_malloc(len);
1167252190Srpaulo	if (buf == NULL) {
1168252190Srpaulo		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
1169252190Srpaulo		return;
1170252190Srpaulo	}
1171252190Srpaulo
1172252190Srpaulo	n = read(sock, buf, len);
1173209139Srpaulo	if (n < 0) {
1174209139Srpaulo		if (errno != EINTR && errno != EAGAIN)
1175252190Srpaulo			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
1176252190Srpaulo				   __func__, strerror(errno));
1177252190Srpaulo		os_free(buf);
1178209139Srpaulo		return;
1179209139Srpaulo	}
1180209139Srpaulo
1181209139Srpaulo	rtm = (struct rt_msghdr *) buf;
1182209139Srpaulo	if (rtm->rtm_version != RTM_VERSION) {
1183252190Srpaulo		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
1184252190Srpaulo			   rtm->rtm_version);
1185252190Srpaulo		os_free(buf);
1186209139Srpaulo		return;
1187209139Srpaulo	}
1188209139Srpaulo	os_memset(&event, 0, sizeof(event));
1189209139Srpaulo	switch (rtm->rtm_type) {
1190209139Srpaulo	case RTM_IFANNOUNCE:
1191209139Srpaulo		ifan = (struct if_announcemsghdr *) rtm;
1192209139Srpaulo		if (ifan->ifan_index != drv->ifindex)
1193209139Srpaulo			break;
1194214501Srpaulo		os_strlcpy(event.interface_status.ifname, drv->ifname,
1195214501Srpaulo			   sizeof(event.interface_status.ifname));
1196209139Srpaulo		switch (ifan->ifan_what) {
1197209139Srpaulo		case IFAN_DEPARTURE:
1198209139Srpaulo			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
1199209139Srpaulo		default:
1200252190Srpaulo			os_free(buf);
1201209139Srpaulo			return;
1202209139Srpaulo		}
1203209139Srpaulo		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
1204209139Srpaulo			   event.interface_status.ifname,
1205209139Srpaulo			   ifan->ifan_what == IFAN_DEPARTURE ?
1206209139Srpaulo				"removed" : "added");
1207209139Srpaulo		wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
1208209139Srpaulo		break;
1209209139Srpaulo	case RTM_IEEE80211:
1210209139Srpaulo		ifan = (struct if_announcemsghdr *) rtm;
1211209139Srpaulo		if (ifan->ifan_index != drv->ifindex)
1212209139Srpaulo			break;
1213209139Srpaulo		switch (ifan->ifan_what) {
1214209139Srpaulo		case RTM_IEEE80211_ASSOC:
1215209139Srpaulo		case RTM_IEEE80211_REASSOC:
1216214501Srpaulo			if (drv->is_ap)
1217214501Srpaulo				break;
1218209139Srpaulo			wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
1219209139Srpaulo			break;
1220209139Srpaulo		case RTM_IEEE80211_DISASSOC:
1221214501Srpaulo			if (drv->is_ap)
1222214501Srpaulo				break;
1223209139Srpaulo			wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
1224209139Srpaulo			break;
1225209139Srpaulo		case RTM_IEEE80211_SCAN:
1226214501Srpaulo			if (drv->is_ap)
1227214501Srpaulo				break;
1228209139Srpaulo			wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
1229209139Srpaulo			break;
1230214501Srpaulo		case RTM_IEEE80211_LEAVE:
1231214501Srpaulo			leave = (struct ieee80211_leave_event *) &ifan[1];
1232214501Srpaulo			drv_event_disassoc(ctx, leave->iev_addr);
1233214501Srpaulo			break;
1234214501Srpaulo		case RTM_IEEE80211_JOIN:
1235214501Srpaulo#ifdef RTM_IEEE80211_REJOIN
1236214501Srpaulo		case RTM_IEEE80211_REJOIN:
1237214501Srpaulo#endif
1238214501Srpaulo			join = (struct ieee80211_join_event *) &ifan[1];
1239214501Srpaulo			bsd_new_sta(drv, ctx, join->iev_addr);
1240214501Srpaulo			break;
1241209139Srpaulo		case RTM_IEEE80211_REPLAY:
1242209139Srpaulo			/* ignore */
1243209139Srpaulo			break;
1244209139Srpaulo		case RTM_IEEE80211_MICHAEL:
1245209139Srpaulo			mic = (struct ieee80211_michael_event *) &ifan[1];
1246209139Srpaulo			wpa_printf(MSG_DEBUG,
1247209139Srpaulo				"Michael MIC failure wireless event: "
1248209139Srpaulo				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
1249209139Srpaulo				MAC2STR(mic->iev_src));
1250209139Srpaulo
1251209139Srpaulo			os_memset(&event, 0, sizeof(event));
1252209139Srpaulo			event.michael_mic_failure.unicast =
1253209139Srpaulo				!IEEE80211_IS_MULTICAST(mic->iev_dst);
1254209139Srpaulo			wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
1255209139Srpaulo				&event);
1256209139Srpaulo			break;
1257209139Srpaulo		}
1258209139Srpaulo		break;
1259209139Srpaulo	case RTM_IFINFO:
1260209139Srpaulo		ifm = (struct if_msghdr *) rtm;
1261209139Srpaulo		if (ifm->ifm_index != drv->ifindex)
1262209139Srpaulo			break;
1263209139Srpaulo		if ((rtm->rtm_flags & RTF_UP) == 0) {
1264214501Srpaulo			os_strlcpy(event.interface_status.ifname, drv->ifname,
1265214501Srpaulo				   sizeof(event.interface_status.ifname));
1266209139Srpaulo			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
1267209139Srpaulo			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
1268209139Srpaulo				   event.interface_status.ifname);
1269209139Srpaulo			wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
1270209139Srpaulo		}
1271209139Srpaulo		break;
1272209139Srpaulo	}
1273252190Srpaulo	os_free(buf);
1274209139Srpaulo}
1275209139Srpaulo
1276214501Srpaulostatic void
1277214501Srpaulowpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
1278214501Srpaulo			      struct ieee80211req_scan_result *sr)
1279209139Srpaulo{
1280214501Srpaulo	struct wpa_scan_res *result, **tmp;
1281214501Srpaulo	size_t extra_len;
1282214501Srpaulo	u8 *pos;
1283209139Srpaulo
1284214501Srpaulo	extra_len = 2 + sr->isr_ssid_len;
1285214501Srpaulo	extra_len += 2 + sr->isr_nrates;
1286214501Srpaulo	extra_len += 3; /* ERP IE */
1287214501Srpaulo	extra_len += sr->isr_ie_len;
1288209139Srpaulo
1289214501Srpaulo	result = os_zalloc(sizeof(*result) + extra_len);
1290214501Srpaulo	if (result == NULL)
1291214501Srpaulo		return;
1292214501Srpaulo	os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN);
1293214501Srpaulo	result->freq = sr->isr_freq;
1294214501Srpaulo	result->beacon_int = sr->isr_intval;
1295214501Srpaulo	result->caps = sr->isr_capinfo;
1296214501Srpaulo	result->qual = sr->isr_rssi;
1297214501Srpaulo	result->noise = sr->isr_noise;
1298209139Srpaulo
1299214501Srpaulo	pos = (u8 *)(result + 1);
1300209139Srpaulo
1301214501Srpaulo	*pos++ = WLAN_EID_SSID;
1302214501Srpaulo	*pos++ = sr->isr_ssid_len;
1303214501Srpaulo	os_memcpy(pos, sr + 1, sr->isr_ssid_len);
1304214501Srpaulo	pos += sr->isr_ssid_len;
1305209139Srpaulo
1306214501Srpaulo	/*
1307214501Srpaulo	 * Deal all rates as supported rate.
1308214501Srpaulo	 * Because net80211 doesn't report extended supported rate or not.
1309214501Srpaulo	 */
1310214501Srpaulo	*pos++ = WLAN_EID_SUPP_RATES;
1311214501Srpaulo	*pos++ = sr->isr_nrates;
1312214501Srpaulo	os_memcpy(pos, sr->isr_rates, sr->isr_nrates);
1313214501Srpaulo	pos += sr->isr_nrates;
1314214501Srpaulo
1315214501Srpaulo	*pos++ = WLAN_EID_ERP_INFO;
1316214501Srpaulo	*pos++ = 1;
1317214501Srpaulo	*pos++ = sr->isr_erp;
1318214501Srpaulo
1319214501Srpaulo	os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
1320214501Srpaulo	pos += sr->isr_ie_len;
1321214501Srpaulo
1322214501Srpaulo	result->ie_len = pos - (u8 *)(result + 1);
1323214501Srpaulo
1324252190Srpaulo	tmp = os_realloc_array(res->res, res->num + 1,
1325252190Srpaulo			       sizeof(struct wpa_scan_res *));
1326214501Srpaulo	if (tmp == NULL) {
1327214501Srpaulo		os_free(result);
1328214501Srpaulo		return;
1329214501Srpaulo	}
1330214501Srpaulo	tmp[res->num++] = result;
1331214501Srpaulo	res->res = tmp;
1332209139Srpaulo}
1333209139Srpaulo
1334214501Srpaulostruct wpa_scan_results *
1335214501Srpaulowpa_driver_bsd_get_scan_results2(void *priv)
1336209139Srpaulo{
1337214501Srpaulo	struct ieee80211req_scan_result *sr;
1338214501Srpaulo	struct wpa_scan_results *res;
1339214501Srpaulo	int len, rest;
1340214501Srpaulo	uint8_t buf[24*1024], *pos;
1341209139Srpaulo
1342214501Srpaulo	len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024);
1343214501Srpaulo	if (len < 0)
1344214501Srpaulo		return NULL;
1345214501Srpaulo
1346214501Srpaulo	res = os_zalloc(sizeof(*res));
1347214501Srpaulo	if (res == NULL)
1348214501Srpaulo		return NULL;
1349214501Srpaulo
1350214501Srpaulo	pos = buf;
1351214501Srpaulo	rest = len;
1352214501Srpaulo	while (rest >= sizeof(struct ieee80211req_scan_result)) {
1353214501Srpaulo		sr = (struct ieee80211req_scan_result *)pos;
1354214501Srpaulo		wpa_driver_bsd_add_scan_entry(res, sr);
1355214501Srpaulo		pos += sr->isr_len;
1356214501Srpaulo		rest -= sr->isr_len;
1357209139Srpaulo	}
1358209139Srpaulo
1359214501Srpaulo	wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)",
1360214501Srpaulo		   len, (unsigned long)res->num);
1361209139Srpaulo
1362214501Srpaulo	return res;
1363209139Srpaulo}
1364209139Srpaulo
1365214501Srpaulostatic int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
1366209139Srpaulo{
1367214501Srpaulo#ifdef IEEE80211_IOC_DEVCAPS
1368214501Srpaulo/* kernel definitions copied from net80211/ieee80211_var.h */
1369214501Srpaulo#define IEEE80211_CIPHER_WEP            0
1370214501Srpaulo#define IEEE80211_CIPHER_TKIP           1
1371214501Srpaulo#define IEEE80211_CIPHER_AES_CCM        3
1372214501Srpaulo#define IEEE80211_CRYPTO_WEP            (1<<IEEE80211_CIPHER_WEP)
1373214501Srpaulo#define IEEE80211_CRYPTO_TKIP           (1<<IEEE80211_CIPHER_TKIP)
1374214501Srpaulo#define IEEE80211_CRYPTO_AES_CCM        (1<<IEEE80211_CIPHER_AES_CCM)
1375214501Srpaulo#define IEEE80211_C_HOSTAP      0x00000400      /* CAPABILITY: HOSTAP avail */
1376214501Srpaulo#define IEEE80211_C_WPA1        0x00800000      /* CAPABILITY: WPA1 avail */
1377214501Srpaulo#define IEEE80211_C_WPA2        0x01000000      /* CAPABILITY: WPA2 avail */
1378214501Srpaulo	struct ieee80211_devcaps_req devcaps;
1379209139Srpaulo
1380214501Srpaulo	if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps,
1381214501Srpaulo			sizeof(devcaps)) < 0) {
1382214501Srpaulo		wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s",
1383214501Srpaulo			   strerror(errno));
1384209139Srpaulo		return -1;
1385209139Srpaulo	}
1386209139Srpaulo
1387214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x",
1388214501Srpaulo		   __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps);
1389209139Srpaulo
1390214501Srpaulo	if (devcaps.dc_drivercaps & IEEE80211_C_WPA1)
1391214501Srpaulo		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1392214501Srpaulo			WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1393214501Srpaulo	if (devcaps.dc_drivercaps & IEEE80211_C_WPA2)
1394214501Srpaulo		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1395214501Srpaulo			WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1396214501Srpaulo
1397214501Srpaulo	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP)
1398214501Srpaulo		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
1399214501Srpaulo			WPA_DRIVER_CAPA_ENC_WEP104;
1400214501Srpaulo	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP)
1401214501Srpaulo		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1402214501Srpaulo	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM)
1403214501Srpaulo		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1404214501Srpaulo
1405214501Srpaulo	if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP)
1406214501Srpaulo		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
1407214501Srpaulo#undef IEEE80211_CIPHER_WEP
1408214501Srpaulo#undef IEEE80211_CIPHER_TKIP
1409214501Srpaulo#undef IEEE80211_CIPHER_AES_CCM
1410214501Srpaulo#undef IEEE80211_CRYPTO_WEP
1411214501Srpaulo#undef IEEE80211_CRYPTO_TKIP
1412214501Srpaulo#undef IEEE80211_CRYPTO_AES_CCM
1413214501Srpaulo#undef IEEE80211_C_HOSTAP
1414214501Srpaulo#undef IEEE80211_C_WPA1
1415214501Srpaulo#undef IEEE80211_C_WPA2
1416214501Srpaulo#else /* IEEE80211_IOC_DEVCAPS */
1417214501Srpaulo	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
1418214501Srpaulo	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1419214501Srpaulo		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1420214501Srpaulo		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1421214501Srpaulo		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1422214501Srpaulo	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
1423214501Srpaulo		WPA_DRIVER_CAPA_ENC_WEP104 |
1424214501Srpaulo		WPA_DRIVER_CAPA_ENC_TKIP |
1425214501Srpaulo		WPA_DRIVER_CAPA_ENC_CCMP;
1426214501Srpaulo	drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
1427214501Srpaulo#endif /* IEEE80211_IOC_DEVCAPS */
1428214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID
1429214501Srpaulo	drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID;
1430214501Srpaulo#else /* IEEE80211_IOC_SCAN_MAX_SSID */
1431214501Srpaulo	drv->capa.max_scan_ssids = 1;
1432214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
1433214501Srpaulo	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
1434214501Srpaulo		WPA_DRIVER_AUTH_SHARED |
1435214501Srpaulo		WPA_DRIVER_AUTH_LEAP;
1436214501Srpaulo	return 0;
1437209139Srpaulo}
1438209139Srpaulo
1439209139Srpaulostatic void *
1440209139Srpaulowpa_driver_bsd_init(void *ctx, const char *ifname)
1441209139Srpaulo{
1442209139Srpaulo#define	GETPARAM(drv, param, v) \
1443209139Srpaulo	(((v) = get80211param(drv, param)) != -1)
1444214501Srpaulo	struct bsd_driver_data *drv;
1445209139Srpaulo
1446209139Srpaulo	drv = os_zalloc(sizeof(*drv));
1447209139Srpaulo	if (drv == NULL)
1448209139Srpaulo		return NULL;
1449209139Srpaulo	/*
1450209139Srpaulo	 * NB: We require the interface name be mappable to an index.
1451209139Srpaulo	 *     This implies we do not support having wpa_supplicant
1452209139Srpaulo	 *     wait for an interface to appear.  This seems ok; that
1453209139Srpaulo	 *     doesn't belong here; it's really the job of devd.
1454209139Srpaulo	 */
1455209139Srpaulo	drv->ifindex = if_nametoindex(ifname);
1456209139Srpaulo	if (drv->ifindex == 0) {
1457209139Srpaulo		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
1458209139Srpaulo			   __func__, ifname);
1459209139Srpaulo		goto fail1;
1460209139Srpaulo	}
1461209139Srpaulo	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
1462209139Srpaulo	if (drv->sock < 0)
1463209139Srpaulo		goto fail1;
1464209139Srpaulo	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
1465209139Srpaulo	if (drv->route < 0)
1466209139Srpaulo		goto fail;
1467209139Srpaulo	eloop_register_read_sock(drv->route,
1468209139Srpaulo		wpa_driver_bsd_event_receive, ctx, drv);
1469209139Srpaulo
1470209139Srpaulo	drv->ctx = ctx;
1471209139Srpaulo	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
1472209139Srpaulo
1473214501Srpaulo	/* Down interface during setup. */
1474214501Srpaulo	if (bsd_ctrl_iface(drv, 0) < 0)
1475214501Srpaulo		goto fail;
1476214501Srpaulo
1477209139Srpaulo	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
1478209139Srpaulo		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
1479209139Srpaulo			__func__, strerror(errno));
1480209139Srpaulo		goto fail;
1481209139Srpaulo	}
1482209139Srpaulo	if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
1483209139Srpaulo		wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
1484209139Srpaulo			__func__, strerror(errno));
1485209139Srpaulo		goto fail;
1486209139Srpaulo	}
1487209139Srpaulo	if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
1488209139Srpaulo		wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
1489209139Srpaulo			__func__, strerror(errno));
1490209139Srpaulo		goto fail;
1491209139Srpaulo	}
1492209139Srpaulo
1493214501Srpaulo	if (wpa_driver_bsd_capa(drv))
1494209139Srpaulo		goto fail;
1495209139Srpaulo
1496209139Srpaulo	return drv;
1497209139Srpaulofail:
1498209139Srpaulo	close(drv->sock);
1499209139Srpaulofail1:
1500209139Srpaulo	os_free(drv);
1501209139Srpaulo	return NULL;
1502209139Srpaulo#undef GETPARAM
1503209139Srpaulo}
1504209139Srpaulo
1505209139Srpaulostatic void
1506209139Srpaulowpa_driver_bsd_deinit(void *priv)
1507209139Srpaulo{
1508214501Srpaulo	struct bsd_driver_data *drv = priv;
1509209139Srpaulo
1510214501Srpaulo	wpa_driver_bsd_set_wpa(drv, 0);
1511209139Srpaulo	eloop_unregister_read_sock(drv->route);
1512209139Srpaulo
1513209139Srpaulo	/* NB: mark interface down */
1514214501Srpaulo	bsd_ctrl_iface(drv, 0);
1515209139Srpaulo
1516209139Srpaulo	wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
1517209139Srpaulo	if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
1518209139Srpaulo		wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
1519209139Srpaulo			__func__);
1520209139Srpaulo
1521214501Srpaulo	if (drv->sock_xmit != NULL)
1522214501Srpaulo		l2_packet_deinit(drv->sock_xmit);
1523209139Srpaulo	(void) close(drv->route);		/* ioctl socket */
1524209139Srpaulo	(void) close(drv->sock);		/* event socket */
1525209139Srpaulo	os_free(drv);
1526209139Srpaulo}
1527209139Srpaulo
1528214501Srpaulostatic int
1529214501Srpaulowpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
1530214501Srpaulo{
1531214501Srpaulo	struct bsd_driver_data *drv = priv;
1532209139Srpaulo
1533214501Srpaulo	os_memcpy(capa, &drv->capa, sizeof(*capa));
1534214501Srpaulo	return 0;
1535214501Srpaulo}
1536214501Srpaulo#endif /* HOSTAPD */
1537214501Srpaulo
1538214501Srpaulo
1539209139Srpauloconst struct wpa_driver_ops wpa_driver_bsd_ops = {
1540209139Srpaulo	.name			= "bsd",
1541214501Srpaulo	.desc			= "BSD 802.11 support",
1542214501Srpaulo#ifdef HOSTAPD
1543214501Srpaulo	.hapd_init		= bsd_init,
1544214501Srpaulo	.hapd_deinit		= bsd_deinit,
1545214501Srpaulo	.set_privacy		= bsd_set_privacy,
1546214501Srpaulo	.get_seqnum		= bsd_get_seqnum,
1547214501Srpaulo	.flush			= bsd_flush,
1548214501Srpaulo	.read_sta_data		= bsd_read_sta_driver_data,
1549214501Srpaulo	.sta_disassoc		= bsd_sta_disassoc,
1550214501Srpaulo	.sta_deauth		= bsd_sta_deauth,
1551214501Srpaulo#else /* HOSTAPD */
1552209139Srpaulo	.init			= wpa_driver_bsd_init,
1553209139Srpaulo	.deinit			= wpa_driver_bsd_deinit,
1554209139Srpaulo	.get_bssid		= wpa_driver_bsd_get_bssid,
1555209139Srpaulo	.get_ssid		= wpa_driver_bsd_get_ssid,
1556209139Srpaulo	.set_countermeasures	= wpa_driver_bsd_set_countermeasures,
1557214501Srpaulo	.scan2			= wpa_driver_bsd_scan,
1558214501Srpaulo	.get_scan_results2	= wpa_driver_bsd_get_scan_results2,
1559209139Srpaulo	.deauthenticate		= wpa_driver_bsd_deauthenticate,
1560209139Srpaulo	.associate		= wpa_driver_bsd_associate,
1561214501Srpaulo	.get_capa		= wpa_driver_bsd_get_capa,
1562214501Srpaulo#endif /* HOSTAPD */
1563252190Srpaulo	.set_freq		= bsd_set_freq,
1564214501Srpaulo	.set_key		= bsd_set_key,
1565214501Srpaulo	.set_ieee8021x		= bsd_set_ieee8021x,
1566214501Srpaulo	.hapd_set_ssid		= bsd_set_ssid,
1567214501Srpaulo	.hapd_get_ssid		= bsd_get_ssid,
1568214501Srpaulo	.hapd_send_eapol	= bsd_send_eapol,
1569214501Srpaulo	.sta_set_flags		= bsd_set_sta_authorized,
1570214501Srpaulo	.set_generic_elem	= bsd_set_opt_ie,
1571209139Srpaulo};
1572