1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * WPA Supplicant - driver interaction with BSD net80211 layer
3e5b75505Sopenharmony_ci * Copyright (c) 2004, Sam Leffler <sam@errno.com>
4e5b75505Sopenharmony_ci * Copyright (c) 2004, 2Wire, Inc
5e5b75505Sopenharmony_ci *
6e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
7e5b75505Sopenharmony_ci * See README for more details.
8e5b75505Sopenharmony_ci */
9e5b75505Sopenharmony_ci
10e5b75505Sopenharmony_ci#include "includes.h"
11e5b75505Sopenharmony_ci#include <sys/ioctl.h>
12e5b75505Sopenharmony_ci#include <sys/sysctl.h>
13e5b75505Sopenharmony_ci
14e5b75505Sopenharmony_ci#include "common.h"
15e5b75505Sopenharmony_ci#include "driver.h"
16e5b75505Sopenharmony_ci#include "eloop.h"
17e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h"
18e5b75505Sopenharmony_ci#include "common/wpa_common.h"
19e5b75505Sopenharmony_ci
20e5b75505Sopenharmony_ci#include <net/if.h>
21e5b75505Sopenharmony_ci#include <net/if_media.h>
22e5b75505Sopenharmony_ci
23e5b75505Sopenharmony_ci#ifdef __NetBSD__
24e5b75505Sopenharmony_ci#include <net/if_ether.h>
25e5b75505Sopenharmony_ci#else
26e5b75505Sopenharmony_ci#include <net/ethernet.h>
27e5b75505Sopenharmony_ci#endif
28e5b75505Sopenharmony_ci#include <net/route.h>
29e5b75505Sopenharmony_ci
30e5b75505Sopenharmony_ci#ifdef __DragonFly__
31e5b75505Sopenharmony_ci#include <netproto/802_11/ieee80211_ioctl.h>
32e5b75505Sopenharmony_ci#include <netproto/802_11/ieee80211_dragonfly.h>
33e5b75505Sopenharmony_ci#else /* __DragonFly__ */
34e5b75505Sopenharmony_ci#ifdef __GLIBC__
35e5b75505Sopenharmony_ci#include <netinet/ether.h>
36e5b75505Sopenharmony_ci#endif /* __GLIBC__ */
37e5b75505Sopenharmony_ci#include <net80211/ieee80211.h>
38e5b75505Sopenharmony_ci#include <net80211/ieee80211_ioctl.h>
39e5b75505Sopenharmony_ci#include <net80211/ieee80211_crypto.h>
40e5b75505Sopenharmony_ci#endif /* __DragonFly__ || __GLIBC__ */
41e5b75505Sopenharmony_ci#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
42e5b75505Sopenharmony_ci#include <net80211/ieee80211_freebsd.h>
43e5b75505Sopenharmony_ci#endif
44e5b75505Sopenharmony_ci#if __NetBSD__
45e5b75505Sopenharmony_ci#include <net80211/ieee80211_netbsd.h>
46e5b75505Sopenharmony_ci#endif
47e5b75505Sopenharmony_ci
48e5b75505Sopenharmony_ci#include "l2_packet/l2_packet.h"
49e5b75505Sopenharmony_ci
50e5b75505Sopenharmony_cistruct bsd_driver_global {
51e5b75505Sopenharmony_ci	void		*ctx;
52e5b75505Sopenharmony_ci	int		sock;			/* socket for 802.11 ioctls */
53e5b75505Sopenharmony_ci	int		route;			/* routing socket for events */
54e5b75505Sopenharmony_ci	char		*event_buf;
55e5b75505Sopenharmony_ci	size_t		event_buf_len;
56e5b75505Sopenharmony_ci	struct dl_list	ifaces;			/* list of interfaces */
57e5b75505Sopenharmony_ci};
58e5b75505Sopenharmony_ci
59e5b75505Sopenharmony_cistruct bsd_driver_data {
60e5b75505Sopenharmony_ci	struct dl_list	list;
61e5b75505Sopenharmony_ci	struct bsd_driver_global *global;
62e5b75505Sopenharmony_ci	struct hostapd_data *hapd;	/* back pointer */
63e5b75505Sopenharmony_ci
64e5b75505Sopenharmony_ci	struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
65e5b75505Sopenharmony_ci	char	ifname[IFNAMSIZ+1];	/* interface name */
66e5b75505Sopenharmony_ci	int	flags;
67e5b75505Sopenharmony_ci	unsigned int ifindex;		/* interface index */
68e5b75505Sopenharmony_ci	int	if_removed;		/* has the interface been removed? */
69e5b75505Sopenharmony_ci	void	*ctx;
70e5b75505Sopenharmony_ci	struct wpa_driver_capa capa;	/* driver capability */
71e5b75505Sopenharmony_ci	int	is_ap;			/* Access point mode */
72e5b75505Sopenharmony_ci	int	prev_roaming;	/* roaming state to restore on deinit */
73e5b75505Sopenharmony_ci	int	prev_privacy;	/* privacy state to restore on deinit */
74e5b75505Sopenharmony_ci	int	prev_wpa;	/* wpa state to restore on deinit */
75e5b75505Sopenharmony_ci	enum ieee80211_opmode opmode;	/* operation mode */
76e5b75505Sopenharmony_ci};
77e5b75505Sopenharmony_ci
78e5b75505Sopenharmony_ci/* Generic functions for hostapd and wpa_supplicant */
79e5b75505Sopenharmony_ci
80e5b75505Sopenharmony_cistatic struct bsd_driver_data *
81e5b75505Sopenharmony_cibsd_get_drvindex(void *priv, unsigned int ifindex)
82e5b75505Sopenharmony_ci{
83e5b75505Sopenharmony_ci	struct bsd_driver_global *global = priv;
84e5b75505Sopenharmony_ci	struct bsd_driver_data *drv;
85e5b75505Sopenharmony_ci
86e5b75505Sopenharmony_ci	dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
87e5b75505Sopenharmony_ci		if (drv->ifindex == ifindex)
88e5b75505Sopenharmony_ci			return drv;
89e5b75505Sopenharmony_ci	}
90e5b75505Sopenharmony_ci	return NULL;
91e5b75505Sopenharmony_ci}
92e5b75505Sopenharmony_ci
93e5b75505Sopenharmony_ci#ifndef HOSTAPD
94e5b75505Sopenharmony_cistatic struct bsd_driver_data *
95e5b75505Sopenharmony_cibsd_get_drvname(void *priv, const char *ifname)
96e5b75505Sopenharmony_ci{
97e5b75505Sopenharmony_ci	struct bsd_driver_global *global = priv;
98e5b75505Sopenharmony_ci	struct bsd_driver_data *drv;
99e5b75505Sopenharmony_ci
100e5b75505Sopenharmony_ci	dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
101e5b75505Sopenharmony_ci		if (os_strcmp(drv->ifname, ifname) == 0)
102e5b75505Sopenharmony_ci			return drv;
103e5b75505Sopenharmony_ci	}
104e5b75505Sopenharmony_ci	return NULL;
105e5b75505Sopenharmony_ci}
106e5b75505Sopenharmony_ci#endif /* HOSTAPD */
107e5b75505Sopenharmony_ci
108e5b75505Sopenharmony_cistatic int
109e5b75505Sopenharmony_cibsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
110e5b75505Sopenharmony_ci{
111e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
112e5b75505Sopenharmony_ci	struct ieee80211req ireq;
113e5b75505Sopenharmony_ci
114e5b75505Sopenharmony_ci	if (drv->ifindex == 0 || drv->if_removed)
115e5b75505Sopenharmony_ci		return -1;
116e5b75505Sopenharmony_ci
117e5b75505Sopenharmony_ci	os_memset(&ireq, 0, sizeof(ireq));
118e5b75505Sopenharmony_ci	os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
119e5b75505Sopenharmony_ci	ireq.i_type = op;
120e5b75505Sopenharmony_ci	ireq.i_val = val;
121e5b75505Sopenharmony_ci	ireq.i_data = (void *) arg;
122e5b75505Sopenharmony_ci	ireq.i_len = arg_len;
123e5b75505Sopenharmony_ci
124e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCS80211, &ireq) < 0) {
125e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
126e5b75505Sopenharmony_ci			   "arg_len=%u]: %s", op, val, arg_len,
127e5b75505Sopenharmony_ci			   strerror(errno));
128e5b75505Sopenharmony_ci		return -1;
129e5b75505Sopenharmony_ci	}
130e5b75505Sopenharmony_ci	return 0;
131e5b75505Sopenharmony_ci}
132e5b75505Sopenharmony_ci
133e5b75505Sopenharmony_cistatic int
134e5b75505Sopenharmony_cibsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
135e5b75505Sopenharmony_ci	     int arg_len)
136e5b75505Sopenharmony_ci{
137e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
138e5b75505Sopenharmony_ci
139e5b75505Sopenharmony_ci	os_memset(ireq, 0, sizeof(*ireq));
140e5b75505Sopenharmony_ci	os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name));
141e5b75505Sopenharmony_ci	ireq->i_type = op;
142e5b75505Sopenharmony_ci	ireq->i_len = arg_len;
143e5b75505Sopenharmony_ci	ireq->i_data = arg;
144e5b75505Sopenharmony_ci
145e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
146e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
147e5b75505Sopenharmony_ci			   "arg_len=%u]: %s", op, arg_len, strerror(errno));
148e5b75505Sopenharmony_ci		return -1;
149e5b75505Sopenharmony_ci	}
150e5b75505Sopenharmony_ci	return 0;
151e5b75505Sopenharmony_ci}
152e5b75505Sopenharmony_ci
153e5b75505Sopenharmony_cistatic int
154e5b75505Sopenharmony_ciget80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
155e5b75505Sopenharmony_ci{
156e5b75505Sopenharmony_ci	struct ieee80211req ireq;
157e5b75505Sopenharmony_ci
158e5b75505Sopenharmony_ci	if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0)
159e5b75505Sopenharmony_ci		return -1;
160e5b75505Sopenharmony_ci	return ireq.i_len;
161e5b75505Sopenharmony_ci}
162e5b75505Sopenharmony_ci
163e5b75505Sopenharmony_cistatic int
164e5b75505Sopenharmony_ciset80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
165e5b75505Sopenharmony_ci{
166e5b75505Sopenharmony_ci	return bsd_set80211(drv, op, 0, arg, arg_len);
167e5b75505Sopenharmony_ci}
168e5b75505Sopenharmony_ci
169e5b75505Sopenharmony_cistatic int
170e5b75505Sopenharmony_ciset80211param(struct bsd_driver_data *drv, int op, int arg)
171e5b75505Sopenharmony_ci{
172e5b75505Sopenharmony_ci	return bsd_set80211(drv, op, arg, NULL, 0);
173e5b75505Sopenharmony_ci}
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_cistatic int
176e5b75505Sopenharmony_cibsd_get_ssid(void *priv, u8 *ssid, int len)
177e5b75505Sopenharmony_ci{
178e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
179e5b75505Sopenharmony_ci#ifdef SIOCG80211NWID
180e5b75505Sopenharmony_ci	struct ieee80211_nwid nwid;
181e5b75505Sopenharmony_ci	struct ifreq ifr;
182e5b75505Sopenharmony_ci
183e5b75505Sopenharmony_ci	os_memset(&ifr, 0, sizeof(ifr));
184e5b75505Sopenharmony_ci	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
185e5b75505Sopenharmony_ci	ifr.ifr_data = (void *)&nwid;
186e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCG80211NWID, &ifr) < 0 ||
187e5b75505Sopenharmony_ci	    nwid.i_len > IEEE80211_NWID_LEN)
188e5b75505Sopenharmony_ci		return -1;
189e5b75505Sopenharmony_ci	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
190e5b75505Sopenharmony_ci	return nwid.i_len;
191e5b75505Sopenharmony_ci#else
192e5b75505Sopenharmony_ci	return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN);
193e5b75505Sopenharmony_ci#endif
194e5b75505Sopenharmony_ci}
195e5b75505Sopenharmony_ci
196e5b75505Sopenharmony_cistatic int
197e5b75505Sopenharmony_cibsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
198e5b75505Sopenharmony_ci{
199e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
200e5b75505Sopenharmony_ci#ifdef SIOCS80211NWID
201e5b75505Sopenharmony_ci	struct ieee80211_nwid nwid;
202e5b75505Sopenharmony_ci	struct ifreq ifr;
203e5b75505Sopenharmony_ci
204e5b75505Sopenharmony_ci	os_memcpy(nwid.i_nwid, ssid, ssid_len);
205e5b75505Sopenharmony_ci	nwid.i_len = ssid_len;
206e5b75505Sopenharmony_ci	os_memset(&ifr, 0, sizeof(ifr));
207e5b75505Sopenharmony_ci	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
208e5b75505Sopenharmony_ci	ifr.ifr_data = (void *)&nwid;
209e5b75505Sopenharmony_ci	return ioctl(drv->global->sock, SIOCS80211NWID, &ifr);
210e5b75505Sopenharmony_ci#else
211e5b75505Sopenharmony_ci	return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
212e5b75505Sopenharmony_ci#endif
213e5b75505Sopenharmony_ci}
214e5b75505Sopenharmony_ci
215e5b75505Sopenharmony_cistatic int
216e5b75505Sopenharmony_cibsd_get_if_media(void *priv)
217e5b75505Sopenharmony_ci{
218e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
219e5b75505Sopenharmony_ci	struct ifmediareq ifmr;
220e5b75505Sopenharmony_ci
221e5b75505Sopenharmony_ci	os_memset(&ifmr, 0, sizeof(ifmr));
222e5b75505Sopenharmony_ci	os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
223e5b75505Sopenharmony_ci
224e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCGIFMEDIA, &ifmr) < 0) {
225e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
226e5b75505Sopenharmony_ci			   strerror(errno));
227e5b75505Sopenharmony_ci		return -1;
228e5b75505Sopenharmony_ci	}
229e5b75505Sopenharmony_ci
230e5b75505Sopenharmony_ci	return ifmr.ifm_current;
231e5b75505Sopenharmony_ci}
232e5b75505Sopenharmony_ci
233e5b75505Sopenharmony_cistatic int
234e5b75505Sopenharmony_cibsd_set_if_media(void *priv, int media)
235e5b75505Sopenharmony_ci{
236e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
237e5b75505Sopenharmony_ci	struct ifreq ifr;
238e5b75505Sopenharmony_ci
239e5b75505Sopenharmony_ci	os_memset(&ifr, 0, sizeof(ifr));
240e5b75505Sopenharmony_ci	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
241e5b75505Sopenharmony_ci	ifr.ifr_media = media;
242e5b75505Sopenharmony_ci
243e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCSIFMEDIA, &ifr) < 0) {
244e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
245e5b75505Sopenharmony_ci			   strerror(errno));
246e5b75505Sopenharmony_ci		return -1;
247e5b75505Sopenharmony_ci	}
248e5b75505Sopenharmony_ci
249e5b75505Sopenharmony_ci	return 0;
250e5b75505Sopenharmony_ci}
251e5b75505Sopenharmony_ci
252e5b75505Sopenharmony_cistatic int
253e5b75505Sopenharmony_cibsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode)
254e5b75505Sopenharmony_ci{
255e5b75505Sopenharmony_ci	int media = bsd_get_if_media(priv);
256e5b75505Sopenharmony_ci
257e5b75505Sopenharmony_ci	if (media < 0)
258e5b75505Sopenharmony_ci		return -1;
259e5b75505Sopenharmony_ci	media &= ~mask;
260e5b75505Sopenharmony_ci	media |= mode;
261e5b75505Sopenharmony_ci	if (bsd_set_if_media(priv, media) < 0)
262e5b75505Sopenharmony_ci		return -1;
263e5b75505Sopenharmony_ci	return 0;
264e5b75505Sopenharmony_ci}
265e5b75505Sopenharmony_ci
266e5b75505Sopenharmony_cistatic int
267e5b75505Sopenharmony_cibsd_del_key(void *priv, const u8 *addr, int key_idx)
268e5b75505Sopenharmony_ci{
269e5b75505Sopenharmony_ci	struct ieee80211req_del_key wk;
270e5b75505Sopenharmony_ci
271e5b75505Sopenharmony_ci	os_memset(&wk, 0, sizeof(wk));
272e5b75505Sopenharmony_ci	if (addr == NULL) {
273e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx);
274e5b75505Sopenharmony_ci		wk.idk_keyix = key_idx;
275e5b75505Sopenharmony_ci	} else {
276e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__,
277e5b75505Sopenharmony_ci			   MAC2STR(addr));
278e5b75505Sopenharmony_ci		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
279e5b75505Sopenharmony_ci		wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE;	/* XXX */
280e5b75505Sopenharmony_ci	}
281e5b75505Sopenharmony_ci
282e5b75505Sopenharmony_ci	return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
283e5b75505Sopenharmony_ci}
284e5b75505Sopenharmony_ci
285e5b75505Sopenharmony_cistatic int
286e5b75505Sopenharmony_cibsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr)
287e5b75505Sopenharmony_ci{
288e5b75505Sopenharmony_ci	struct ieee80211req_mlme mlme;
289e5b75505Sopenharmony_ci
290e5b75505Sopenharmony_ci	os_memset(&mlme, 0, sizeof(mlme));
291e5b75505Sopenharmony_ci	mlme.im_op = op;
292e5b75505Sopenharmony_ci	mlme.im_reason = reason;
293e5b75505Sopenharmony_ci	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
294e5b75505Sopenharmony_ci	return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
295e5b75505Sopenharmony_ci}
296e5b75505Sopenharmony_ci
297e5b75505Sopenharmony_cistatic int
298e5b75505Sopenharmony_cibsd_ctrl_iface(void *priv, int enable)
299e5b75505Sopenharmony_ci{
300e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
301e5b75505Sopenharmony_ci	struct ifreq ifr;
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci	os_memset(&ifr, 0, sizeof(ifr));
304e5b75505Sopenharmony_ci	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
305e5b75505Sopenharmony_ci
306e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCGIFFLAGS, &ifr) < 0) {
307e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
308e5b75505Sopenharmony_ci			   strerror(errno));
309e5b75505Sopenharmony_ci		return -1;
310e5b75505Sopenharmony_ci	}
311e5b75505Sopenharmony_ci	drv->flags = ifr.ifr_flags;
312e5b75505Sopenharmony_ci
313e5b75505Sopenharmony_ci	if (enable) {
314e5b75505Sopenharmony_ci		if (ifr.ifr_flags & IFF_UP)
315e5b75505Sopenharmony_ci			return 0;
316e5b75505Sopenharmony_ci		ifr.ifr_flags |= IFF_UP;
317e5b75505Sopenharmony_ci	} else {
318e5b75505Sopenharmony_ci		if (!(ifr.ifr_flags & IFF_UP))
319e5b75505Sopenharmony_ci			return 0;
320e5b75505Sopenharmony_ci		ifr.ifr_flags &= ~IFF_UP;
321e5b75505Sopenharmony_ci	}
322e5b75505Sopenharmony_ci
323e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
324e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
325e5b75505Sopenharmony_ci			   strerror(errno));
326e5b75505Sopenharmony_ci		return -1;
327e5b75505Sopenharmony_ci	}
328e5b75505Sopenharmony_ci
329e5b75505Sopenharmony_ci	drv->flags = ifr.ifr_flags;
330e5b75505Sopenharmony_ci	return 0;
331e5b75505Sopenharmony_ci}
332e5b75505Sopenharmony_ci
333e5b75505Sopenharmony_cistatic int
334e5b75505Sopenharmony_cibsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
335e5b75505Sopenharmony_ci	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
336e5b75505Sopenharmony_ci	    size_t seq_len, const u8 *key, size_t key_len)
337e5b75505Sopenharmony_ci{
338e5b75505Sopenharmony_ci	struct ieee80211req_key wk;
339e5b75505Sopenharmony_ci#ifdef IEEE80211_KEY_NOREPLAY
340e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
341e5b75505Sopenharmony_ci#endif /* IEEE80211_KEY_NOREPLAY */
342e5b75505Sopenharmony_ci
343e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
344e5b75505Sopenharmony_ci		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
345e5b75505Sopenharmony_ci		   set_tx, seq_len, key_len);
346e5b75505Sopenharmony_ci
347e5b75505Sopenharmony_ci	if (alg == WPA_ALG_NONE) {
348e5b75505Sopenharmony_ci#ifndef HOSTAPD
349e5b75505Sopenharmony_ci		if (addr == NULL || is_broadcast_ether_addr(addr))
350e5b75505Sopenharmony_ci			return bsd_del_key(priv, NULL, key_idx);
351e5b75505Sopenharmony_ci		else
352e5b75505Sopenharmony_ci#endif /* HOSTAPD */
353e5b75505Sopenharmony_ci			return bsd_del_key(priv, addr, key_idx);
354e5b75505Sopenharmony_ci	}
355e5b75505Sopenharmony_ci
356e5b75505Sopenharmony_ci	os_memset(&wk, 0, sizeof(wk));
357e5b75505Sopenharmony_ci	switch (alg) {
358e5b75505Sopenharmony_ci	case WPA_ALG_WEP:
359e5b75505Sopenharmony_ci		wk.ik_type = IEEE80211_CIPHER_WEP;
360e5b75505Sopenharmony_ci		break;
361e5b75505Sopenharmony_ci	case WPA_ALG_TKIP:
362e5b75505Sopenharmony_ci		wk.ik_type = IEEE80211_CIPHER_TKIP;
363e5b75505Sopenharmony_ci		break;
364e5b75505Sopenharmony_ci	case WPA_ALG_CCMP:
365e5b75505Sopenharmony_ci		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
366e5b75505Sopenharmony_ci		break;
367e5b75505Sopenharmony_ci	default:
368e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg);
369e5b75505Sopenharmony_ci		return -1;
370e5b75505Sopenharmony_ci	}
371e5b75505Sopenharmony_ci
372e5b75505Sopenharmony_ci	wk.ik_flags = IEEE80211_KEY_RECV;
373e5b75505Sopenharmony_ci	if (set_tx)
374e5b75505Sopenharmony_ci		wk.ik_flags |= IEEE80211_KEY_XMIT;
375e5b75505Sopenharmony_ci
376e5b75505Sopenharmony_ci	if (addr == NULL) {
377e5b75505Sopenharmony_ci		os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
378e5b75505Sopenharmony_ci		wk.ik_keyix = key_idx;
379e5b75505Sopenharmony_ci	} else {
380e5b75505Sopenharmony_ci		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
381e5b75505Sopenharmony_ci		/*
382e5b75505Sopenharmony_ci		 * Deduce whether group/global or unicast key by checking
383e5b75505Sopenharmony_ci		 * the address (yech).  Note also that we can only mark global
384e5b75505Sopenharmony_ci		 * keys default; doing this for a unicast key is an error.
385e5b75505Sopenharmony_ci		 */
386e5b75505Sopenharmony_ci		if (is_broadcast_ether_addr(addr)) {
387e5b75505Sopenharmony_ci			wk.ik_flags |= IEEE80211_KEY_GROUP;
388e5b75505Sopenharmony_ci			wk.ik_keyix = key_idx;
389e5b75505Sopenharmony_ci		} else {
390e5b75505Sopenharmony_ci			wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE :
391e5b75505Sopenharmony_ci				key_idx;
392e5b75505Sopenharmony_ci		}
393e5b75505Sopenharmony_ci	}
394e5b75505Sopenharmony_ci	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
395e5b75505Sopenharmony_ci		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
396e5b75505Sopenharmony_ci#ifndef HOSTAPD
397e5b75505Sopenharmony_ci#ifdef IEEE80211_KEY_NOREPLAY
398e5b75505Sopenharmony_ci	/*
399e5b75505Sopenharmony_ci	 * Ignore replay failures in IBSS and AHDEMO mode.
400e5b75505Sopenharmony_ci	 */
401e5b75505Sopenharmony_ci	if (drv->opmode == IEEE80211_M_IBSS ||
402e5b75505Sopenharmony_ci	    drv->opmode == IEEE80211_M_AHDEMO)
403e5b75505Sopenharmony_ci		wk.ik_flags |= IEEE80211_KEY_NOREPLAY;
404e5b75505Sopenharmony_ci#endif /* IEEE80211_KEY_NOREPLAY */
405e5b75505Sopenharmony_ci#endif /* HOSTAPD */
406e5b75505Sopenharmony_ci	wk.ik_keylen = key_len;
407e5b75505Sopenharmony_ci	if (seq) {
408e5b75505Sopenharmony_ci#ifdef WORDS_BIGENDIAN
409e5b75505Sopenharmony_ci		/*
410e5b75505Sopenharmony_ci		 * wk.ik_keyrsc is in host byte order (big endian), need to
411e5b75505Sopenharmony_ci		 * swap it to match with the byte order used in WPA.
412e5b75505Sopenharmony_ci		 */
413e5b75505Sopenharmony_ci		int i;
414e5b75505Sopenharmony_ci		u8 *keyrsc = (u8 *) &wk.ik_keyrsc;
415e5b75505Sopenharmony_ci		for (i = 0; i < seq_len; i++)
416e5b75505Sopenharmony_ci			keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i];
417e5b75505Sopenharmony_ci#else /* WORDS_BIGENDIAN */
418e5b75505Sopenharmony_ci		os_memcpy(&wk.ik_keyrsc, seq, seq_len);
419e5b75505Sopenharmony_ci#endif /* WORDS_BIGENDIAN */
420e5b75505Sopenharmony_ci	}
421e5b75505Sopenharmony_ci	os_memcpy(wk.ik_keydata, key, key_len);
422e5b75505Sopenharmony_ci
423e5b75505Sopenharmony_ci	return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
424e5b75505Sopenharmony_ci}
425e5b75505Sopenharmony_ci
426e5b75505Sopenharmony_cistatic int
427e5b75505Sopenharmony_cibsd_configure_wpa(void *priv, struct wpa_bss_params *params)
428e5b75505Sopenharmony_ci{
429e5b75505Sopenharmony_ci#ifndef IEEE80211_IOC_APPIE
430e5b75505Sopenharmony_ci	static const char *ciphernames[] =
431e5b75505Sopenharmony_ci		{ "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
432e5b75505Sopenharmony_ci	int v;
433e5b75505Sopenharmony_ci
434e5b75505Sopenharmony_ci	switch (params->wpa_group) {
435e5b75505Sopenharmony_ci	case WPA_CIPHER_CCMP:
436e5b75505Sopenharmony_ci		v = IEEE80211_CIPHER_AES_CCM;
437e5b75505Sopenharmony_ci		break;
438e5b75505Sopenharmony_ci	case WPA_CIPHER_TKIP:
439e5b75505Sopenharmony_ci		v = IEEE80211_CIPHER_TKIP;
440e5b75505Sopenharmony_ci		break;
441e5b75505Sopenharmony_ci	case WPA_CIPHER_WEP104:
442e5b75505Sopenharmony_ci		v = IEEE80211_CIPHER_WEP;
443e5b75505Sopenharmony_ci		break;
444e5b75505Sopenharmony_ci	case WPA_CIPHER_WEP40:
445e5b75505Sopenharmony_ci		v = IEEE80211_CIPHER_WEP;
446e5b75505Sopenharmony_ci		break;
447e5b75505Sopenharmony_ci	case WPA_CIPHER_NONE:
448e5b75505Sopenharmony_ci		v = IEEE80211_CIPHER_NONE;
449e5b75505Sopenharmony_ci		break;
450e5b75505Sopenharmony_ci	default:
451e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "Unknown group key cipher %u",
452e5b75505Sopenharmony_ci			   params->wpa_group);
453e5b75505Sopenharmony_ci		return -1;
454e5b75505Sopenharmony_ci	}
455e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
456e5b75505Sopenharmony_ci		   __func__, ciphernames[v], v);
457e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
458e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
459e5b75505Sopenharmony_ci			   "Unable to set group key cipher to %u (%s)",
460e5b75505Sopenharmony_ci			   v, ciphernames[v]);
461e5b75505Sopenharmony_ci		return -1;
462e5b75505Sopenharmony_ci	}
463e5b75505Sopenharmony_ci	if (v == IEEE80211_CIPHER_WEP) {
464e5b75505Sopenharmony_ci		/* key length is done only for specific ciphers */
465e5b75505Sopenharmony_ci		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
466e5b75505Sopenharmony_ci		if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
467e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
468e5b75505Sopenharmony_ci				   "Unable to set group key length to %u", v);
469e5b75505Sopenharmony_ci			return -1;
470e5b75505Sopenharmony_ci		}
471e5b75505Sopenharmony_ci	}
472e5b75505Sopenharmony_ci
473e5b75505Sopenharmony_ci	v = 0;
474e5b75505Sopenharmony_ci	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
475e5b75505Sopenharmony_ci		v |= 1<<IEEE80211_CIPHER_AES_CCM;
476e5b75505Sopenharmony_ci	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
477e5b75505Sopenharmony_ci		v |= 1<<IEEE80211_CIPHER_TKIP;
478e5b75505Sopenharmony_ci	if (params->wpa_pairwise & WPA_CIPHER_NONE)
479e5b75505Sopenharmony_ci		v |= 1<<IEEE80211_CIPHER_NONE;
480e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
481e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
482e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
483e5b75505Sopenharmony_ci			   "Unable to set pairwise key ciphers to 0x%x", v);
484e5b75505Sopenharmony_ci		return -1;
485e5b75505Sopenharmony_ci	}
486e5b75505Sopenharmony_ci
487e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
488e5b75505Sopenharmony_ci		   __func__, params->wpa_key_mgmt);
489e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
490e5b75505Sopenharmony_ci			  params->wpa_key_mgmt)) {
491e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
492e5b75505Sopenharmony_ci			   "Unable to set key management algorithms to 0x%x",
493e5b75505Sopenharmony_ci			   params->wpa_key_mgmt);
494e5b75505Sopenharmony_ci		return -1;
495e5b75505Sopenharmony_ci	}
496e5b75505Sopenharmony_ci
497e5b75505Sopenharmony_ci	v = 0;
498e5b75505Sopenharmony_ci	if (params->rsn_preauth)
499e5b75505Sopenharmony_ci		v |= BIT(0);
500e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
501e5b75505Sopenharmony_ci		   __func__, params->rsn_preauth);
502e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
503e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
504e5b75505Sopenharmony_ci			   v);
505e5b75505Sopenharmony_ci		return -1;
506e5b75505Sopenharmony_ci	}
507e5b75505Sopenharmony_ci#endif /* IEEE80211_IOC_APPIE */
508e5b75505Sopenharmony_ci
509e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
510e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
511e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
512e5b75505Sopenharmony_ci		return -1;
513e5b75505Sopenharmony_ci	}
514e5b75505Sopenharmony_ci	return 0;
515e5b75505Sopenharmony_ci}
516e5b75505Sopenharmony_ci
517e5b75505Sopenharmony_cistatic int
518e5b75505Sopenharmony_cibsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
519e5b75505Sopenharmony_ci{
520e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
521e5b75505Sopenharmony_ci
522e5b75505Sopenharmony_ci	if (!params->enabled) {
523e5b75505Sopenharmony_ci		/* XXX restore state */
524e5b75505Sopenharmony_ci		return set80211param(priv, IEEE80211_IOC_AUTHMODE,
525e5b75505Sopenharmony_ci				     IEEE80211_AUTH_AUTO);
526e5b75505Sopenharmony_ci	}
527e5b75505Sopenharmony_ci	if (!params->wpa && !params->ieee802_1x) {
528e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled",
529e5b75505Sopenharmony_ci			   __func__);
530e5b75505Sopenharmony_ci		return -1;
531e5b75505Sopenharmony_ci	}
532e5b75505Sopenharmony_ci	if (params->wpa && bsd_configure_wpa(priv, params) != 0) {
533e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state",
534e5b75505Sopenharmony_ci			   __func__);
535e5b75505Sopenharmony_ci		return -1;
536e5b75505Sopenharmony_ci	}
537e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
538e5b75505Sopenharmony_ci		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
539e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X",
540e5b75505Sopenharmony_ci			   __func__);
541e5b75505Sopenharmony_ci		return -1;
542e5b75505Sopenharmony_ci	}
543e5b75505Sopenharmony_ci	return bsd_ctrl_iface(priv, 1);
544e5b75505Sopenharmony_ci}
545e5b75505Sopenharmony_ci
546e5b75505Sopenharmony_cistatic void
547e5b75505Sopenharmony_cibsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
548e5b75505Sopenharmony_ci{
549e5b75505Sopenharmony_ci	struct ieee80211req_wpaie ie;
550e5b75505Sopenharmony_ci	int ielen = 0;
551e5b75505Sopenharmony_ci	u8 *iebuf = NULL;
552e5b75505Sopenharmony_ci
553e5b75505Sopenharmony_ci	/*
554e5b75505Sopenharmony_ci	 * Fetch and validate any negotiated WPA/RSN parameters.
555e5b75505Sopenharmony_ci	 */
556e5b75505Sopenharmony_ci	memset(&ie, 0, sizeof(ie));
557e5b75505Sopenharmony_ci	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
558e5b75505Sopenharmony_ci	if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
559e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
560e5b75505Sopenharmony_ci			   "Failed to get WPA/RSN information element");
561e5b75505Sopenharmony_ci		goto no_ie;
562e5b75505Sopenharmony_ci	}
563e5b75505Sopenharmony_ci	iebuf = ie.wpa_ie;
564e5b75505Sopenharmony_ci	ielen = ie.wpa_ie[1];
565e5b75505Sopenharmony_ci	if (ielen == 0)
566e5b75505Sopenharmony_ci		iebuf = NULL;
567e5b75505Sopenharmony_ci	else
568e5b75505Sopenharmony_ci		ielen += 2;
569e5b75505Sopenharmony_ci
570e5b75505Sopenharmony_cino_ie:
571e5b75505Sopenharmony_ci	drv_event_assoc(ctx, addr, iebuf, ielen, 0);
572e5b75505Sopenharmony_ci}
573e5b75505Sopenharmony_ci
574e5b75505Sopenharmony_cistatic int
575e5b75505Sopenharmony_cibsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
576e5b75505Sopenharmony_ci	       int encrypt, const u8 *own_addr, u32 flags)
577e5b75505Sopenharmony_ci{
578e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
579e5b75505Sopenharmony_ci
580e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len);
581e5b75505Sopenharmony_ci
582e5b75505Sopenharmony_ci	return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data,
583e5b75505Sopenharmony_ci			      data_len);
584e5b75505Sopenharmony_ci}
585e5b75505Sopenharmony_ci
586e5b75505Sopenharmony_cistatic int
587e5b75505Sopenharmony_cibsd_set_freq(void *priv, struct hostapd_freq_params *freq)
588e5b75505Sopenharmony_ci{
589e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
590e5b75505Sopenharmony_ci#ifdef SIOCS80211CHANNEL
591e5b75505Sopenharmony_ci	struct ieee80211chanreq creq;
592e5b75505Sopenharmony_ci#endif /* SIOCS80211CHANNEL */
593e5b75505Sopenharmony_ci	u32 mode;
594e5b75505Sopenharmony_ci	int channel = freq->channel;
595e5b75505Sopenharmony_ci
596e5b75505Sopenharmony_ci	if (channel < 14) {
597e5b75505Sopenharmony_ci		mode =
598e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N
599e5b75505Sopenharmony_ci			freq->ht_enabled ? IFM_IEEE80211_11NG :
600e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */
601e5b75505Sopenharmony_ci		        IFM_IEEE80211_11G;
602e5b75505Sopenharmony_ci	} else if (channel == 14) {
603e5b75505Sopenharmony_ci		mode = IFM_IEEE80211_11B;
604e5b75505Sopenharmony_ci	} else {
605e5b75505Sopenharmony_ci		mode =
606e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N
607e5b75505Sopenharmony_ci			freq->ht_enabled ? IFM_IEEE80211_11NA :
608e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */
609e5b75505Sopenharmony_ci			IFM_IEEE80211_11A;
610e5b75505Sopenharmony_ci	}
611e5b75505Sopenharmony_ci	if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
612e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: failed to set modulation mode",
613e5b75505Sopenharmony_ci			   __func__);
614e5b75505Sopenharmony_ci		return -1;
615e5b75505Sopenharmony_ci	}
616e5b75505Sopenharmony_ci
617e5b75505Sopenharmony_ci#ifdef SIOCS80211CHANNEL
618e5b75505Sopenharmony_ci	os_memset(&creq, 0, sizeof(creq));
619e5b75505Sopenharmony_ci	os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
620e5b75505Sopenharmony_ci	creq.i_channel = (u_int16_t)channel;
621e5b75505Sopenharmony_ci	return ioctl(drv->global->sock, SIOCS80211CHANNEL, &creq);
622e5b75505Sopenharmony_ci#else /* SIOCS80211CHANNEL */
623e5b75505Sopenharmony_ci	return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
624e5b75505Sopenharmony_ci#endif /* SIOCS80211CHANNEL */
625e5b75505Sopenharmony_ci}
626e5b75505Sopenharmony_ci
627e5b75505Sopenharmony_cistatic int
628e5b75505Sopenharmony_cibsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
629e5b75505Sopenharmony_ci{
630e5b75505Sopenharmony_ci#ifdef IEEE80211_IOC_APPIE
631e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__,
632e5b75505Sopenharmony_ci		   (unsigned long)ie_len);
633e5b75505Sopenharmony_ci	return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA,
634e5b75505Sopenharmony_ci			    ie, ie_len);
635e5b75505Sopenharmony_ci#endif /* IEEE80211_IOC_APPIE */
636e5b75505Sopenharmony_ci	return 0;
637e5b75505Sopenharmony_ci}
638e5b75505Sopenharmony_ci
639e5b75505Sopenharmony_cistatic size_t
640e5b75505Sopenharmony_cirtbuf_len(void)
641e5b75505Sopenharmony_ci{
642e5b75505Sopenharmony_ci	size_t len;
643e5b75505Sopenharmony_ci
644e5b75505Sopenharmony_ci	int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
645e5b75505Sopenharmony_ci
646e5b75505Sopenharmony_ci	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
647e5b75505Sopenharmony_ci		wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
648e5b75505Sopenharmony_ci			   strerror(errno));
649e5b75505Sopenharmony_ci		len = 2048;
650e5b75505Sopenharmony_ci	}
651e5b75505Sopenharmony_ci
652e5b75505Sopenharmony_ci	return len;
653e5b75505Sopenharmony_ci}
654e5b75505Sopenharmony_ci
655e5b75505Sopenharmony_ci#ifdef HOSTAPD
656e5b75505Sopenharmony_ci
657e5b75505Sopenharmony_ci/*
658e5b75505Sopenharmony_ci * Avoid conflicts with hostapd definitions by undefining couple of defines
659e5b75505Sopenharmony_ci * from net80211 header files.
660e5b75505Sopenharmony_ci */
661e5b75505Sopenharmony_ci#undef RSN_VERSION
662e5b75505Sopenharmony_ci#undef WPA_VERSION
663e5b75505Sopenharmony_ci#undef WPA_OUI_TYPE
664e5b75505Sopenharmony_ci
665e5b75505Sopenharmony_cistatic int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
666e5b75505Sopenharmony_ci			  u16 reason_code);
667e5b75505Sopenharmony_ci
668e5b75505Sopenharmony_cistatic const char *
669e5b75505Sopenharmony_ciether_sprintf(const u8 *addr)
670e5b75505Sopenharmony_ci{
671e5b75505Sopenharmony_ci	static char buf[sizeof(MACSTR)];
672e5b75505Sopenharmony_ci
673e5b75505Sopenharmony_ci	if (addr != NULL)
674e5b75505Sopenharmony_ci		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
675e5b75505Sopenharmony_ci	else
676e5b75505Sopenharmony_ci		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
677e5b75505Sopenharmony_ci	return buf;
678e5b75505Sopenharmony_ci}
679e5b75505Sopenharmony_ci
680e5b75505Sopenharmony_cistatic int
681e5b75505Sopenharmony_cibsd_set_privacy(void *priv, int enabled)
682e5b75505Sopenharmony_ci{
683e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
684e5b75505Sopenharmony_ci
685e5b75505Sopenharmony_ci	return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled);
686e5b75505Sopenharmony_ci}
687e5b75505Sopenharmony_ci
688e5b75505Sopenharmony_cistatic int
689e5b75505Sopenharmony_cibsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
690e5b75505Sopenharmony_ci	       u8 *seq)
691e5b75505Sopenharmony_ci{
692e5b75505Sopenharmony_ci	struct ieee80211req_key wk;
693e5b75505Sopenharmony_ci
694e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
695e5b75505Sopenharmony_ci		   __func__, ether_sprintf(addr), idx);
696e5b75505Sopenharmony_ci
697e5b75505Sopenharmony_ci	memset(&wk, 0, sizeof(wk));
698e5b75505Sopenharmony_ci	if (addr == NULL)
699e5b75505Sopenharmony_ci		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
700e5b75505Sopenharmony_ci	else
701e5b75505Sopenharmony_ci		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
702e5b75505Sopenharmony_ci	wk.ik_keyix = idx;
703e5b75505Sopenharmony_ci
704e5b75505Sopenharmony_ci	if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
705e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "Failed to get encryption");
706e5b75505Sopenharmony_ci		return -1;
707e5b75505Sopenharmony_ci	}
708e5b75505Sopenharmony_ci
709e5b75505Sopenharmony_ci#ifdef WORDS_BIGENDIAN
710e5b75505Sopenharmony_ci	{
711e5b75505Sopenharmony_ci		/*
712e5b75505Sopenharmony_ci		 * wk.ik_keytsc is in host byte order (big endian), need to
713e5b75505Sopenharmony_ci		 * swap it to match with the byte order used in WPA.
714e5b75505Sopenharmony_ci		 */
715e5b75505Sopenharmony_ci		int i;
716e5b75505Sopenharmony_ci		u8 tmp[WPA_KEY_RSC_LEN];
717e5b75505Sopenharmony_ci		memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
718e5b75505Sopenharmony_ci		for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
719e5b75505Sopenharmony_ci			seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
720e5b75505Sopenharmony_ci		}
721e5b75505Sopenharmony_ci	}
722e5b75505Sopenharmony_ci#else /* WORDS_BIGENDIAN */
723e5b75505Sopenharmony_ci	memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
724e5b75505Sopenharmony_ci#endif /* WORDS_BIGENDIAN */
725e5b75505Sopenharmony_ci	return 0;
726e5b75505Sopenharmony_ci}
727e5b75505Sopenharmony_ci
728e5b75505Sopenharmony_ci
729e5b75505Sopenharmony_cistatic int
730e5b75505Sopenharmony_cibsd_flush(void *priv)
731e5b75505Sopenharmony_ci{
732e5b75505Sopenharmony_ci	u8 allsta[IEEE80211_ADDR_LEN];
733e5b75505Sopenharmony_ci
734e5b75505Sopenharmony_ci	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
735e5b75505Sopenharmony_ci	return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE);
736e5b75505Sopenharmony_ci}
737e5b75505Sopenharmony_ci
738e5b75505Sopenharmony_ci
739e5b75505Sopenharmony_cistatic int
740e5b75505Sopenharmony_cibsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
741e5b75505Sopenharmony_ci			 const u8 *addr)
742e5b75505Sopenharmony_ci{
743e5b75505Sopenharmony_ci	struct ieee80211req_sta_stats stats;
744e5b75505Sopenharmony_ci
745e5b75505Sopenharmony_ci	memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
746e5b75505Sopenharmony_ci	if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats))
747e5b75505Sopenharmony_ci	    > 0) {
748e5b75505Sopenharmony_ci		/* XXX? do packets counts include non-data frames? */
749e5b75505Sopenharmony_ci		data->rx_packets = stats.is_stats.ns_rx_data;
750e5b75505Sopenharmony_ci		data->rx_bytes = stats.is_stats.ns_rx_bytes;
751e5b75505Sopenharmony_ci		data->tx_packets = stats.is_stats.ns_tx_data;
752e5b75505Sopenharmony_ci		data->tx_bytes = stats.is_stats.ns_tx_bytes;
753e5b75505Sopenharmony_ci	}
754e5b75505Sopenharmony_ci	return 0;
755e5b75505Sopenharmony_ci}
756e5b75505Sopenharmony_ci
757e5b75505Sopenharmony_cistatic int
758e5b75505Sopenharmony_cibsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, u16 reason_code)
759e5b75505Sopenharmony_ci{
760e5b75505Sopenharmony_ci	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
761e5b75505Sopenharmony_ci				   addr);
762e5b75505Sopenharmony_ci}
763e5b75505Sopenharmony_ci
764e5b75505Sopenharmony_cistatic int
765e5b75505Sopenharmony_cibsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
766e5b75505Sopenharmony_ci		 u16 reason_code)
767e5b75505Sopenharmony_ci{
768e5b75505Sopenharmony_ci	return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
769e5b75505Sopenharmony_ci				   addr);
770e5b75505Sopenharmony_ci}
771e5b75505Sopenharmony_ci
772e5b75505Sopenharmony_cistatic void
773e5b75505Sopenharmony_cibsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
774e5b75505Sopenharmony_ci{
775e5b75505Sopenharmony_ci	struct bsd_driver_global *global = sock_ctx;
776e5b75505Sopenharmony_ci	struct bsd_driver_data *drv;
777e5b75505Sopenharmony_ci	struct if_announcemsghdr *ifan;
778e5b75505Sopenharmony_ci	struct rt_msghdr *rtm;
779e5b75505Sopenharmony_ci	struct ieee80211_michael_event *mic;
780e5b75505Sopenharmony_ci	struct ieee80211_join_event *join;
781e5b75505Sopenharmony_ci	struct ieee80211_leave_event *leave;
782e5b75505Sopenharmony_ci	int n;
783e5b75505Sopenharmony_ci	union wpa_event_data data;
784e5b75505Sopenharmony_ci
785e5b75505Sopenharmony_ci	n = read(sock, global->event_buf, global->event_buf_len);
786e5b75505Sopenharmony_ci	if (n < 0) {
787e5b75505Sopenharmony_ci		if (errno != EINTR && errno != EAGAIN)
788e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "%s read() failed: %s",
789e5b75505Sopenharmony_ci				   __func__, strerror(errno));
790e5b75505Sopenharmony_ci		return;
791e5b75505Sopenharmony_ci	}
792e5b75505Sopenharmony_ci
793e5b75505Sopenharmony_ci	rtm = (struct rt_msghdr *) global->event_buf;
794e5b75505Sopenharmony_ci	if (rtm->rtm_version != RTM_VERSION) {
795e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
796e5b75505Sopenharmony_ci			   rtm->rtm_version);
797e5b75505Sopenharmony_ci		return;
798e5b75505Sopenharmony_ci	}
799e5b75505Sopenharmony_ci	switch (rtm->rtm_type) {
800e5b75505Sopenharmony_ci	case RTM_IEEE80211:
801e5b75505Sopenharmony_ci		ifan = (struct if_announcemsghdr *) rtm;
802e5b75505Sopenharmony_ci		drv = bsd_get_drvindex(global, ifan->ifan_index);
803e5b75505Sopenharmony_ci		if (drv == NULL)
804e5b75505Sopenharmony_ci			return;
805e5b75505Sopenharmony_ci		switch (ifan->ifan_what) {
806e5b75505Sopenharmony_ci		case RTM_IEEE80211_ASSOC:
807e5b75505Sopenharmony_ci		case RTM_IEEE80211_REASSOC:
808e5b75505Sopenharmony_ci		case RTM_IEEE80211_DISASSOC:
809e5b75505Sopenharmony_ci		case RTM_IEEE80211_SCAN:
810e5b75505Sopenharmony_ci			break;
811e5b75505Sopenharmony_ci		case RTM_IEEE80211_LEAVE:
812e5b75505Sopenharmony_ci			leave = (struct ieee80211_leave_event *) &ifan[1];
813e5b75505Sopenharmony_ci			drv_event_disassoc(drv->hapd, leave->iev_addr);
814e5b75505Sopenharmony_ci			break;
815e5b75505Sopenharmony_ci		case RTM_IEEE80211_JOIN:
816e5b75505Sopenharmony_ci#ifdef RTM_IEEE80211_REJOIN
817e5b75505Sopenharmony_ci		case RTM_IEEE80211_REJOIN:
818e5b75505Sopenharmony_ci#endif
819e5b75505Sopenharmony_ci			join = (struct ieee80211_join_event *) &ifan[1];
820e5b75505Sopenharmony_ci			bsd_new_sta(drv, drv->hapd, join->iev_addr);
821e5b75505Sopenharmony_ci			break;
822e5b75505Sopenharmony_ci		case RTM_IEEE80211_REPLAY:
823e5b75505Sopenharmony_ci			/* ignore */
824e5b75505Sopenharmony_ci			break;
825e5b75505Sopenharmony_ci		case RTM_IEEE80211_MICHAEL:
826e5b75505Sopenharmony_ci			mic = (struct ieee80211_michael_event *) &ifan[1];
827e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
828e5b75505Sopenharmony_ci				"Michael MIC failure wireless event: "
829e5b75505Sopenharmony_ci				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
830e5b75505Sopenharmony_ci				MAC2STR(mic->iev_src));
831e5b75505Sopenharmony_ci			os_memset(&data, 0, sizeof(data));
832e5b75505Sopenharmony_ci			data.michael_mic_failure.unicast = 1;
833e5b75505Sopenharmony_ci			data.michael_mic_failure.src = mic->iev_src;
834e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->hapd,
835e5b75505Sopenharmony_ci					     EVENT_MICHAEL_MIC_FAILURE, &data);
836e5b75505Sopenharmony_ci			break;
837e5b75505Sopenharmony_ci		}
838e5b75505Sopenharmony_ci		break;
839e5b75505Sopenharmony_ci	}
840e5b75505Sopenharmony_ci}
841e5b75505Sopenharmony_ci
842e5b75505Sopenharmony_cistatic void
843e5b75505Sopenharmony_cihandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
844e5b75505Sopenharmony_ci{
845e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = ctx;
846e5b75505Sopenharmony_ci	drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
847e5b75505Sopenharmony_ci}
848e5b75505Sopenharmony_ci
849e5b75505Sopenharmony_cistatic void *
850e5b75505Sopenharmony_cibsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
851e5b75505Sopenharmony_ci{
852e5b75505Sopenharmony_ci	struct bsd_driver_data *drv;
853e5b75505Sopenharmony_ci
854e5b75505Sopenharmony_ci	drv = os_zalloc(sizeof(struct bsd_driver_data));
855e5b75505Sopenharmony_ci	if (drv == NULL) {
856e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data");
857e5b75505Sopenharmony_ci		return NULL;
858e5b75505Sopenharmony_ci	}
859e5b75505Sopenharmony_ci
860e5b75505Sopenharmony_ci	drv->ifindex = if_nametoindex(params->ifname);
861e5b75505Sopenharmony_ci	if (drv->ifindex == 0) {
862e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
863e5b75505Sopenharmony_ci			   __func__, params->ifname);
864e5b75505Sopenharmony_ci		goto bad;
865e5b75505Sopenharmony_ci	}
866e5b75505Sopenharmony_ci
867e5b75505Sopenharmony_ci	drv->hapd = hapd;
868e5b75505Sopenharmony_ci	drv->global = params->global_priv;
869e5b75505Sopenharmony_ci	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
870e5b75505Sopenharmony_ci
871e5b75505Sopenharmony_ci	drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
872e5b75505Sopenharmony_ci					handle_read, drv, 0);
873e5b75505Sopenharmony_ci	if (drv->sock_xmit == NULL)
874e5b75505Sopenharmony_ci		goto bad;
875e5b75505Sopenharmony_ci	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
876e5b75505Sopenharmony_ci		goto bad;
877e5b75505Sopenharmony_ci
878e5b75505Sopenharmony_ci	/* mark down during setup */
879e5b75505Sopenharmony_ci	if (bsd_ctrl_iface(drv, 0) < 0)
880e5b75505Sopenharmony_ci		goto bad;
881e5b75505Sopenharmony_ci
882e5b75505Sopenharmony_ci	if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
883e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
884e5b75505Sopenharmony_ci			   __func__);
885e5b75505Sopenharmony_ci		goto bad;
886e5b75505Sopenharmony_ci	}
887e5b75505Sopenharmony_ci
888e5b75505Sopenharmony_ci	dl_list_add(&drv->global->ifaces, &drv->list);
889e5b75505Sopenharmony_ci
890e5b75505Sopenharmony_ci	return drv;
891e5b75505Sopenharmony_cibad:
892e5b75505Sopenharmony_ci	if (drv->sock_xmit != NULL)
893e5b75505Sopenharmony_ci		l2_packet_deinit(drv->sock_xmit);
894e5b75505Sopenharmony_ci	os_free(drv);
895e5b75505Sopenharmony_ci	return NULL;
896e5b75505Sopenharmony_ci}
897e5b75505Sopenharmony_ci
898e5b75505Sopenharmony_ci
899e5b75505Sopenharmony_cistatic void
900e5b75505Sopenharmony_cibsd_deinit(void *priv)
901e5b75505Sopenharmony_ci{
902e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
903e5b75505Sopenharmony_ci
904e5b75505Sopenharmony_ci	if (drv->ifindex != 0)
905e5b75505Sopenharmony_ci		bsd_ctrl_iface(drv, 0);
906e5b75505Sopenharmony_ci	if (drv->sock_xmit != NULL)
907e5b75505Sopenharmony_ci		l2_packet_deinit(drv->sock_xmit);
908e5b75505Sopenharmony_ci	os_free(drv);
909e5b75505Sopenharmony_ci}
910e5b75505Sopenharmony_ci
911e5b75505Sopenharmony_ci
912e5b75505Sopenharmony_cistatic int
913e5b75505Sopenharmony_cibsd_commit(void *priv)
914e5b75505Sopenharmony_ci{
915e5b75505Sopenharmony_ci	return bsd_ctrl_iface(priv, 1);
916e5b75505Sopenharmony_ci}
917e5b75505Sopenharmony_ci
918e5b75505Sopenharmony_ci
919e5b75505Sopenharmony_cistatic int
920e5b75505Sopenharmony_cibsd_set_sta_authorized(void *priv, const u8 *addr,
921e5b75505Sopenharmony_ci		       unsigned int total_flags, unsigned int flags_or,
922e5b75505Sopenharmony_ci		       unsigned int flags_and)
923e5b75505Sopenharmony_ci{
924e5b75505Sopenharmony_ci	int authorized = -1;
925e5b75505Sopenharmony_ci
926e5b75505Sopenharmony_ci	/* For now, only support setting Authorized flag */
927e5b75505Sopenharmony_ci	if (flags_or & WPA_STA_AUTHORIZED)
928e5b75505Sopenharmony_ci		authorized = 1;
929e5b75505Sopenharmony_ci	if (!(flags_and & WPA_STA_AUTHORIZED))
930e5b75505Sopenharmony_ci		authorized = 0;
931e5b75505Sopenharmony_ci
932e5b75505Sopenharmony_ci	if (authorized < 0)
933e5b75505Sopenharmony_ci		return 0;
934e5b75505Sopenharmony_ci
935e5b75505Sopenharmony_ci	return bsd_send_mlme_param(priv, authorized ?
936e5b75505Sopenharmony_ci				   IEEE80211_MLME_AUTHORIZE :
937e5b75505Sopenharmony_ci				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
938e5b75505Sopenharmony_ci}
939e5b75505Sopenharmony_ci#else /* HOSTAPD */
940e5b75505Sopenharmony_ci
941e5b75505Sopenharmony_cistatic int
942e5b75505Sopenharmony_ciget80211param(struct bsd_driver_data *drv, int op)
943e5b75505Sopenharmony_ci{
944e5b75505Sopenharmony_ci	struct ieee80211req ireq;
945e5b75505Sopenharmony_ci
946e5b75505Sopenharmony_ci	if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0)
947e5b75505Sopenharmony_ci		return -1;
948e5b75505Sopenharmony_ci	return ireq.i_val;
949e5b75505Sopenharmony_ci}
950e5b75505Sopenharmony_ci
951e5b75505Sopenharmony_cistatic int
952e5b75505Sopenharmony_ciwpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
953e5b75505Sopenharmony_ci{
954e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
955e5b75505Sopenharmony_ci#ifdef SIOCG80211BSSID
956e5b75505Sopenharmony_ci	struct ieee80211_bssid bs;
957e5b75505Sopenharmony_ci
958e5b75505Sopenharmony_ci	os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
959e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCG80211BSSID, &bs) < 0)
960e5b75505Sopenharmony_ci		return -1;
961e5b75505Sopenharmony_ci	os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
962e5b75505Sopenharmony_ci	return 0;
963e5b75505Sopenharmony_ci#else
964e5b75505Sopenharmony_ci	return get80211var(drv, IEEE80211_IOC_BSSID,
965e5b75505Sopenharmony_ci		bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
966e5b75505Sopenharmony_ci#endif
967e5b75505Sopenharmony_ci}
968e5b75505Sopenharmony_ci
969e5b75505Sopenharmony_cistatic int
970e5b75505Sopenharmony_ciwpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
971e5b75505Sopenharmony_ci{
972e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
973e5b75505Sopenharmony_ci	return bsd_get_ssid(drv, ssid, 0);
974e5b75505Sopenharmony_ci}
975e5b75505Sopenharmony_ci
976e5b75505Sopenharmony_cistatic int
977e5b75505Sopenharmony_ciwpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie,
978e5b75505Sopenharmony_ci			  size_t wpa_ie_len)
979e5b75505Sopenharmony_ci{
980e5b75505Sopenharmony_ci#ifdef IEEE80211_IOC_APPIE
981e5b75505Sopenharmony_ci	return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len);
982e5b75505Sopenharmony_ci#else /* IEEE80211_IOC_APPIE */
983e5b75505Sopenharmony_ci	return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
984e5b75505Sopenharmony_ci#endif /* IEEE80211_IOC_APPIE */
985e5b75505Sopenharmony_ci}
986e5b75505Sopenharmony_ci
987e5b75505Sopenharmony_cistatic int
988e5b75505Sopenharmony_ciwpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
989e5b75505Sopenharmony_ci{
990e5b75505Sopenharmony_ci	int ret = 0;
991e5b75505Sopenharmony_ci
992e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
993e5b75505Sopenharmony_ci		__func__, wpa, privacy);
994e5b75505Sopenharmony_ci
995e5b75505Sopenharmony_ci	if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
996e5b75505Sopenharmony_ci		ret = -1;
997e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0)
998e5b75505Sopenharmony_ci		ret = -1;
999e5b75505Sopenharmony_ci	if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0)
1000e5b75505Sopenharmony_ci		ret = -1;
1001e5b75505Sopenharmony_ci
1002e5b75505Sopenharmony_ci	return ret;
1003e5b75505Sopenharmony_ci}
1004e5b75505Sopenharmony_ci
1005e5b75505Sopenharmony_cistatic int
1006e5b75505Sopenharmony_ciwpa_driver_bsd_set_wpa(void *priv, int enabled)
1007e5b75505Sopenharmony_ci{
1008e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
1009e5b75505Sopenharmony_ci
1010e5b75505Sopenharmony_ci	return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
1011e5b75505Sopenharmony_ci}
1012e5b75505Sopenharmony_ci
1013e5b75505Sopenharmony_cistatic int
1014e5b75505Sopenharmony_ciwpa_driver_bsd_set_countermeasures(void *priv, int enabled)
1015e5b75505Sopenharmony_ci{
1016e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
1017e5b75505Sopenharmony_ci	return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled);
1018e5b75505Sopenharmony_ci}
1019e5b75505Sopenharmony_ci
1020e5b75505Sopenharmony_ci
1021e5b75505Sopenharmony_cistatic int
1022e5b75505Sopenharmony_ciwpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
1023e5b75505Sopenharmony_ci{
1024e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
1025e5b75505Sopenharmony_ci	return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
1026e5b75505Sopenharmony_ci}
1027e5b75505Sopenharmony_ci
1028e5b75505Sopenharmony_cistatic int
1029e5b75505Sopenharmony_ciwpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, u16 reason_code)
1030e5b75505Sopenharmony_ci{
1031e5b75505Sopenharmony_ci	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
1032e5b75505Sopenharmony_ci				   addr);
1033e5b75505Sopenharmony_ci}
1034e5b75505Sopenharmony_ci
1035e5b75505Sopenharmony_cistatic int
1036e5b75505Sopenharmony_ciwpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
1037e5b75505Sopenharmony_ci{
1038e5b75505Sopenharmony_ci	int authmode;
1039e5b75505Sopenharmony_ci
1040e5b75505Sopenharmony_ci	if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
1041e5b75505Sopenharmony_ci	    (auth_alg & WPA_AUTH_ALG_SHARED))
1042e5b75505Sopenharmony_ci		authmode = IEEE80211_AUTH_AUTO;
1043e5b75505Sopenharmony_ci	else if (auth_alg & WPA_AUTH_ALG_SHARED)
1044e5b75505Sopenharmony_ci		authmode = IEEE80211_AUTH_SHARED;
1045e5b75505Sopenharmony_ci	else
1046e5b75505Sopenharmony_ci		authmode = IEEE80211_AUTH_OPEN;
1047e5b75505Sopenharmony_ci
1048e5b75505Sopenharmony_ci	return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode);
1049e5b75505Sopenharmony_ci}
1050e5b75505Sopenharmony_ci
1051e5b75505Sopenharmony_cistatic void
1052e5b75505Sopenharmony_cihandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
1053e5b75505Sopenharmony_ci{
1054e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = ctx;
1055e5b75505Sopenharmony_ci
1056e5b75505Sopenharmony_ci	drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
1057e5b75505Sopenharmony_ci}
1058e5b75505Sopenharmony_ci
1059e5b75505Sopenharmony_cistatic int
1060e5b75505Sopenharmony_ciwpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
1061e5b75505Sopenharmony_ci{
1062e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
1063e5b75505Sopenharmony_ci	struct ieee80211req_mlme mlme;
1064e5b75505Sopenharmony_ci	u32 mode;
1065e5b75505Sopenharmony_ci	int privacy;
1066e5b75505Sopenharmony_ci	int ret = 0;
1067e5b75505Sopenharmony_ci
1068e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
1069e5b75505Sopenharmony_ci		"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
1070e5b75505Sopenharmony_ci		, __func__
1071e5b75505Sopenharmony_ci		   , (unsigned int) params->ssid_len, params->ssid
1072e5b75505Sopenharmony_ci		, (unsigned int) params->wpa_ie_len
1073e5b75505Sopenharmony_ci		, params->pairwise_suite
1074e5b75505Sopenharmony_ci		, params->group_suite
1075e5b75505Sopenharmony_ci		, params->key_mgmt_suite
1076e5b75505Sopenharmony_ci	);
1077e5b75505Sopenharmony_ci
1078e5b75505Sopenharmony_ci	switch (params->mode) {
1079e5b75505Sopenharmony_ci	case IEEE80211_MODE_INFRA:
1080e5b75505Sopenharmony_ci		mode = 0 /* STA */;
1081e5b75505Sopenharmony_ci		break;
1082e5b75505Sopenharmony_ci	case IEEE80211_MODE_IBSS:
1083e5b75505Sopenharmony_ci		mode = IFM_IEEE80211_IBSS;
1084e5b75505Sopenharmony_ci		break;
1085e5b75505Sopenharmony_ci	case IEEE80211_MODE_AP:
1086e5b75505Sopenharmony_ci		mode = IFM_IEEE80211_HOSTAP;
1087e5b75505Sopenharmony_ci		break;
1088e5b75505Sopenharmony_ci	default:
1089e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__);
1090e5b75505Sopenharmony_ci		return -1;
1091e5b75505Sopenharmony_ci	}
1092e5b75505Sopenharmony_ci	if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) {
1093e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
1094e5b75505Sopenharmony_ci			   __func__);
1095e5b75505Sopenharmony_ci		return -1;
1096e5b75505Sopenharmony_ci	}
1097e5b75505Sopenharmony_ci
1098e5b75505Sopenharmony_ci	if (params->mode == IEEE80211_MODE_AP) {
1099e5b75505Sopenharmony_ci		drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
1100e5b75505Sopenharmony_ci						handle_read, drv, 0);
1101e5b75505Sopenharmony_ci		if (drv->sock_xmit == NULL)
1102e5b75505Sopenharmony_ci			return -1;
1103e5b75505Sopenharmony_ci		drv->is_ap = 1;
1104e5b75505Sopenharmony_ci		return 0;
1105e5b75505Sopenharmony_ci	}
1106e5b75505Sopenharmony_ci
1107e5b75505Sopenharmony_ci	if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted)
1108e5b75505Sopenharmony_ci	    < 0)
1109e5b75505Sopenharmony_ci		ret = -1;
1110e5b75505Sopenharmony_ci	if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0)
1111e5b75505Sopenharmony_ci		ret = -1;
1112e5b75505Sopenharmony_ci	/* XXX error handling is wrong but unclear what to do... */
1113e5b75505Sopenharmony_ci	if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
1114e5b75505Sopenharmony_ci		return -1;
1115e5b75505Sopenharmony_ci
1116e5b75505Sopenharmony_ci	privacy = !(params->pairwise_suite == WPA_CIPHER_NONE &&
1117e5b75505Sopenharmony_ci	    params->group_suite == WPA_CIPHER_NONE &&
1118e5b75505Sopenharmony_ci	    params->key_mgmt_suite == WPA_KEY_MGMT_NONE &&
1119e5b75505Sopenharmony_ci	    params->wpa_ie_len == 0);
1120e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
1121e5b75505Sopenharmony_ci
1122e5b75505Sopenharmony_ci	if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
1123e5b75505Sopenharmony_ci		return -1;
1124e5b75505Sopenharmony_ci
1125e5b75505Sopenharmony_ci	if (params->wpa_ie_len &&
1126e5b75505Sopenharmony_ci	    set80211param(drv, IEEE80211_IOC_WPA,
1127e5b75505Sopenharmony_ci			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
1128e5b75505Sopenharmony_ci		return -1;
1129e5b75505Sopenharmony_ci
1130e5b75505Sopenharmony_ci	os_memset(&mlme, 0, sizeof(mlme));
1131e5b75505Sopenharmony_ci	mlme.im_op = IEEE80211_MLME_ASSOC;
1132e5b75505Sopenharmony_ci	if (params->ssid != NULL)
1133e5b75505Sopenharmony_ci		os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
1134e5b75505Sopenharmony_ci	mlme.im_ssid_len = params->ssid_len;
1135e5b75505Sopenharmony_ci	if (params->bssid != NULL)
1136e5b75505Sopenharmony_ci		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
1137e5b75505Sopenharmony_ci	if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
1138e5b75505Sopenharmony_ci		return -1;
1139e5b75505Sopenharmony_ci	return ret;
1140e5b75505Sopenharmony_ci}
1141e5b75505Sopenharmony_ci
1142e5b75505Sopenharmony_cistatic int
1143e5b75505Sopenharmony_ciwpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
1144e5b75505Sopenharmony_ci{
1145e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
1146e5b75505Sopenharmony_ci#ifdef IEEE80211_IOC_SCAN_MAX_SSID
1147e5b75505Sopenharmony_ci	struct ieee80211_scan_req sr;
1148e5b75505Sopenharmony_ci	int i;
1149e5b75505Sopenharmony_ci#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
1150e5b75505Sopenharmony_ci
1151e5b75505Sopenharmony_ci	if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) {
1152e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
1153e5b75505Sopenharmony_ci			   __func__);
1154e5b75505Sopenharmony_ci		return -1;
1155e5b75505Sopenharmony_ci	}
1156e5b75505Sopenharmony_ci
1157e5b75505Sopenharmony_ci	if (set80211param(drv, IEEE80211_IOC_ROAMING,
1158e5b75505Sopenharmony_ci			  IEEE80211_ROAMING_MANUAL) < 0) {
1159e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: failed to set "
1160e5b75505Sopenharmony_ci			   "wpa_supplicant-based roaming: %s", __func__,
1161e5b75505Sopenharmony_ci			   strerror(errno));
1162e5b75505Sopenharmony_ci		return -1;
1163e5b75505Sopenharmony_ci	}
1164e5b75505Sopenharmony_ci
1165e5b75505Sopenharmony_ci	if (wpa_driver_bsd_set_wpa(drv, 1) < 0) {
1166e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__,
1167e5b75505Sopenharmony_ci			   strerror(errno));
1168e5b75505Sopenharmony_ci		return -1;
1169e5b75505Sopenharmony_ci	}
1170e5b75505Sopenharmony_ci
1171e5b75505Sopenharmony_ci	/* NB: interface must be marked UP to do a scan */
1172e5b75505Sopenharmony_ci	if (bsd_ctrl_iface(drv, 1) < 0)
1173e5b75505Sopenharmony_ci		return -1;
1174e5b75505Sopenharmony_ci
1175e5b75505Sopenharmony_ci#ifdef IEEE80211_IOC_SCAN_MAX_SSID
1176e5b75505Sopenharmony_ci	os_memset(&sr, 0, sizeof(sr));
1177e5b75505Sopenharmony_ci	sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE |
1178e5b75505Sopenharmony_ci		IEEE80211_IOC_SCAN_NOJOIN;
1179e5b75505Sopenharmony_ci	sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
1180e5b75505Sopenharmony_ci	if (params->num_ssids > 0) {
1181e5b75505Sopenharmony_ci		sr.sr_nssid = params->num_ssids;
1182e5b75505Sopenharmony_ci#if 0
1183e5b75505Sopenharmony_ci		/* Boundary check is done by upper layer */
1184e5b75505Sopenharmony_ci		if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID)
1185e5b75505Sopenharmony_ci			sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID;
1186e5b75505Sopenharmony_ci#endif
1187e5b75505Sopenharmony_ci
1188e5b75505Sopenharmony_ci		/* NB: check scan cache first */
1189e5b75505Sopenharmony_ci		sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK;
1190e5b75505Sopenharmony_ci	}
1191e5b75505Sopenharmony_ci	for (i = 0; i < sr.sr_nssid; i++) {
1192e5b75505Sopenharmony_ci		sr.sr_ssid[i].len = params->ssids[i].ssid_len;
1193e5b75505Sopenharmony_ci		os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid,
1194e5b75505Sopenharmony_ci			  sr.sr_ssid[i].len);
1195e5b75505Sopenharmony_ci	}
1196e5b75505Sopenharmony_ci
1197e5b75505Sopenharmony_ci	/* NB: net80211 delivers a scan complete event so no need to poll */
1198e5b75505Sopenharmony_ci	return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr));
1199e5b75505Sopenharmony_ci#else /* IEEE80211_IOC_SCAN_MAX_SSID */
1200e5b75505Sopenharmony_ci	/* set desired ssid before scan */
1201e5b75505Sopenharmony_ci	if (bsd_set_ssid(drv, params->ssids[0].ssid,
1202e5b75505Sopenharmony_ci			 params->ssids[0].ssid_len) < 0)
1203e5b75505Sopenharmony_ci		return -1;
1204e5b75505Sopenharmony_ci
1205e5b75505Sopenharmony_ci	/* NB: net80211 delivers a scan complete event so no need to poll */
1206e5b75505Sopenharmony_ci	return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
1207e5b75505Sopenharmony_ci#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
1208e5b75505Sopenharmony_ci}
1209e5b75505Sopenharmony_ci
1210e5b75505Sopenharmony_cistatic void
1211e5b75505Sopenharmony_ciwpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
1212e5b75505Sopenharmony_ci{
1213e5b75505Sopenharmony_ci	struct bsd_driver_global *global = sock_ctx;
1214e5b75505Sopenharmony_ci	struct bsd_driver_data *drv;
1215e5b75505Sopenharmony_ci	struct if_announcemsghdr *ifan;
1216e5b75505Sopenharmony_ci	struct if_msghdr *ifm;
1217e5b75505Sopenharmony_ci	struct rt_msghdr *rtm;
1218e5b75505Sopenharmony_ci	union wpa_event_data event;
1219e5b75505Sopenharmony_ci	struct ieee80211_michael_event *mic;
1220e5b75505Sopenharmony_ci	struct ieee80211_leave_event *leave;
1221e5b75505Sopenharmony_ci	struct ieee80211_join_event *join;
1222e5b75505Sopenharmony_ci	int n;
1223e5b75505Sopenharmony_ci
1224e5b75505Sopenharmony_ci	n = read(sock, global->event_buf, global->event_buf_len);
1225e5b75505Sopenharmony_ci	if (n < 0) {
1226e5b75505Sopenharmony_ci		if (errno != EINTR && errno != EAGAIN)
1227e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "%s read() failed: %s",
1228e5b75505Sopenharmony_ci				   __func__, strerror(errno));
1229e5b75505Sopenharmony_ci		return;
1230e5b75505Sopenharmony_ci	}
1231e5b75505Sopenharmony_ci
1232e5b75505Sopenharmony_ci	rtm = (struct rt_msghdr *) global->event_buf;
1233e5b75505Sopenharmony_ci	if (rtm->rtm_version != RTM_VERSION) {
1234e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
1235e5b75505Sopenharmony_ci			   rtm->rtm_version);
1236e5b75505Sopenharmony_ci		return;
1237e5b75505Sopenharmony_ci	}
1238e5b75505Sopenharmony_ci	os_memset(&event, 0, sizeof(event));
1239e5b75505Sopenharmony_ci	switch (rtm->rtm_type) {
1240e5b75505Sopenharmony_ci	case RTM_IFANNOUNCE:
1241e5b75505Sopenharmony_ci		ifan = (struct if_announcemsghdr *) rtm;
1242e5b75505Sopenharmony_ci		switch (ifan->ifan_what) {
1243e5b75505Sopenharmony_ci		case IFAN_DEPARTURE:
1244e5b75505Sopenharmony_ci			drv = bsd_get_drvindex(global, ifan->ifan_index);
1245e5b75505Sopenharmony_ci			if (drv)
1246e5b75505Sopenharmony_ci				drv->if_removed = 1;
1247e5b75505Sopenharmony_ci			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
1248e5b75505Sopenharmony_ci			break;
1249e5b75505Sopenharmony_ci		case IFAN_ARRIVAL:
1250e5b75505Sopenharmony_ci			drv = bsd_get_drvname(global, ifan->ifan_name);
1251e5b75505Sopenharmony_ci			if (drv) {
1252e5b75505Sopenharmony_ci				drv->ifindex = ifan->ifan_index;
1253e5b75505Sopenharmony_ci				drv->if_removed = 0;
1254e5b75505Sopenharmony_ci			}
1255e5b75505Sopenharmony_ci			event.interface_status.ievent = EVENT_INTERFACE_ADDED;
1256e5b75505Sopenharmony_ci			break;
1257e5b75505Sopenharmony_ci		default:
1258e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
1259e5b75505Sopenharmony_ci			return;
1260e5b75505Sopenharmony_ci		}
1261e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
1262e5b75505Sopenharmony_ci			   ifan->ifan_name,
1263e5b75505Sopenharmony_ci			   ifan->ifan_what == IFAN_DEPARTURE ?
1264e5b75505Sopenharmony_ci				"removed" : "added");
1265e5b75505Sopenharmony_ci		os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
1266e5b75505Sopenharmony_ci			   sizeof(event.interface_status.ifname));
1267e5b75505Sopenharmony_ci		if (drv) {
1268e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
1269e5b75505Sopenharmony_ci					     &event);
1270e5b75505Sopenharmony_ci			/*
1271e5b75505Sopenharmony_ci			 * Set ifindex to zero after sending the event as the
1272e5b75505Sopenharmony_ci			 * event might query the driver to ensure a match.
1273e5b75505Sopenharmony_ci			 */
1274e5b75505Sopenharmony_ci			if (ifan->ifan_what == IFAN_DEPARTURE)
1275e5b75505Sopenharmony_ci				drv->ifindex = 0;
1276e5b75505Sopenharmony_ci		} else {
1277e5b75505Sopenharmony_ci			wpa_supplicant_event_global(global->ctx,
1278e5b75505Sopenharmony_ci						    EVENT_INTERFACE_STATUS,
1279e5b75505Sopenharmony_ci						    &event);
1280e5b75505Sopenharmony_ci		}
1281e5b75505Sopenharmony_ci		break;
1282e5b75505Sopenharmony_ci	case RTM_IEEE80211:
1283e5b75505Sopenharmony_ci		ifan = (struct if_announcemsghdr *) rtm;
1284e5b75505Sopenharmony_ci		drv = bsd_get_drvindex(global, ifan->ifan_index);
1285e5b75505Sopenharmony_ci		if (drv == NULL)
1286e5b75505Sopenharmony_ci			return;
1287e5b75505Sopenharmony_ci		switch (ifan->ifan_what) {
1288e5b75505Sopenharmony_ci		case RTM_IEEE80211_ASSOC:
1289e5b75505Sopenharmony_ci		case RTM_IEEE80211_REASSOC:
1290e5b75505Sopenharmony_ci			if (drv->is_ap)
1291e5b75505Sopenharmony_ci				break;
1292e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1293e5b75505Sopenharmony_ci			break;
1294e5b75505Sopenharmony_ci		case RTM_IEEE80211_DISASSOC:
1295e5b75505Sopenharmony_ci			if (drv->is_ap)
1296e5b75505Sopenharmony_ci				break;
1297e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
1298e5b75505Sopenharmony_ci			break;
1299e5b75505Sopenharmony_ci		case RTM_IEEE80211_SCAN:
1300e5b75505Sopenharmony_ci			if (drv->is_ap)
1301e5b75505Sopenharmony_ci				break;
1302e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
1303e5b75505Sopenharmony_ci					     NULL);
1304e5b75505Sopenharmony_ci			break;
1305e5b75505Sopenharmony_ci		case RTM_IEEE80211_LEAVE:
1306e5b75505Sopenharmony_ci			leave = (struct ieee80211_leave_event *) &ifan[1];
1307e5b75505Sopenharmony_ci			drv_event_disassoc(drv->ctx, leave->iev_addr);
1308e5b75505Sopenharmony_ci			break;
1309e5b75505Sopenharmony_ci		case RTM_IEEE80211_JOIN:
1310e5b75505Sopenharmony_ci#ifdef RTM_IEEE80211_REJOIN
1311e5b75505Sopenharmony_ci		case RTM_IEEE80211_REJOIN:
1312e5b75505Sopenharmony_ci#endif
1313e5b75505Sopenharmony_ci			join = (struct ieee80211_join_event *) &ifan[1];
1314e5b75505Sopenharmony_ci			bsd_new_sta(drv, drv->ctx, join->iev_addr);
1315e5b75505Sopenharmony_ci			break;
1316e5b75505Sopenharmony_ci		case RTM_IEEE80211_REPLAY:
1317e5b75505Sopenharmony_ci			/* ignore */
1318e5b75505Sopenharmony_ci			break;
1319e5b75505Sopenharmony_ci		case RTM_IEEE80211_MICHAEL:
1320e5b75505Sopenharmony_ci			mic = (struct ieee80211_michael_event *) &ifan[1];
1321e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
1322e5b75505Sopenharmony_ci				"Michael MIC failure wireless event: "
1323e5b75505Sopenharmony_ci				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
1324e5b75505Sopenharmony_ci				MAC2STR(mic->iev_src));
1325e5b75505Sopenharmony_ci
1326e5b75505Sopenharmony_ci			os_memset(&event, 0, sizeof(event));
1327e5b75505Sopenharmony_ci			event.michael_mic_failure.unicast =
1328e5b75505Sopenharmony_ci				!IEEE80211_IS_MULTICAST(mic->iev_dst);
1329e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->ctx,
1330e5b75505Sopenharmony_ci					     EVENT_MICHAEL_MIC_FAILURE, &event);
1331e5b75505Sopenharmony_ci			break;
1332e5b75505Sopenharmony_ci		}
1333e5b75505Sopenharmony_ci		break;
1334e5b75505Sopenharmony_ci	case RTM_IFINFO:
1335e5b75505Sopenharmony_ci		ifm = (struct if_msghdr *) rtm;
1336e5b75505Sopenharmony_ci		drv = bsd_get_drvindex(global, ifm->ifm_index);
1337e5b75505Sopenharmony_ci		if (drv == NULL)
1338e5b75505Sopenharmony_ci			return;
1339e5b75505Sopenharmony_ci		if ((ifm->ifm_flags & IFF_UP) == 0 &&
1340e5b75505Sopenharmony_ci		    (drv->flags & IFF_UP) != 0) {
1341e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
1342e5b75505Sopenharmony_ci				   drv->ifname);
1343e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
1344e5b75505Sopenharmony_ci					     NULL);
1345e5b75505Sopenharmony_ci		} else if ((ifm->ifm_flags & IFF_UP) != 0 &&
1346e5b75505Sopenharmony_ci		    (drv->flags & IFF_UP) == 0) {
1347e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
1348e5b75505Sopenharmony_ci				   drv->ifname);
1349e5b75505Sopenharmony_ci			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
1350e5b75505Sopenharmony_ci					     NULL);
1351e5b75505Sopenharmony_ci		}
1352e5b75505Sopenharmony_ci		drv->flags = ifm->ifm_flags;
1353e5b75505Sopenharmony_ci		break;
1354e5b75505Sopenharmony_ci	}
1355e5b75505Sopenharmony_ci}
1356e5b75505Sopenharmony_ci
1357e5b75505Sopenharmony_cistatic void
1358e5b75505Sopenharmony_ciwpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
1359e5b75505Sopenharmony_ci			      struct ieee80211req_scan_result *sr)
1360e5b75505Sopenharmony_ci{
1361e5b75505Sopenharmony_ci	struct wpa_scan_res *result, **tmp;
1362e5b75505Sopenharmony_ci	size_t extra_len;
1363e5b75505Sopenharmony_ci	u8 *pos;
1364e5b75505Sopenharmony_ci
1365e5b75505Sopenharmony_ci	extra_len = 2 + sr->isr_ssid_len;
1366e5b75505Sopenharmony_ci	extra_len += 2 + sr->isr_nrates;
1367e5b75505Sopenharmony_ci	extra_len += 3; /* ERP IE */
1368e5b75505Sopenharmony_ci	extra_len += sr->isr_ie_len;
1369e5b75505Sopenharmony_ci
1370e5b75505Sopenharmony_ci	result = os_zalloc(sizeof(*result) + extra_len);
1371e5b75505Sopenharmony_ci	if (result == NULL)
1372e5b75505Sopenharmony_ci		return;
1373e5b75505Sopenharmony_ci	os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN);
1374e5b75505Sopenharmony_ci	result->freq = sr->isr_freq;
1375e5b75505Sopenharmony_ci	result->beacon_int = sr->isr_intval;
1376e5b75505Sopenharmony_ci	result->caps = sr->isr_capinfo;
1377e5b75505Sopenharmony_ci	result->qual = sr->isr_rssi;
1378e5b75505Sopenharmony_ci	result->noise = sr->isr_noise;
1379e5b75505Sopenharmony_ci
1380e5b75505Sopenharmony_ci#ifdef __FreeBSD__
1381e5b75505Sopenharmony_ci	/*
1382e5b75505Sopenharmony_ci	 * the rssi value reported by the kernel is in 0.5dB steps relative to
1383e5b75505Sopenharmony_ci	 * the reported noise floor. see ieee80211_node.h for details.
1384e5b75505Sopenharmony_ci	 */
1385e5b75505Sopenharmony_ci	result->level = sr->isr_rssi / 2 + sr->isr_noise;
1386e5b75505Sopenharmony_ci#else
1387e5b75505Sopenharmony_ci	result->level = sr->isr_rssi;
1388e5b75505Sopenharmony_ci#endif
1389e5b75505Sopenharmony_ci
1390e5b75505Sopenharmony_ci	pos = (u8 *)(result + 1);
1391e5b75505Sopenharmony_ci
1392e5b75505Sopenharmony_ci	*pos++ = WLAN_EID_SSID;
1393e5b75505Sopenharmony_ci	*pos++ = sr->isr_ssid_len;
1394e5b75505Sopenharmony_ci	os_memcpy(pos, sr + 1, sr->isr_ssid_len);
1395e5b75505Sopenharmony_ci	pos += sr->isr_ssid_len;
1396e5b75505Sopenharmony_ci
1397e5b75505Sopenharmony_ci	/*
1398e5b75505Sopenharmony_ci	 * Deal all rates as supported rate.
1399e5b75505Sopenharmony_ci	 * Because net80211 doesn't report extended supported rate or not.
1400e5b75505Sopenharmony_ci	 */
1401e5b75505Sopenharmony_ci	*pos++ = WLAN_EID_SUPP_RATES;
1402e5b75505Sopenharmony_ci	*pos++ = sr->isr_nrates;
1403e5b75505Sopenharmony_ci	os_memcpy(pos, sr->isr_rates, sr->isr_nrates);
1404e5b75505Sopenharmony_ci	pos += sr->isr_nrates;
1405e5b75505Sopenharmony_ci
1406e5b75505Sopenharmony_ci	*pos++ = WLAN_EID_ERP_INFO;
1407e5b75505Sopenharmony_ci	*pos++ = 1;
1408e5b75505Sopenharmony_ci	*pos++ = sr->isr_erp;
1409e5b75505Sopenharmony_ci
1410e5b75505Sopenharmony_ci#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1411e5b75505Sopenharmony_ci	os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len + sr->isr_meshid_len,
1412e5b75505Sopenharmony_ci		  sr->isr_ie_len);
1413e5b75505Sopenharmony_ci#else
1414e5b75505Sopenharmony_ci	os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
1415e5b75505Sopenharmony_ci#endif
1416e5b75505Sopenharmony_ci	pos += sr->isr_ie_len;
1417e5b75505Sopenharmony_ci
1418e5b75505Sopenharmony_ci	result->ie_len = pos - (u8 *)(result + 1);
1419e5b75505Sopenharmony_ci
1420e5b75505Sopenharmony_ci	tmp = os_realloc_array(res->res, res->num + 1,
1421e5b75505Sopenharmony_ci			       sizeof(struct wpa_scan_res *));
1422e5b75505Sopenharmony_ci	if (tmp == NULL) {
1423e5b75505Sopenharmony_ci		os_free(result);
1424e5b75505Sopenharmony_ci		return;
1425e5b75505Sopenharmony_ci	}
1426e5b75505Sopenharmony_ci	tmp[res->num++] = result;
1427e5b75505Sopenharmony_ci	res->res = tmp;
1428e5b75505Sopenharmony_ci}
1429e5b75505Sopenharmony_ci
1430e5b75505Sopenharmony_cistruct wpa_scan_results *
1431e5b75505Sopenharmony_ciwpa_driver_bsd_get_scan_results2(void *priv)
1432e5b75505Sopenharmony_ci{
1433e5b75505Sopenharmony_ci	struct ieee80211req_scan_result *sr;
1434e5b75505Sopenharmony_ci	struct wpa_scan_results *res;
1435e5b75505Sopenharmony_ci	int len, rest;
1436e5b75505Sopenharmony_ci	uint8_t buf[24*1024], *pos;
1437e5b75505Sopenharmony_ci
1438e5b75505Sopenharmony_ci	len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024);
1439e5b75505Sopenharmony_ci	if (len < 0)
1440e5b75505Sopenharmony_ci		return NULL;
1441e5b75505Sopenharmony_ci
1442e5b75505Sopenharmony_ci	res = os_zalloc(sizeof(*res));
1443e5b75505Sopenharmony_ci	if (res == NULL)
1444e5b75505Sopenharmony_ci		return NULL;
1445e5b75505Sopenharmony_ci
1446e5b75505Sopenharmony_ci	pos = buf;
1447e5b75505Sopenharmony_ci	rest = len;
1448e5b75505Sopenharmony_ci	while (rest >= sizeof(struct ieee80211req_scan_result)) {
1449e5b75505Sopenharmony_ci		sr = (struct ieee80211req_scan_result *)pos;
1450e5b75505Sopenharmony_ci		wpa_driver_bsd_add_scan_entry(res, sr);
1451e5b75505Sopenharmony_ci		pos += sr->isr_len;
1452e5b75505Sopenharmony_ci		rest -= sr->isr_len;
1453e5b75505Sopenharmony_ci	}
1454e5b75505Sopenharmony_ci
1455e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)",
1456e5b75505Sopenharmony_ci		   len, (unsigned long)res->num);
1457e5b75505Sopenharmony_ci
1458e5b75505Sopenharmony_ci	return res;
1459e5b75505Sopenharmony_ci}
1460e5b75505Sopenharmony_ci
1461e5b75505Sopenharmony_cistatic int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
1462e5b75505Sopenharmony_ci{
1463e5b75505Sopenharmony_ci#ifdef IEEE80211_IOC_DEVCAPS
1464e5b75505Sopenharmony_ci/* kernel definitions copied from net80211/ieee80211_var.h */
1465e5b75505Sopenharmony_ci#define IEEE80211_CIPHER_WEP            0
1466e5b75505Sopenharmony_ci#define IEEE80211_CIPHER_TKIP           1
1467e5b75505Sopenharmony_ci#define IEEE80211_CIPHER_AES_CCM        3
1468e5b75505Sopenharmony_ci#define IEEE80211_CRYPTO_WEP            (1<<IEEE80211_CIPHER_WEP)
1469e5b75505Sopenharmony_ci#define IEEE80211_CRYPTO_TKIP           (1<<IEEE80211_CIPHER_TKIP)
1470e5b75505Sopenharmony_ci#define IEEE80211_CRYPTO_AES_CCM        (1<<IEEE80211_CIPHER_AES_CCM)
1471e5b75505Sopenharmony_ci#define IEEE80211_C_HOSTAP      0x00000400      /* CAPABILITY: HOSTAP avail */
1472e5b75505Sopenharmony_ci#define IEEE80211_C_WPA1        0x00800000      /* CAPABILITY: WPA1 avail */
1473e5b75505Sopenharmony_ci#define IEEE80211_C_WPA2        0x01000000      /* CAPABILITY: WPA2 avail */
1474e5b75505Sopenharmony_ci	struct ieee80211_devcaps_req devcaps;
1475e5b75505Sopenharmony_ci
1476e5b75505Sopenharmony_ci	if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps,
1477e5b75505Sopenharmony_ci			sizeof(devcaps)) < 0) {
1478e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s",
1479e5b75505Sopenharmony_ci			   strerror(errno));
1480e5b75505Sopenharmony_ci		return -1;
1481e5b75505Sopenharmony_ci	}
1482e5b75505Sopenharmony_ci
1483e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x",
1484e5b75505Sopenharmony_ci		   __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps);
1485e5b75505Sopenharmony_ci
1486e5b75505Sopenharmony_ci	if (devcaps.dc_drivercaps & IEEE80211_C_WPA1)
1487e5b75505Sopenharmony_ci		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1488e5b75505Sopenharmony_ci			WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1489e5b75505Sopenharmony_ci	if (devcaps.dc_drivercaps & IEEE80211_C_WPA2)
1490e5b75505Sopenharmony_ci		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1491e5b75505Sopenharmony_ci			WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1492e5b75505Sopenharmony_ci
1493e5b75505Sopenharmony_ci	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP)
1494e5b75505Sopenharmony_ci		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
1495e5b75505Sopenharmony_ci			WPA_DRIVER_CAPA_ENC_WEP104;
1496e5b75505Sopenharmony_ci	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP)
1497e5b75505Sopenharmony_ci		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1498e5b75505Sopenharmony_ci	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM)
1499e5b75505Sopenharmony_ci		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1500e5b75505Sopenharmony_ci
1501e5b75505Sopenharmony_ci	if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP)
1502e5b75505Sopenharmony_ci		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
1503e5b75505Sopenharmony_ci#undef IEEE80211_CIPHER_WEP
1504e5b75505Sopenharmony_ci#undef IEEE80211_CIPHER_TKIP
1505e5b75505Sopenharmony_ci#undef IEEE80211_CIPHER_AES_CCM
1506e5b75505Sopenharmony_ci#undef IEEE80211_CRYPTO_WEP
1507e5b75505Sopenharmony_ci#undef IEEE80211_CRYPTO_TKIP
1508e5b75505Sopenharmony_ci#undef IEEE80211_CRYPTO_AES_CCM
1509e5b75505Sopenharmony_ci#undef IEEE80211_C_HOSTAP
1510e5b75505Sopenharmony_ci#undef IEEE80211_C_WPA1
1511e5b75505Sopenharmony_ci#undef IEEE80211_C_WPA2
1512e5b75505Sopenharmony_ci#else /* IEEE80211_IOC_DEVCAPS */
1513e5b75505Sopenharmony_ci	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
1514e5b75505Sopenharmony_ci	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1515e5b75505Sopenharmony_ci		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1516e5b75505Sopenharmony_ci		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1517e5b75505Sopenharmony_ci		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1518e5b75505Sopenharmony_ci	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
1519e5b75505Sopenharmony_ci		WPA_DRIVER_CAPA_ENC_WEP104 |
1520e5b75505Sopenharmony_ci		WPA_DRIVER_CAPA_ENC_TKIP |
1521e5b75505Sopenharmony_ci		WPA_DRIVER_CAPA_ENC_CCMP;
1522e5b75505Sopenharmony_ci	drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
1523e5b75505Sopenharmony_ci#endif /* IEEE80211_IOC_DEVCAPS */
1524e5b75505Sopenharmony_ci#ifdef IEEE80211_IOC_SCAN_MAX_SSID
1525e5b75505Sopenharmony_ci	drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID;
1526e5b75505Sopenharmony_ci#else /* IEEE80211_IOC_SCAN_MAX_SSID */
1527e5b75505Sopenharmony_ci	drv->capa.max_scan_ssids = 1;
1528e5b75505Sopenharmony_ci#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
1529e5b75505Sopenharmony_ci	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
1530e5b75505Sopenharmony_ci		WPA_DRIVER_AUTH_SHARED |
1531e5b75505Sopenharmony_ci		WPA_DRIVER_AUTH_LEAP;
1532e5b75505Sopenharmony_ci	return 0;
1533e5b75505Sopenharmony_ci}
1534e5b75505Sopenharmony_ci
1535e5b75505Sopenharmony_cistatic enum ieee80211_opmode
1536e5b75505Sopenharmony_ciget80211opmode(struct bsd_driver_data *drv)
1537e5b75505Sopenharmony_ci{
1538e5b75505Sopenharmony_ci	struct ifmediareq ifmr;
1539e5b75505Sopenharmony_ci
1540e5b75505Sopenharmony_ci	(void) memset(&ifmr, 0, sizeof(ifmr));
1541e5b75505Sopenharmony_ci	(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
1542e5b75505Sopenharmony_ci
1543e5b75505Sopenharmony_ci	if (ioctl(drv->global->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1544e5b75505Sopenharmony_ci		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
1545e5b75505Sopenharmony_ci			if (ifmr.ifm_current & IFM_FLAG0)
1546e5b75505Sopenharmony_ci				return IEEE80211_M_AHDEMO;
1547e5b75505Sopenharmony_ci			else
1548e5b75505Sopenharmony_ci				return IEEE80211_M_IBSS;
1549e5b75505Sopenharmony_ci		}
1550e5b75505Sopenharmony_ci		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1551e5b75505Sopenharmony_ci			return IEEE80211_M_HOSTAP;
1552e5b75505Sopenharmony_ci		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1553e5b75505Sopenharmony_ci			return IEEE80211_M_MONITOR;
1554e5b75505Sopenharmony_ci#ifdef IEEE80211_M_MBSS
1555e5b75505Sopenharmony_ci		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
1556e5b75505Sopenharmony_ci			return IEEE80211_M_MBSS;
1557e5b75505Sopenharmony_ci#endif /* IEEE80211_M_MBSS */
1558e5b75505Sopenharmony_ci	}
1559e5b75505Sopenharmony_ci	return IEEE80211_M_STA;
1560e5b75505Sopenharmony_ci}
1561e5b75505Sopenharmony_ci
1562e5b75505Sopenharmony_cistatic void *
1563e5b75505Sopenharmony_ciwpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
1564e5b75505Sopenharmony_ci{
1565e5b75505Sopenharmony_ci#define	GETPARAM(drv, param, v) \
1566e5b75505Sopenharmony_ci	(((v) = get80211param(drv, param)) != -1)
1567e5b75505Sopenharmony_ci	struct bsd_driver_data *drv;
1568e5b75505Sopenharmony_ci
1569e5b75505Sopenharmony_ci	drv = os_zalloc(sizeof(*drv));
1570e5b75505Sopenharmony_ci	if (drv == NULL)
1571e5b75505Sopenharmony_ci		return NULL;
1572e5b75505Sopenharmony_ci
1573e5b75505Sopenharmony_ci	/*
1574e5b75505Sopenharmony_ci	 * NB: We require the interface name be mappable to an index.
1575e5b75505Sopenharmony_ci	 *     This implies we do not support having wpa_supplicant
1576e5b75505Sopenharmony_ci	 *     wait for an interface to appear.  This seems ok; that
1577e5b75505Sopenharmony_ci	 *     doesn't belong here; it's really the job of devd.
1578e5b75505Sopenharmony_ci	 */
1579e5b75505Sopenharmony_ci	drv->ifindex = if_nametoindex(ifname);
1580e5b75505Sopenharmony_ci	if (drv->ifindex == 0) {
1581e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
1582e5b75505Sopenharmony_ci			   __func__, ifname);
1583e5b75505Sopenharmony_ci		goto fail;
1584e5b75505Sopenharmony_ci	}
1585e5b75505Sopenharmony_ci
1586e5b75505Sopenharmony_ci	drv->ctx = ctx;
1587e5b75505Sopenharmony_ci	drv->global = priv;
1588e5b75505Sopenharmony_ci	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
1589e5b75505Sopenharmony_ci
1590e5b75505Sopenharmony_ci	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
1591e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
1592e5b75505Sopenharmony_ci			__func__, strerror(errno));
1593e5b75505Sopenharmony_ci		goto fail;
1594e5b75505Sopenharmony_ci	}
1595e5b75505Sopenharmony_ci	if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
1596e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
1597e5b75505Sopenharmony_ci			__func__, strerror(errno));
1598e5b75505Sopenharmony_ci		goto fail;
1599e5b75505Sopenharmony_ci	}
1600e5b75505Sopenharmony_ci	if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
1601e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
1602e5b75505Sopenharmony_ci			__func__, strerror(errno));
1603e5b75505Sopenharmony_ci		goto fail;
1604e5b75505Sopenharmony_ci	}
1605e5b75505Sopenharmony_ci
1606e5b75505Sopenharmony_ci	if (wpa_driver_bsd_capa(drv))
1607e5b75505Sopenharmony_ci		goto fail;
1608e5b75505Sopenharmony_ci
1609e5b75505Sopenharmony_ci	/* Down interface during setup. */
1610e5b75505Sopenharmony_ci	if (bsd_ctrl_iface(drv, 0) < 0)
1611e5b75505Sopenharmony_ci		goto fail;
1612e5b75505Sopenharmony_ci
1613e5b75505Sopenharmony_ci	drv->opmode = get80211opmode(drv);
1614e5b75505Sopenharmony_ci	dl_list_add(&drv->global->ifaces, &drv->list);
1615e5b75505Sopenharmony_ci
1616e5b75505Sopenharmony_ci	return drv;
1617e5b75505Sopenharmony_cifail:
1618e5b75505Sopenharmony_ci	os_free(drv);
1619e5b75505Sopenharmony_ci	return NULL;
1620e5b75505Sopenharmony_ci#undef GETPARAM
1621e5b75505Sopenharmony_ci}
1622e5b75505Sopenharmony_ci
1623e5b75505Sopenharmony_cistatic void
1624e5b75505Sopenharmony_ciwpa_driver_bsd_deinit(void *priv)
1625e5b75505Sopenharmony_ci{
1626e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
1627e5b75505Sopenharmony_ci
1628e5b75505Sopenharmony_ci	if (drv->ifindex != 0 && !drv->if_removed) {
1629e5b75505Sopenharmony_ci		wpa_driver_bsd_set_wpa(drv, 0);
1630e5b75505Sopenharmony_ci
1631e5b75505Sopenharmony_ci		/* NB: mark interface down */
1632e5b75505Sopenharmony_ci		bsd_ctrl_iface(drv, 0);
1633e5b75505Sopenharmony_ci
1634e5b75505Sopenharmony_ci		wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
1635e5b75505Sopenharmony_ci						drv->prev_privacy);
1636e5b75505Sopenharmony_ci
1637e5b75505Sopenharmony_ci		if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)
1638e5b75505Sopenharmony_ci		    < 0)
1639e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
1640e5b75505Sopenharmony_ci				   "%s: failed to restore roaming state",
1641e5b75505Sopenharmony_ci				   __func__);
1642e5b75505Sopenharmony_ci	}
1643e5b75505Sopenharmony_ci
1644e5b75505Sopenharmony_ci	if (drv->sock_xmit != NULL)
1645e5b75505Sopenharmony_ci		l2_packet_deinit(drv->sock_xmit);
1646e5b75505Sopenharmony_ci	dl_list_del(&drv->list);
1647e5b75505Sopenharmony_ci	os_free(drv);
1648e5b75505Sopenharmony_ci}
1649e5b75505Sopenharmony_ci
1650e5b75505Sopenharmony_cistatic int
1651e5b75505Sopenharmony_ciwpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
1652e5b75505Sopenharmony_ci{
1653e5b75505Sopenharmony_ci	struct bsd_driver_data *drv = priv;
1654e5b75505Sopenharmony_ci
1655e5b75505Sopenharmony_ci	os_memcpy(capa, &drv->capa, sizeof(*capa));
1656e5b75505Sopenharmony_ci	return 0;
1657e5b75505Sopenharmony_ci}
1658e5b75505Sopenharmony_ci#endif /* HOSTAPD */
1659e5b75505Sopenharmony_ci
1660e5b75505Sopenharmony_cistatic void *
1661e5b75505Sopenharmony_cibsd_global_init(void *ctx)
1662e5b75505Sopenharmony_ci{
1663e5b75505Sopenharmony_ci	struct bsd_driver_global *global;
1664e5b75505Sopenharmony_ci
1665e5b75505Sopenharmony_ci	global = os_zalloc(sizeof(*global));
1666e5b75505Sopenharmony_ci	if (global == NULL)
1667e5b75505Sopenharmony_ci		return NULL;
1668e5b75505Sopenharmony_ci
1669e5b75505Sopenharmony_ci	global->ctx = ctx;
1670e5b75505Sopenharmony_ci	dl_list_init(&global->ifaces);
1671e5b75505Sopenharmony_ci
1672e5b75505Sopenharmony_ci	global->sock = socket(PF_INET, SOCK_DGRAM, 0);
1673e5b75505Sopenharmony_ci	if (global->sock < 0) {
1674e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
1675e5b75505Sopenharmony_ci			   strerror(errno));
1676e5b75505Sopenharmony_ci		goto fail1;
1677e5b75505Sopenharmony_ci	}
1678e5b75505Sopenharmony_ci
1679e5b75505Sopenharmony_ci	global->route = socket(PF_ROUTE, SOCK_RAW, 0);
1680e5b75505Sopenharmony_ci	if (global->route < 0) {
1681e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
1682e5b75505Sopenharmony_ci			   strerror(errno));
1683e5b75505Sopenharmony_ci		goto fail;
1684e5b75505Sopenharmony_ci	}
1685e5b75505Sopenharmony_ci
1686e5b75505Sopenharmony_ci	global->event_buf_len = rtbuf_len();
1687e5b75505Sopenharmony_ci	global->event_buf = os_malloc(global->event_buf_len);
1688e5b75505Sopenharmony_ci	if (global->event_buf == NULL) {
1689e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
1690e5b75505Sopenharmony_ci		goto fail;
1691e5b75505Sopenharmony_ci	}
1692e5b75505Sopenharmony_ci
1693e5b75505Sopenharmony_ci#ifdef HOSTAPD
1694e5b75505Sopenharmony_ci	eloop_register_read_sock(global->route, bsd_wireless_event_receive,
1695e5b75505Sopenharmony_ci				 NULL, global);
1696e5b75505Sopenharmony_ci
1697e5b75505Sopenharmony_ci#else /* HOSTAPD */
1698e5b75505Sopenharmony_ci	eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
1699e5b75505Sopenharmony_ci				 NULL, global);
1700e5b75505Sopenharmony_ci#endif /* HOSTAPD */
1701e5b75505Sopenharmony_ci
1702e5b75505Sopenharmony_ci	return global;
1703e5b75505Sopenharmony_ci
1704e5b75505Sopenharmony_cifail:
1705e5b75505Sopenharmony_ci	close(global->sock);
1706e5b75505Sopenharmony_cifail1:
1707e5b75505Sopenharmony_ci	os_free(global);
1708e5b75505Sopenharmony_ci	return NULL;
1709e5b75505Sopenharmony_ci}
1710e5b75505Sopenharmony_ci
1711e5b75505Sopenharmony_cistatic void
1712e5b75505Sopenharmony_cibsd_global_deinit(void *priv)
1713e5b75505Sopenharmony_ci{
1714e5b75505Sopenharmony_ci	struct bsd_driver_global *global = priv;
1715e5b75505Sopenharmony_ci
1716e5b75505Sopenharmony_ci	eloop_unregister_read_sock(global->route);
1717e5b75505Sopenharmony_ci	(void) close(global->route);
1718e5b75505Sopenharmony_ci	(void) close(global->sock);
1719e5b75505Sopenharmony_ci	os_free(global);
1720e5b75505Sopenharmony_ci}
1721e5b75505Sopenharmony_ci
1722e5b75505Sopenharmony_ci
1723e5b75505Sopenharmony_ciconst struct wpa_driver_ops wpa_driver_bsd_ops = {
1724e5b75505Sopenharmony_ci	.name			= "bsd",
1725e5b75505Sopenharmony_ci	.desc			= "BSD 802.11 support",
1726e5b75505Sopenharmony_ci	.global_init		= bsd_global_init,
1727e5b75505Sopenharmony_ci	.global_deinit		= bsd_global_deinit,
1728e5b75505Sopenharmony_ci#ifdef HOSTAPD
1729e5b75505Sopenharmony_ci	.hapd_init		= bsd_init,
1730e5b75505Sopenharmony_ci	.hapd_deinit		= bsd_deinit,
1731e5b75505Sopenharmony_ci	.set_privacy		= bsd_set_privacy,
1732e5b75505Sopenharmony_ci	.get_seqnum		= bsd_get_seqnum,
1733e5b75505Sopenharmony_ci	.flush			= bsd_flush,
1734e5b75505Sopenharmony_ci	.read_sta_data		= bsd_read_sta_driver_data,
1735e5b75505Sopenharmony_ci	.sta_disassoc		= bsd_sta_disassoc,
1736e5b75505Sopenharmony_ci	.sta_deauth		= bsd_sta_deauth,
1737e5b75505Sopenharmony_ci	.sta_set_flags		= bsd_set_sta_authorized,
1738e5b75505Sopenharmony_ci	.commit			= bsd_commit,
1739e5b75505Sopenharmony_ci#else /* HOSTAPD */
1740e5b75505Sopenharmony_ci	.init2			= wpa_driver_bsd_init,
1741e5b75505Sopenharmony_ci	.deinit			= wpa_driver_bsd_deinit,
1742e5b75505Sopenharmony_ci	.get_bssid		= wpa_driver_bsd_get_bssid,
1743e5b75505Sopenharmony_ci	.get_ssid		= wpa_driver_bsd_get_ssid,
1744e5b75505Sopenharmony_ci	.set_countermeasures	= wpa_driver_bsd_set_countermeasures,
1745e5b75505Sopenharmony_ci	.scan2			= wpa_driver_bsd_scan,
1746e5b75505Sopenharmony_ci	.get_scan_results2	= wpa_driver_bsd_get_scan_results2,
1747e5b75505Sopenharmony_ci	.deauthenticate		= wpa_driver_bsd_deauthenticate,
1748e5b75505Sopenharmony_ci	.associate		= wpa_driver_bsd_associate,
1749e5b75505Sopenharmony_ci	.get_capa		= wpa_driver_bsd_get_capa,
1750e5b75505Sopenharmony_ci#endif /* HOSTAPD */
1751e5b75505Sopenharmony_ci	.set_freq		= bsd_set_freq,
1752e5b75505Sopenharmony_ci	.set_key		= bsd_set_key,
1753e5b75505Sopenharmony_ci	.set_ieee8021x		= bsd_set_ieee8021x,
1754e5b75505Sopenharmony_ci	.hapd_set_ssid		= bsd_set_ssid,
1755e5b75505Sopenharmony_ci	.hapd_get_ssid		= bsd_get_ssid,
1756e5b75505Sopenharmony_ci	.hapd_send_eapol	= bsd_send_eapol,
1757e5b75505Sopenharmony_ci	.set_generic_elem	= bsd_set_opt_ie,
1758e5b75505Sopenharmony_ci};
1759