xref: /freebsd/contrib/wpa/wpa_supplicant/wpa_priv.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA Supplicant / privileged helper program
339beb93cSSam Leffler  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler #ifdef __linux__
1139beb93cSSam Leffler #include <fcntl.h>
1239beb93cSSam Leffler #endif /* __linux__ */
1339beb93cSSam Leffler #include <sys/un.h>
1439beb93cSSam Leffler #include <sys/stat.h>
1539beb93cSSam Leffler 
1639beb93cSSam Leffler #include "common.h"
1739beb93cSSam Leffler #include "eloop.h"
18e28a4053SRui Paulo #include "common/version.h"
1939beb93cSSam Leffler #include "drivers/driver.h"
2039beb93cSSam Leffler #include "l2_packet/l2_packet.h"
21e28a4053SRui Paulo #include "common/privsep_commands.h"
22e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
2339beb93cSSam Leffler 
2485732ac8SCy Schubert #define WPA_PRIV_MAX_L2 3
2539beb93cSSam Leffler 
2639beb93cSSam Leffler struct wpa_priv_interface {
2739beb93cSSam Leffler 	struct wpa_priv_interface *next;
2839beb93cSSam Leffler 	char *driver_name;
2939beb93cSSam Leffler 	char *ifname;
3039beb93cSSam Leffler 	char *sock_name;
3139beb93cSSam Leffler 	int fd;
3239beb93cSSam Leffler 
33780fb4a2SCy Schubert 	void *ctx;
34780fb4a2SCy Schubert 
35325151a3SRui Paulo 	const struct wpa_driver_ops *driver;
3639beb93cSSam Leffler 	void *drv_priv;
37325151a3SRui Paulo 	void *drv_global_priv;
3839beb93cSSam Leffler 	struct sockaddr_un drv_addr;
3985732ac8SCy Schubert 	socklen_t drv_addr_len;
4039beb93cSSam Leffler 	int wpas_registered;
4139beb93cSSam Leffler 
4285732ac8SCy Schubert 	struct l2_packet_data *l2[WPA_PRIV_MAX_L2];
4385732ac8SCy Schubert 	struct sockaddr_un l2_addr[WPA_PRIV_MAX_L2];
4485732ac8SCy Schubert 	socklen_t l2_addr_len[WPA_PRIV_MAX_L2];
4585732ac8SCy Schubert 	struct wpa_priv_l2 {
4685732ac8SCy Schubert 		struct wpa_priv_interface *parent;
4785732ac8SCy Schubert 		int idx;
4885732ac8SCy Schubert 	} l2_ctx[WPA_PRIV_MAX_L2];
4939beb93cSSam Leffler };
5039beb93cSSam Leffler 
51780fb4a2SCy Schubert struct wpa_priv_global {
52780fb4a2SCy Schubert 	struct wpa_priv_interface *interfaces;
53780fb4a2SCy Schubert };
54780fb4a2SCy Schubert 
5539beb93cSSam Leffler 
wpa_priv_cmd_register(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen)5639beb93cSSam Leffler static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
5785732ac8SCy Schubert 				  struct sockaddr_un *from, socklen_t fromlen)
5839beb93cSSam Leffler {
5985732ac8SCy Schubert 	int i;
6085732ac8SCy Schubert 
6139beb93cSSam Leffler 	if (iface->drv_priv) {
6239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
6339beb93cSSam Leffler 		if (iface->driver->deinit)
6439beb93cSSam Leffler 			iface->driver->deinit(iface->drv_priv);
6539beb93cSSam Leffler 		iface->drv_priv = NULL;
66325151a3SRui Paulo 		if (iface->drv_global_priv) {
67325151a3SRui Paulo 			iface->driver->global_deinit(iface->drv_global_priv);
68325151a3SRui Paulo 			iface->drv_global_priv = NULL;
69325151a3SRui Paulo 		}
7039beb93cSSam Leffler 		iface->wpas_registered = 0;
7139beb93cSSam Leffler 	}
7239beb93cSSam Leffler 
7385732ac8SCy Schubert 	for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
7485732ac8SCy Schubert 		if (iface->l2[i]) {
7585732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
7685732ac8SCy Schubert 				   "Cleaning up forgotten l2_packet instance");
7785732ac8SCy Schubert 			l2_packet_deinit(iface->l2[i]);
7885732ac8SCy Schubert 			iface->l2[i] = NULL;
7985732ac8SCy Schubert 		}
8039beb93cSSam Leffler 	}
8139beb93cSSam Leffler 
82325151a3SRui Paulo 	if (iface->driver->init2) {
83325151a3SRui Paulo 		if (iface->driver->global_init) {
84780fb4a2SCy Schubert 			iface->drv_global_priv =
85780fb4a2SCy Schubert 				iface->driver->global_init(iface->ctx);
86325151a3SRui Paulo 			if (!iface->drv_global_priv) {
87325151a3SRui Paulo 				wpa_printf(MSG_INFO,
88325151a3SRui Paulo 					   "Failed to initialize driver global context");
8939beb93cSSam Leffler 				return;
90325151a3SRui Paulo 			}
91325151a3SRui Paulo 		} else {
92325151a3SRui Paulo 			iface->drv_global_priv = NULL;
93325151a3SRui Paulo 		}
94325151a3SRui Paulo 		iface->drv_priv = iface->driver->init2(iface, iface->ifname,
95325151a3SRui Paulo 						       iface->drv_global_priv);
96325151a3SRui Paulo 	} else if (iface->driver->init) {
9739beb93cSSam Leffler 		iface->drv_priv = iface->driver->init(iface, iface->ifname);
98325151a3SRui Paulo 	} else {
99325151a3SRui Paulo 		return;
100325151a3SRui Paulo 	}
10139beb93cSSam Leffler 	if (iface->drv_priv == NULL) {
10239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to initialize driver wrapper");
10339beb93cSSam Leffler 		return;
10439beb93cSSam Leffler 	}
10539beb93cSSam Leffler 
10639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
10739beb93cSSam Leffler 		   "'%s'", iface->driver_name, iface->ifname);
10839beb93cSSam Leffler 
10985732ac8SCy Schubert 	os_memcpy(&iface->drv_addr, from, fromlen);
11085732ac8SCy Schubert 	iface->drv_addr_len = fromlen;
11139beb93cSSam Leffler 	iface->wpas_registered = 1;
11239beb93cSSam Leffler 
11339beb93cSSam Leffler 	if (iface->driver->set_param &&
11439beb93cSSam Leffler 	    iface->driver->set_param(iface->drv_priv, NULL) < 0) {
11539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Driver interface rejected param");
11639beb93cSSam Leffler 	}
11739beb93cSSam Leffler }
11839beb93cSSam Leffler 
11939beb93cSSam Leffler 
wpa_priv_cmd_unregister(struct wpa_priv_interface * iface,struct sockaddr_un * from)12039beb93cSSam Leffler static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface,
12139beb93cSSam Leffler 				    struct sockaddr_un *from)
12239beb93cSSam Leffler {
12339beb93cSSam Leffler 	if (iface->drv_priv) {
12439beb93cSSam Leffler 		if (iface->driver->deinit)
12539beb93cSSam Leffler 			iface->driver->deinit(iface->drv_priv);
12639beb93cSSam Leffler 		iface->drv_priv = NULL;
127325151a3SRui Paulo 		if (iface->drv_global_priv) {
128325151a3SRui Paulo 			iface->driver->global_deinit(iface->drv_global_priv);
129325151a3SRui Paulo 			iface->drv_global_priv = NULL;
130325151a3SRui Paulo 		}
13139beb93cSSam Leffler 		iface->wpas_registered = 0;
13239beb93cSSam Leffler 	}
13339beb93cSSam Leffler }
13439beb93cSSam Leffler 
13539beb93cSSam Leffler 
wpa_priv_cmd_scan(struct wpa_priv_interface * iface,void * buf,size_t len)13639beb93cSSam Leffler static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
13785732ac8SCy Schubert 			      void *buf, size_t len)
13839beb93cSSam Leffler {
139e28a4053SRui Paulo 	struct wpa_driver_scan_params params;
14085732ac8SCy Schubert 	struct privsep_cmd_scan *scan;
14185732ac8SCy Schubert 	unsigned int i;
14285732ac8SCy Schubert 	int freqs[PRIVSEP_MAX_SCAN_FREQS + 1];
143e28a4053SRui Paulo 
14439beb93cSSam Leffler 	if (iface->drv_priv == NULL)
14539beb93cSSam Leffler 		return;
14639beb93cSSam Leffler 
14785732ac8SCy Schubert 	if (len < sizeof(*scan)) {
14885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "Invalid scan request");
14985732ac8SCy Schubert 		return;
15085732ac8SCy Schubert 	}
15185732ac8SCy Schubert 
15285732ac8SCy Schubert 	scan = buf;
15385732ac8SCy Schubert 
154e28a4053SRui Paulo 	os_memset(&params, 0, sizeof(params));
15585732ac8SCy Schubert 	if (scan->num_ssids > WPAS_MAX_SCAN_SSIDS) {
15685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "Invalid scan request (num_ssids)");
15785732ac8SCy Schubert 		return;
15885732ac8SCy Schubert 	}
15985732ac8SCy Schubert 	params.num_ssids = scan->num_ssids;
16085732ac8SCy Schubert 	for (i = 0; i < scan->num_ssids; i++) {
16185732ac8SCy Schubert 		params.ssids[i].ssid = scan->ssids[i];
16285732ac8SCy Schubert 		params.ssids[i].ssid_len = scan->ssid_lens[i];
16385732ac8SCy Schubert 	}
16485732ac8SCy Schubert 
16585732ac8SCy Schubert 	if (scan->num_freqs > PRIVSEP_MAX_SCAN_FREQS) {
16685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "Invalid scan request (num_freqs)");
16785732ac8SCy Schubert 		return;
16885732ac8SCy Schubert 	}
16985732ac8SCy Schubert 	if (scan->num_freqs) {
17085732ac8SCy Schubert 		for (i = 0; i < scan->num_freqs; i++)
17185732ac8SCy Schubert 			freqs[i] = scan->freqs[i];
17285732ac8SCy Schubert 		freqs[i] = 0;
17385732ac8SCy Schubert 		params.freqs = freqs;
174e28a4053SRui Paulo 	}
175e28a4053SRui Paulo 
176e28a4053SRui Paulo 	if (iface->driver->scan2)
177e28a4053SRui Paulo 		iface->driver->scan2(iface->drv_priv, &params);
17839beb93cSSam Leffler }
17939beb93cSSam Leffler 
18039beb93cSSam Leffler 
wpa_priv_get_scan_results2(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen)18139beb93cSSam Leffler static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
18285732ac8SCy Schubert 				       struct sockaddr_un *from,
18385732ac8SCy Schubert 				       socklen_t fromlen)
18439beb93cSSam Leffler {
18539beb93cSSam Leffler 	struct wpa_scan_results *res;
18639beb93cSSam Leffler 	u8 *buf = NULL, *pos, *end;
18739beb93cSSam Leffler 	int val;
18839beb93cSSam Leffler 	size_t i;
18939beb93cSSam Leffler 
190*a90b9d01SCy Schubert 	if (iface->driver->get_scan_results)
191*a90b9d01SCy Schubert 		res = iface->driver->get_scan_results(iface->drv_priv, NULL);
192*a90b9d01SCy Schubert 	else
19339beb93cSSam Leffler 		res = iface->driver->get_scan_results2(iface->drv_priv);
19439beb93cSSam Leffler 	if (res == NULL)
19539beb93cSSam Leffler 		goto fail;
19639beb93cSSam Leffler 
19739beb93cSSam Leffler 	buf = os_malloc(60000);
19839beb93cSSam Leffler 	if (buf == NULL)
19939beb93cSSam Leffler 		goto fail;
20039beb93cSSam Leffler 	pos = buf;
20139beb93cSSam Leffler 	end = buf + 60000;
20239beb93cSSam Leffler 	val = res->num;
20339beb93cSSam Leffler 	os_memcpy(pos, &val, sizeof(int));
20439beb93cSSam Leffler 	pos += sizeof(int);
20539beb93cSSam Leffler 
20639beb93cSSam Leffler 	for (i = 0; i < res->num; i++) {
20739beb93cSSam Leffler 		struct wpa_scan_res *r = res->res[i];
20885732ac8SCy Schubert 		val = sizeof(*r) + r->ie_len + r->beacon_ie_len;
20939beb93cSSam Leffler 		if (end - pos < (int) sizeof(int) + val)
21039beb93cSSam Leffler 			break;
21139beb93cSSam Leffler 		os_memcpy(pos, &val, sizeof(int));
21239beb93cSSam Leffler 		pos += sizeof(int);
21339beb93cSSam Leffler 		os_memcpy(pos, r, val);
21439beb93cSSam Leffler 		pos += val;
21539beb93cSSam Leffler 	}
21639beb93cSSam Leffler 
21785732ac8SCy Schubert 	sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, fromlen);
21839beb93cSSam Leffler 
21939beb93cSSam Leffler 	os_free(buf);
2203157ba21SRui Paulo 	wpa_scan_results_free(res);
22139beb93cSSam Leffler 	return;
22239beb93cSSam Leffler 
22339beb93cSSam Leffler fail:
22439beb93cSSam Leffler 	os_free(buf);
2253157ba21SRui Paulo 	wpa_scan_results_free(res);
22685732ac8SCy Schubert 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
22739beb93cSSam Leffler }
22839beb93cSSam Leffler 
22939beb93cSSam Leffler 
wpa_priv_cmd_get_scan_results(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen)23039beb93cSSam Leffler static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
23185732ac8SCy Schubert 					  struct sockaddr_un *from,
23285732ac8SCy Schubert 					  socklen_t fromlen)
23339beb93cSSam Leffler {
23439beb93cSSam Leffler 	if (iface->drv_priv == NULL)
23539beb93cSSam Leffler 		return;
23639beb93cSSam Leffler 
237*a90b9d01SCy Schubert 	if (iface->driver->get_scan_results || iface->driver->get_scan_results2)
23885732ac8SCy Schubert 		wpa_priv_get_scan_results2(iface, from, fromlen);
23939beb93cSSam Leffler 	else
24085732ac8SCy Schubert 		sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
24139beb93cSSam Leffler }
24239beb93cSSam Leffler 
24339beb93cSSam Leffler 
wpa_priv_cmd_authenticate(struct wpa_priv_interface * iface,void * buf,size_t len)244325151a3SRui Paulo static void wpa_priv_cmd_authenticate(struct wpa_priv_interface *iface,
245325151a3SRui Paulo 				      void *buf, size_t len)
246325151a3SRui Paulo {
247325151a3SRui Paulo 	struct wpa_driver_auth_params params;
248325151a3SRui Paulo 	struct privsep_cmd_authenticate *auth;
249325151a3SRui Paulo 	int res, i;
250325151a3SRui Paulo 
251325151a3SRui Paulo 	if (iface->drv_priv == NULL || iface->driver->authenticate == NULL)
252325151a3SRui Paulo 		return;
253325151a3SRui Paulo 
254325151a3SRui Paulo 	if (len < sizeof(*auth)) {
255325151a3SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid authentication request");
256325151a3SRui Paulo 		return;
257325151a3SRui Paulo 	}
258325151a3SRui Paulo 
259325151a3SRui Paulo 	auth = buf;
26085732ac8SCy Schubert 	if (sizeof(*auth) + auth->ie_len + auth->auth_data_len > len) {
261325151a3SRui Paulo 		wpa_printf(MSG_DEBUG, "Authentication request overflow");
262325151a3SRui Paulo 		return;
263325151a3SRui Paulo 	}
264325151a3SRui Paulo 
265325151a3SRui Paulo 	os_memset(&params, 0, sizeof(params));
266325151a3SRui Paulo 	params.freq = auth->freq;
267325151a3SRui Paulo 	params.bssid = auth->bssid;
268325151a3SRui Paulo 	params.ssid = auth->ssid;
269325151a3SRui Paulo 	if (auth->ssid_len > SSID_MAX_LEN)
270325151a3SRui Paulo 		return;
271325151a3SRui Paulo 	params.ssid_len = auth->ssid_len;
272325151a3SRui Paulo 	params.auth_alg = auth->auth_alg;
273325151a3SRui Paulo 	for (i = 0; i < 4; i++) {
274325151a3SRui Paulo 		if (auth->wep_key_len[i]) {
275325151a3SRui Paulo 			params.wep_key[i] = auth->wep_key[i];
276325151a3SRui Paulo 			params.wep_key_len[i] = auth->wep_key_len[i];
277325151a3SRui Paulo 		}
278325151a3SRui Paulo 	}
279325151a3SRui Paulo 	params.wep_tx_keyidx = auth->wep_tx_keyidx;
280325151a3SRui Paulo 	params.local_state_change = auth->local_state_change;
281325151a3SRui Paulo 	params.p2p = auth->p2p;
282325151a3SRui Paulo 	if (auth->ie_len) {
283325151a3SRui Paulo 		params.ie = (u8 *) (auth + 1);
284325151a3SRui Paulo 		params.ie_len = auth->ie_len;
285325151a3SRui Paulo 	}
28685732ac8SCy Schubert 	if (auth->auth_data_len) {
28785732ac8SCy Schubert 		params.auth_data = ((u8 *) (auth + 1)) + auth->ie_len;
28885732ac8SCy Schubert 		params.auth_data_len = auth->auth_data_len;
289325151a3SRui Paulo 	}
290325151a3SRui Paulo 
291325151a3SRui Paulo 	res = iface->driver->authenticate(iface->drv_priv, &params);
292325151a3SRui Paulo 	wpa_printf(MSG_DEBUG, "drv->authenticate: res=%d", res);
293325151a3SRui Paulo }
294325151a3SRui Paulo 
295325151a3SRui Paulo 
wpa_priv_cmd_associate(struct wpa_priv_interface * iface,void * buf,size_t len)29639beb93cSSam Leffler static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface,
29739beb93cSSam Leffler 				   void *buf, size_t len)
29839beb93cSSam Leffler {
29939beb93cSSam Leffler 	struct wpa_driver_associate_params params;
30039beb93cSSam Leffler 	struct privsep_cmd_associate *assoc;
30139beb93cSSam Leffler 	u8 *bssid;
30239beb93cSSam Leffler 	int res;
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 	if (iface->drv_priv == NULL || iface->driver->associate == NULL)
30539beb93cSSam Leffler 		return;
30639beb93cSSam Leffler 
30739beb93cSSam Leffler 	if (len < sizeof(*assoc)) {
30839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Invalid association request");
30939beb93cSSam Leffler 		return;
31039beb93cSSam Leffler 	}
31139beb93cSSam Leffler 
31239beb93cSSam Leffler 	assoc = buf;
31339beb93cSSam Leffler 	if (sizeof(*assoc) + assoc->wpa_ie_len > len) {
31439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Association request overflow");
31539beb93cSSam Leffler 		return;
31639beb93cSSam Leffler 	}
31739beb93cSSam Leffler 
31839beb93cSSam Leffler 	os_memset(&params, 0, sizeof(params));
31939beb93cSSam Leffler 	bssid = assoc->bssid;
32039beb93cSSam Leffler 	if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5])
32139beb93cSSam Leffler 		params.bssid = bssid;
32239beb93cSSam Leffler 	params.ssid = assoc->ssid;
323325151a3SRui Paulo 	if (assoc->ssid_len > SSID_MAX_LEN)
32439beb93cSSam Leffler 		return;
32539beb93cSSam Leffler 	params.ssid_len = assoc->ssid_len;
3265b9c547cSRui Paulo 	params.freq.mode = assoc->hwmode;
3275b9c547cSRui Paulo 	params.freq.freq = assoc->freq;
3285b9c547cSRui Paulo 	params.freq.channel = assoc->channel;
32939beb93cSSam Leffler 	if (assoc->wpa_ie_len) {
33039beb93cSSam Leffler 		params.wpa_ie = (u8 *) (assoc + 1);
33139beb93cSSam Leffler 		params.wpa_ie_len = assoc->wpa_ie_len;
33239beb93cSSam Leffler 	}
33339beb93cSSam Leffler 	params.pairwise_suite = assoc->pairwise_suite;
33439beb93cSSam Leffler 	params.group_suite = assoc->group_suite;
33539beb93cSSam Leffler 	params.key_mgmt_suite = assoc->key_mgmt_suite;
33639beb93cSSam Leffler 	params.auth_alg = assoc->auth_alg;
33739beb93cSSam Leffler 	params.mode = assoc->mode;
33839beb93cSSam Leffler 
33939beb93cSSam Leffler 	res = iface->driver->associate(iface->drv_priv, &params);
34039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "drv->associate: res=%d", res);
34139beb93cSSam Leffler }
34239beb93cSSam Leffler 
34339beb93cSSam Leffler 
wpa_priv_cmd_get_bssid(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen)34439beb93cSSam Leffler static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
34585732ac8SCy Schubert 				   struct sockaddr_un *from, socklen_t fromlen)
34639beb93cSSam Leffler {
34739beb93cSSam Leffler 	u8 bssid[ETH_ALEN];
34839beb93cSSam Leffler 
34939beb93cSSam Leffler 	if (iface->drv_priv == NULL)
35039beb93cSSam Leffler 		goto fail;
35139beb93cSSam Leffler 
35239beb93cSSam Leffler 	if (iface->driver->get_bssid == NULL ||
35339beb93cSSam Leffler 	    iface->driver->get_bssid(iface->drv_priv, bssid) < 0)
35439beb93cSSam Leffler 		goto fail;
35539beb93cSSam Leffler 
35639beb93cSSam Leffler 	sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
35785732ac8SCy Schubert 	       fromlen);
35839beb93cSSam Leffler 	return;
35939beb93cSSam Leffler 
36039beb93cSSam Leffler fail:
36185732ac8SCy Schubert 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
36239beb93cSSam Leffler }
36339beb93cSSam Leffler 
36439beb93cSSam Leffler 
wpa_priv_cmd_get_ssid(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen)36539beb93cSSam Leffler static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
36685732ac8SCy Schubert 				  struct sockaddr_un *from, socklen_t fromlen)
36739beb93cSSam Leffler {
368325151a3SRui Paulo 	u8 ssid[sizeof(int) + SSID_MAX_LEN];
36939beb93cSSam Leffler 	int res;
37039beb93cSSam Leffler 
37139beb93cSSam Leffler 	if (iface->drv_priv == NULL)
37239beb93cSSam Leffler 		goto fail;
37339beb93cSSam Leffler 
37439beb93cSSam Leffler 	if (iface->driver->get_ssid == NULL)
37539beb93cSSam Leffler 		goto fail;
37639beb93cSSam Leffler 
37785732ac8SCy Schubert 	os_memset(ssid, 0, sizeof(ssid));
37839beb93cSSam Leffler 	res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
379325151a3SRui Paulo 	if (res < 0 || res > SSID_MAX_LEN)
38039beb93cSSam Leffler 		goto fail;
38139beb93cSSam Leffler 	os_memcpy(ssid, &res, sizeof(int));
38239beb93cSSam Leffler 
38339beb93cSSam Leffler 	sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from,
38485732ac8SCy Schubert 	       fromlen);
38539beb93cSSam Leffler 	return;
38639beb93cSSam Leffler 
38739beb93cSSam Leffler fail:
38885732ac8SCy Schubert 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
38939beb93cSSam Leffler }
39039beb93cSSam Leffler 
39139beb93cSSam Leffler 
wpa_priv_cmd_set_key(struct wpa_priv_interface * iface,void * buf,size_t len)39239beb93cSSam Leffler static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
39339beb93cSSam Leffler 				 void *buf, size_t len)
39439beb93cSSam Leffler {
39539beb93cSSam Leffler 	struct privsep_cmd_set_key *params;
39639beb93cSSam Leffler 	int res;
397c1d255d3SCy Schubert 	struct wpa_driver_set_key_params p;
39839beb93cSSam Leffler 
39939beb93cSSam Leffler 	if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
40039beb93cSSam Leffler 		return;
40139beb93cSSam Leffler 
40239beb93cSSam Leffler 	if (len != sizeof(*params)) {
40339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Invalid set_key request");
40439beb93cSSam Leffler 		return;
40539beb93cSSam Leffler 	}
40639beb93cSSam Leffler 
40739beb93cSSam Leffler 	params = buf;
40839beb93cSSam Leffler 
409c1d255d3SCy Schubert 	os_memset(&p, 0, sizeof(p));
410c1d255d3SCy Schubert 	p.ifname = iface->ifname;
411c1d255d3SCy Schubert 	p.alg = params->alg;
412c1d255d3SCy Schubert 	p.addr = params->addr;
413c1d255d3SCy Schubert 	p.key_idx = params->key_idx;
414c1d255d3SCy Schubert 	p.set_tx = params->set_tx;
415c1d255d3SCy Schubert 	p.seq = params->seq_len ? params->seq : NULL;
416c1d255d3SCy Schubert 	p.seq_len = params->seq_len;
417c1d255d3SCy Schubert 	p.key = params->key_len ? params->key : NULL;
418c1d255d3SCy Schubert 	p.key_len = params->key_len;
419c1d255d3SCy Schubert 	p.key_flag = params->key_flag;
420*a90b9d01SCy Schubert 	p.link_id = -1;
421c1d255d3SCy Schubert 
422c1d255d3SCy Schubert 	res = iface->driver->set_key(iface->drv_priv, &p);
42339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
42439beb93cSSam Leffler }
42539beb93cSSam Leffler 
42639beb93cSSam Leffler 
wpa_priv_cmd_get_capa(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen)42739beb93cSSam Leffler static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
42885732ac8SCy Schubert 				  struct sockaddr_un *from, socklen_t fromlen)
42939beb93cSSam Leffler {
43039beb93cSSam Leffler 	struct wpa_driver_capa capa;
43139beb93cSSam Leffler 
43239beb93cSSam Leffler 	if (iface->drv_priv == NULL)
43339beb93cSSam Leffler 		goto fail;
43439beb93cSSam Leffler 
43539beb93cSSam Leffler 	if (iface->driver->get_capa == NULL ||
43639beb93cSSam Leffler 	    iface->driver->get_capa(iface->drv_priv, &capa) < 0)
43739beb93cSSam Leffler 		goto fail;
43839beb93cSSam Leffler 
439325151a3SRui Paulo 	/* For now, no support for passing extended_capa pointers */
440325151a3SRui Paulo 	capa.extended_capa = NULL;
441325151a3SRui Paulo 	capa.extended_capa_mask = NULL;
442325151a3SRui Paulo 	capa.extended_capa_len = 0;
44339beb93cSSam Leffler 	sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
44485732ac8SCy Schubert 	       fromlen);
44539beb93cSSam Leffler 	return;
44639beb93cSSam Leffler 
44739beb93cSSam Leffler fail:
44885732ac8SCy Schubert 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
44939beb93cSSam Leffler }
45039beb93cSSam Leffler 
45139beb93cSSam Leffler 
wpa_priv_l2_rx(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)45239beb93cSSam Leffler static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
45339beb93cSSam Leffler 			   size_t len)
45439beb93cSSam Leffler {
45585732ac8SCy Schubert 	struct wpa_priv_l2 *l2_ctx = ctx;
45685732ac8SCy Schubert 	struct wpa_priv_interface *iface = l2_ctx->parent;
45739beb93cSSam Leffler 	struct msghdr msg;
45839beb93cSSam Leffler 	struct iovec io[2];
45939beb93cSSam Leffler 
46039beb93cSSam Leffler 	io[0].iov_base = (u8 *) src_addr;
46139beb93cSSam Leffler 	io[0].iov_len = ETH_ALEN;
46239beb93cSSam Leffler 	io[1].iov_base = (u8 *) buf;
46339beb93cSSam Leffler 	io[1].iov_len = len;
46439beb93cSSam Leffler 
46539beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
46639beb93cSSam Leffler 	msg.msg_iov = io;
46739beb93cSSam Leffler 	msg.msg_iovlen = 2;
46885732ac8SCy Schubert 	msg.msg_name = &iface->l2_addr[l2_ctx->idx];
46985732ac8SCy Schubert 	msg.msg_namelen = iface->l2_addr_len[l2_ctx->idx];
47039beb93cSSam Leffler 
47139beb93cSSam Leffler 	if (sendmsg(iface->fd, &msg, 0) < 0) {
4725b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
47339beb93cSSam Leffler 	}
47439beb93cSSam Leffler }
47539beb93cSSam Leffler 
47639beb93cSSam Leffler 
wpa_priv_allowed_l2_proto(u16 proto)47785732ac8SCy Schubert static int wpa_priv_allowed_l2_proto(u16 proto)
47885732ac8SCy Schubert {
47985732ac8SCy Schubert 	return proto == ETH_P_EAPOL || proto == ETH_P_RSN_PREAUTH ||
48085732ac8SCy Schubert 		proto == ETH_P_80211_ENCAP;
48185732ac8SCy Schubert }
48285732ac8SCy Schubert 
48385732ac8SCy Schubert 
wpa_priv_cmd_l2_register(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen,void * buf,size_t len)48439beb93cSSam Leffler static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
48539beb93cSSam Leffler 				     struct sockaddr_un *from,
48685732ac8SCy Schubert 				     socklen_t fromlen,
48739beb93cSSam Leffler 				     void *buf, size_t len)
48839beb93cSSam Leffler {
48939beb93cSSam Leffler 	int *reg_cmd = buf;
49039beb93cSSam Leffler 	u8 own_addr[ETH_ALEN];
49139beb93cSSam Leffler 	int res;
49239beb93cSSam Leffler 	u16 proto;
49385732ac8SCy Schubert 	int idx;
49439beb93cSSam Leffler 
49539beb93cSSam Leffler 	if (len != 2 * sizeof(int)) {
49639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
49739beb93cSSam Leffler 			   (unsigned long) len);
49839beb93cSSam Leffler 		return;
49939beb93cSSam Leffler 	}
50039beb93cSSam Leffler 
50139beb93cSSam Leffler 	proto = reg_cmd[0];
50285732ac8SCy Schubert 	if (!wpa_priv_allowed_l2_proto(proto)) {
50339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
50439beb93cSSam Leffler 			   "ethertype 0x%x", proto);
50539beb93cSSam Leffler 		return;
50639beb93cSSam Leffler 	}
50739beb93cSSam Leffler 
50885732ac8SCy Schubert 	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
50985732ac8SCy Schubert 		if (!iface->l2[idx])
51085732ac8SCy Schubert 			break;
51185732ac8SCy Schubert 	}
51285732ac8SCy Schubert 	if (idx == WPA_PRIV_MAX_L2) {
51385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "No free l2_packet connection found");
51485732ac8SCy Schubert 		return;
51539beb93cSSam Leffler 	}
51639beb93cSSam Leffler 
51785732ac8SCy Schubert 	os_memcpy(&iface->l2_addr[idx], from, fromlen);
51885732ac8SCy Schubert 	iface->l2_addr_len[idx] = fromlen;
51939beb93cSSam Leffler 
52085732ac8SCy Schubert 	iface->l2_ctx[idx].idx = idx;
52185732ac8SCy Schubert 	iface->l2_ctx[idx].parent = iface;
52285732ac8SCy Schubert 	iface->l2[idx] = l2_packet_init(iface->ifname, NULL, proto,
52385732ac8SCy Schubert 					wpa_priv_l2_rx, &iface->l2_ctx[idx],
52485732ac8SCy Schubert 					reg_cmd[1]);
52585732ac8SCy Schubert 	if (!iface->l2[idx]) {
52639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
52739beb93cSSam Leffler 			   "instance for protocol %d", proto);
52839beb93cSSam Leffler 		return;
52939beb93cSSam Leffler 	}
53039beb93cSSam Leffler 
53185732ac8SCy Schubert 	if (l2_packet_get_own_addr(iface->l2[idx], own_addr) < 0) {
53239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to get own address from "
53339beb93cSSam Leffler 			   "l2_packet");
53485732ac8SCy Schubert 		l2_packet_deinit(iface->l2[idx]);
53585732ac8SCy Schubert 		iface->l2[idx] = NULL;
53639beb93cSSam Leffler 		return;
53739beb93cSSam Leffler 	}
53839beb93cSSam Leffler 
53939beb93cSSam Leffler 	res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
54085732ac8SCy Schubert 		     (struct sockaddr *) from, fromlen);
54185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "L2 registration[idx=%d]: res=%d", idx, res);
54239beb93cSSam Leffler }
54339beb93cSSam Leffler 
54439beb93cSSam Leffler 
wpa_priv_cmd_l2_unregister(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen)54539beb93cSSam Leffler static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
54685732ac8SCy Schubert 				       struct sockaddr_un *from,
54785732ac8SCy Schubert 				       socklen_t fromlen)
54839beb93cSSam Leffler {
54985732ac8SCy Schubert 	int idx;
55085732ac8SCy Schubert 
55185732ac8SCy Schubert 	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
55285732ac8SCy Schubert 		if (iface->l2_addr_len[idx] == fromlen &&
55385732ac8SCy Schubert 		    os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
55485732ac8SCy Schubert 			break;
55585732ac8SCy Schubert 	}
55685732ac8SCy Schubert 	if (idx == WPA_PRIV_MAX_L2) {
55785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
55885732ac8SCy Schubert 			   "No registered l2_packet socket found for unregister request");
55985732ac8SCy Schubert 		return;
56085732ac8SCy Schubert 	}
56185732ac8SCy Schubert 
56285732ac8SCy Schubert 	if (iface->l2[idx]) {
56385732ac8SCy Schubert 		l2_packet_deinit(iface->l2[idx]);
56485732ac8SCy Schubert 		iface->l2[idx] = NULL;
56539beb93cSSam Leffler 	}
56639beb93cSSam Leffler }
56739beb93cSSam Leffler 
56839beb93cSSam Leffler 
wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface * iface,struct sockaddr_un * from)56939beb93cSSam Leffler static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
57039beb93cSSam Leffler 					      struct sockaddr_un *from)
57139beb93cSSam Leffler {
57285732ac8SCy Schubert 	int idx;
57385732ac8SCy Schubert 
57485732ac8SCy Schubert 	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
57585732ac8SCy Schubert 		if (iface->l2[idx])
57685732ac8SCy Schubert 			l2_packet_notify_auth_start(iface->l2[idx]);
57785732ac8SCy Schubert 	}
57839beb93cSSam Leffler }
57939beb93cSSam Leffler 
58039beb93cSSam Leffler 
wpa_priv_cmd_l2_send(struct wpa_priv_interface * iface,struct sockaddr_un * from,socklen_t fromlen,void * buf,size_t len)58139beb93cSSam Leffler static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
58285732ac8SCy Schubert 				 struct sockaddr_un *from, socklen_t fromlen,
58339beb93cSSam Leffler 				 void *buf, size_t len)
58439beb93cSSam Leffler {
58539beb93cSSam Leffler 	u8 *dst_addr;
58639beb93cSSam Leffler 	u16 proto;
58739beb93cSSam Leffler 	int res;
58885732ac8SCy Schubert 	int idx;
58939beb93cSSam Leffler 
59085732ac8SCy Schubert 	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
59185732ac8SCy Schubert 		if (iface->l2_addr_len[idx] == fromlen &&
59285732ac8SCy Schubert 		    os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
59385732ac8SCy Schubert 			break;
59485732ac8SCy Schubert 	}
59585732ac8SCy Schubert 	if (idx == WPA_PRIV_MAX_L2) {
59685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
59785732ac8SCy Schubert 			   "No registered l2_packet socket found for send request");
59885732ac8SCy Schubert 		return;
59985732ac8SCy Schubert 	}
60085732ac8SCy Schubert 
60185732ac8SCy Schubert 	if (iface->l2[idx] == NULL)
60239beb93cSSam Leffler 		return;
60339beb93cSSam Leffler 
60439beb93cSSam Leffler 	if (len < ETH_ALEN + 2) {
60539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Too short L2 send packet (len=%lu)",
60639beb93cSSam Leffler 			   (unsigned long) len);
60739beb93cSSam Leffler 		return;
60839beb93cSSam Leffler 	}
60939beb93cSSam Leffler 
61039beb93cSSam Leffler 	dst_addr = buf;
611c1d255d3SCy Schubert 	os_memcpy(&proto, (char *) buf + ETH_ALEN, 2);
61239beb93cSSam Leffler 
61385732ac8SCy Schubert 	if (!wpa_priv_allowed_l2_proto(proto)) {
61439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
61539beb93cSSam Leffler 			   "0x%x", proto);
61639beb93cSSam Leffler 		return;
61739beb93cSSam Leffler 	}
61839beb93cSSam Leffler 
61985732ac8SCy Schubert 	res = l2_packet_send(iface->l2[idx], dst_addr, proto,
620c1d255d3SCy Schubert 			     (unsigned char *) buf + ETH_ALEN + 2,
621c1d255d3SCy Schubert 			     len - ETH_ALEN - 2);
62285732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
62339beb93cSSam Leffler }
62439beb93cSSam Leffler 
62539beb93cSSam Leffler 
wpa_priv_cmd_set_country(struct wpa_priv_interface * iface,char * buf)62639beb93cSSam Leffler static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface,
62739beb93cSSam Leffler 				     char *buf)
62839beb93cSSam Leffler {
62939beb93cSSam Leffler 	if (iface->drv_priv == NULL || iface->driver->set_country == NULL ||
63039beb93cSSam Leffler 	    *buf == '\0')
63139beb93cSSam Leffler 		return;
63239beb93cSSam Leffler 
63339beb93cSSam Leffler 	iface->driver->set_country(iface->drv_priv, buf);
63439beb93cSSam Leffler }
63539beb93cSSam Leffler 
63639beb93cSSam Leffler 
wpa_priv_receive(int sock,void * eloop_ctx,void * sock_ctx)63739beb93cSSam Leffler static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
63839beb93cSSam Leffler {
63939beb93cSSam Leffler 	struct wpa_priv_interface *iface = eloop_ctx;
64039beb93cSSam Leffler 	char buf[2000], *pos;
64139beb93cSSam Leffler 	void *cmd_buf;
64239beb93cSSam Leffler 	size_t cmd_len;
64339beb93cSSam Leffler 	int res, cmd;
64439beb93cSSam Leffler 	struct sockaddr_un from;
64539beb93cSSam Leffler 	socklen_t fromlen = sizeof(from);
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
64839beb93cSSam Leffler 		       &fromlen);
64939beb93cSSam Leffler 	if (res < 0) {
6505b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "recvfrom: %s", strerror(errno));
65139beb93cSSam Leffler 		return;
65239beb93cSSam Leffler 	}
65339beb93cSSam Leffler 
65439beb93cSSam Leffler 	if (res < (int) sizeof(int)) {
65539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Too short command (len=%d)", res);
65639beb93cSSam Leffler 		return;
65739beb93cSSam Leffler 	}
65839beb93cSSam Leffler 
65939beb93cSSam Leffler 	os_memcpy(&cmd, buf, sizeof(int));
66039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Command %d for interface %s",
66139beb93cSSam Leffler 		   cmd, iface->ifname);
66239beb93cSSam Leffler 	cmd_buf = &buf[sizeof(int)];
66339beb93cSSam Leffler 	cmd_len = res - sizeof(int);
66439beb93cSSam Leffler 
66539beb93cSSam Leffler 	switch (cmd) {
66639beb93cSSam Leffler 	case PRIVSEP_CMD_REGISTER:
66785732ac8SCy Schubert 		wpa_priv_cmd_register(iface, &from, fromlen);
66839beb93cSSam Leffler 		break;
66939beb93cSSam Leffler 	case PRIVSEP_CMD_UNREGISTER:
67039beb93cSSam Leffler 		wpa_priv_cmd_unregister(iface, &from);
67139beb93cSSam Leffler 		break;
67239beb93cSSam Leffler 	case PRIVSEP_CMD_SCAN:
67339beb93cSSam Leffler 		wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
67439beb93cSSam Leffler 		break;
67539beb93cSSam Leffler 	case PRIVSEP_CMD_GET_SCAN_RESULTS:
67685732ac8SCy Schubert 		wpa_priv_cmd_get_scan_results(iface, &from, fromlen);
67739beb93cSSam Leffler 		break;
67839beb93cSSam Leffler 	case PRIVSEP_CMD_ASSOCIATE:
67939beb93cSSam Leffler 		wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
68039beb93cSSam Leffler 		break;
68139beb93cSSam Leffler 	case PRIVSEP_CMD_GET_BSSID:
68285732ac8SCy Schubert 		wpa_priv_cmd_get_bssid(iface, &from, fromlen);
68339beb93cSSam Leffler 		break;
68439beb93cSSam Leffler 	case PRIVSEP_CMD_GET_SSID:
68585732ac8SCy Schubert 		wpa_priv_cmd_get_ssid(iface, &from, fromlen);
68639beb93cSSam Leffler 		break;
68739beb93cSSam Leffler 	case PRIVSEP_CMD_SET_KEY:
68839beb93cSSam Leffler 		wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
68939beb93cSSam Leffler 		break;
69039beb93cSSam Leffler 	case PRIVSEP_CMD_GET_CAPA:
69185732ac8SCy Schubert 		wpa_priv_cmd_get_capa(iface, &from, fromlen);
69239beb93cSSam Leffler 		break;
69339beb93cSSam Leffler 	case PRIVSEP_CMD_L2_REGISTER:
69485732ac8SCy Schubert 		wpa_priv_cmd_l2_register(iface, &from, fromlen,
69585732ac8SCy Schubert 					 cmd_buf, cmd_len);
69639beb93cSSam Leffler 		break;
69739beb93cSSam Leffler 	case PRIVSEP_CMD_L2_UNREGISTER:
69885732ac8SCy Schubert 		wpa_priv_cmd_l2_unregister(iface, &from, fromlen);
69939beb93cSSam Leffler 		break;
70039beb93cSSam Leffler 	case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
70139beb93cSSam Leffler 		wpa_priv_cmd_l2_notify_auth_start(iface, &from);
70239beb93cSSam Leffler 		break;
70339beb93cSSam Leffler 	case PRIVSEP_CMD_L2_SEND:
70485732ac8SCy Schubert 		wpa_priv_cmd_l2_send(iface, &from, fromlen, cmd_buf, cmd_len);
70539beb93cSSam Leffler 		break;
70639beb93cSSam Leffler 	case PRIVSEP_CMD_SET_COUNTRY:
70739beb93cSSam Leffler 		pos = cmd_buf;
70839beb93cSSam Leffler 		if (pos + cmd_len >= buf + sizeof(buf))
70939beb93cSSam Leffler 			break;
71039beb93cSSam Leffler 		pos[cmd_len] = '\0';
71139beb93cSSam Leffler 		wpa_priv_cmd_set_country(iface, pos);
71239beb93cSSam Leffler 		break;
713325151a3SRui Paulo 	case PRIVSEP_CMD_AUTHENTICATE:
714325151a3SRui Paulo 		wpa_priv_cmd_authenticate(iface, cmd_buf, cmd_len);
715325151a3SRui Paulo 		break;
71639beb93cSSam Leffler 	}
71739beb93cSSam Leffler }
71839beb93cSSam Leffler 
71939beb93cSSam Leffler 
wpa_priv_interface_deinit(struct wpa_priv_interface * iface)72039beb93cSSam Leffler static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
72139beb93cSSam Leffler {
72285732ac8SCy Schubert 	int i;
72385732ac8SCy Schubert 
72485732ac8SCy Schubert 	if (iface->drv_priv) {
72585732ac8SCy Schubert 		if (iface->driver->deinit)
72639beb93cSSam Leffler 			iface->driver->deinit(iface->drv_priv);
72785732ac8SCy Schubert 		if (iface->drv_global_priv)
72885732ac8SCy Schubert 			iface->driver->global_deinit(iface->drv_global_priv);
72985732ac8SCy Schubert 	}
73039beb93cSSam Leffler 
73139beb93cSSam Leffler 	if (iface->fd >= 0) {
73239beb93cSSam Leffler 		eloop_unregister_read_sock(iface->fd);
73339beb93cSSam Leffler 		close(iface->fd);
73439beb93cSSam Leffler 		unlink(iface->sock_name);
73539beb93cSSam Leffler 	}
73639beb93cSSam Leffler 
73785732ac8SCy Schubert 	for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
73885732ac8SCy Schubert 		if (iface->l2[i])
73985732ac8SCy Schubert 			l2_packet_deinit(iface->l2[i]);
74085732ac8SCy Schubert 	}
74139beb93cSSam Leffler 
74239beb93cSSam Leffler 	os_free(iface->ifname);
74339beb93cSSam Leffler 	os_free(iface->driver_name);
74439beb93cSSam Leffler 	os_free(iface->sock_name);
74539beb93cSSam Leffler 	os_free(iface);
74639beb93cSSam Leffler }
74739beb93cSSam Leffler 
74839beb93cSSam Leffler 
74939beb93cSSam Leffler static struct wpa_priv_interface *
wpa_priv_interface_init(void * ctx,const char * dir,const char * params)750780fb4a2SCy Schubert wpa_priv_interface_init(void *ctx, const char *dir, const char *params)
75139beb93cSSam Leffler {
75239beb93cSSam Leffler 	struct wpa_priv_interface *iface;
75339beb93cSSam Leffler 	char *pos;
75439beb93cSSam Leffler 	size_t len;
75539beb93cSSam Leffler 	struct sockaddr_un addr;
75639beb93cSSam Leffler 	int i;
75739beb93cSSam Leffler 
75839beb93cSSam Leffler 	pos = os_strchr(params, ':');
75939beb93cSSam Leffler 	if (pos == NULL)
76039beb93cSSam Leffler 		return NULL;
76139beb93cSSam Leffler 
76239beb93cSSam Leffler 	iface = os_zalloc(sizeof(*iface));
76339beb93cSSam Leffler 	if (iface == NULL)
76439beb93cSSam Leffler 		return NULL;
76539beb93cSSam Leffler 	iface->fd = -1;
766780fb4a2SCy Schubert 	iface->ctx = ctx;
76739beb93cSSam Leffler 
76839beb93cSSam Leffler 	len = pos - params;
7695b9c547cSRui Paulo 	iface->driver_name = dup_binstr(params, len);
77039beb93cSSam Leffler 	if (iface->driver_name == NULL) {
77139beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
77239beb93cSSam Leffler 		return NULL;
77339beb93cSSam Leffler 	}
77439beb93cSSam Leffler 
775e28a4053SRui Paulo 	for (i = 0; wpa_drivers[i]; i++) {
77639beb93cSSam Leffler 		if (os_strcmp(iface->driver_name,
777e28a4053SRui Paulo 			      wpa_drivers[i]->name) == 0) {
778e28a4053SRui Paulo 			iface->driver = wpa_drivers[i];
77939beb93cSSam Leffler 			break;
78039beb93cSSam Leffler 		}
78139beb93cSSam Leffler 	}
78239beb93cSSam Leffler 	if (iface->driver == NULL) {
78339beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Unsupported driver '%s'",
78439beb93cSSam Leffler 			   iface->driver_name);
78539beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
78639beb93cSSam Leffler 		return NULL;
78739beb93cSSam Leffler 	}
78839beb93cSSam Leffler 
78939beb93cSSam Leffler 	pos++;
79039beb93cSSam Leffler 	iface->ifname = os_strdup(pos);
79139beb93cSSam Leffler 	if (iface->ifname == NULL) {
79239beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
79339beb93cSSam Leffler 		return NULL;
79439beb93cSSam Leffler 	}
79539beb93cSSam Leffler 
79639beb93cSSam Leffler 	len = os_strlen(dir) + 1 + os_strlen(iface->ifname);
79739beb93cSSam Leffler 	iface->sock_name = os_malloc(len + 1);
79839beb93cSSam Leffler 	if (iface->sock_name == NULL) {
79939beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
80039beb93cSSam Leffler 		return NULL;
80139beb93cSSam Leffler 	}
80239beb93cSSam Leffler 
80339beb93cSSam Leffler 	os_snprintf(iface->sock_name, len + 1, "%s/%s", dir, iface->ifname);
80439beb93cSSam Leffler 	if (os_strlen(iface->sock_name) >= sizeof(addr.sun_path)) {
80539beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
80639beb93cSSam Leffler 		return NULL;
80739beb93cSSam Leffler 	}
80839beb93cSSam Leffler 
80939beb93cSSam Leffler 	iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
81039beb93cSSam Leffler 	if (iface->fd < 0) {
8115b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
81239beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
81339beb93cSSam Leffler 		return NULL;
81439beb93cSSam Leffler 	}
81539beb93cSSam Leffler 
81639beb93cSSam Leffler 	os_memset(&addr, 0, sizeof(addr));
81739beb93cSSam Leffler 	addr.sun_family = AF_UNIX;
81839beb93cSSam Leffler 	os_strlcpy(addr.sun_path, iface->sock_name, sizeof(addr.sun_path));
81939beb93cSSam Leffler 
82039beb93cSSam Leffler 	if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
82139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "bind(PF_UNIX) failed: %s",
82239beb93cSSam Leffler 			   strerror(errno));
82339beb93cSSam Leffler 		if (connect(iface->fd, (struct sockaddr *) &addr,
82439beb93cSSam Leffler 			    sizeof(addr)) < 0) {
82539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Socket exists, but does not "
82639beb93cSSam Leffler 				   "allow connections - assuming it was "
82739beb93cSSam Leffler 				   "leftover from forced program termination");
82839beb93cSSam Leffler 			if (unlink(iface->sock_name) < 0) {
8295b9c547cSRui Paulo 				wpa_printf(MSG_ERROR,
8305b9c547cSRui Paulo 					   "Could not unlink existing ctrl_iface socket '%s': %s",
8315b9c547cSRui Paulo 					   iface->sock_name, strerror(errno));
83239beb93cSSam Leffler 				goto fail;
83339beb93cSSam Leffler 			}
83439beb93cSSam Leffler 			if (bind(iface->fd, (struct sockaddr *) &addr,
83539beb93cSSam Leffler 				 sizeof(addr)) < 0) {
8365b9c547cSRui Paulo 				wpa_printf(MSG_ERROR,
8375b9c547cSRui Paulo 					   "wpa-priv-iface-init: bind(PF_UNIX): %s",
8385b9c547cSRui Paulo 					   strerror(errno));
83939beb93cSSam Leffler 				goto fail;
84039beb93cSSam Leffler 			}
84139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
84239beb93cSSam Leffler 				   "socket '%s'", iface->sock_name);
84339beb93cSSam Leffler 		} else {
84439beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Socket exists and seems to be "
84539beb93cSSam Leffler 				   "in use - cannot override it");
84639beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
84739beb93cSSam Leffler 				   "not used anymore", iface->sock_name);
84839beb93cSSam Leffler 			goto fail;
84939beb93cSSam Leffler 		}
85039beb93cSSam Leffler 	}
85139beb93cSSam Leffler 
85239beb93cSSam Leffler 	if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
8535b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "chmod: %s", strerror(errno));
85439beb93cSSam Leffler 		goto fail;
85539beb93cSSam Leffler 	}
85639beb93cSSam Leffler 
85739beb93cSSam Leffler 	eloop_register_read_sock(iface->fd, wpa_priv_receive, iface, NULL);
85839beb93cSSam Leffler 
85939beb93cSSam Leffler 	return iface;
86039beb93cSSam Leffler 
86139beb93cSSam Leffler fail:
86239beb93cSSam Leffler 	wpa_priv_interface_deinit(iface);
86339beb93cSSam Leffler 	return NULL;
86439beb93cSSam Leffler }
86539beb93cSSam Leffler 
86639beb93cSSam Leffler 
wpa_priv_send_event(struct wpa_priv_interface * iface,int event,const void * data,size_t data_len)86739beb93cSSam Leffler static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event,
86839beb93cSSam Leffler 			       const void *data, size_t data_len)
86939beb93cSSam Leffler {
87039beb93cSSam Leffler 	struct msghdr msg;
87139beb93cSSam Leffler 	struct iovec io[2];
87239beb93cSSam Leffler 
87339beb93cSSam Leffler 	io[0].iov_base = &event;
87439beb93cSSam Leffler 	io[0].iov_len = sizeof(event);
87539beb93cSSam Leffler 	io[1].iov_base = (u8 *) data;
87639beb93cSSam Leffler 	io[1].iov_len = data_len;
87739beb93cSSam Leffler 
87839beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
87939beb93cSSam Leffler 	msg.msg_iov = io;
88039beb93cSSam Leffler 	msg.msg_iovlen = data ? 2 : 1;
88139beb93cSSam Leffler 	msg.msg_name = &iface->drv_addr;
88285732ac8SCy Schubert 	msg.msg_namelen = iface->drv_addr_len;
88339beb93cSSam Leffler 
88439beb93cSSam Leffler 	if (sendmsg(iface->fd, &msg, 0) < 0) {
8855b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
8865b9c547cSRui Paulo 			   strerror(errno));
88739beb93cSSam Leffler 		return -1;
88839beb93cSSam Leffler 	}
88939beb93cSSam Leffler 
89039beb93cSSam Leffler 	return 0;
89139beb93cSSam Leffler }
89239beb93cSSam Leffler 
89339beb93cSSam Leffler 
wpa_priv_send_auth(struct wpa_priv_interface * iface,union wpa_event_data * data)894325151a3SRui Paulo static void wpa_priv_send_auth(struct wpa_priv_interface *iface,
895325151a3SRui Paulo 			       union wpa_event_data *data)
896325151a3SRui Paulo {
897325151a3SRui Paulo 	size_t buflen = sizeof(struct privsep_event_auth) + data->auth.ies_len;
898325151a3SRui Paulo 	struct privsep_event_auth *auth;
899325151a3SRui Paulo 	u8 *buf, *pos;
900325151a3SRui Paulo 
90185732ac8SCy Schubert 	buf = os_zalloc(buflen);
902325151a3SRui Paulo 	if (buf == NULL)
903325151a3SRui Paulo 		return;
904325151a3SRui Paulo 
905325151a3SRui Paulo 	auth = (struct privsep_event_auth *) buf;
906325151a3SRui Paulo 	pos = (u8 *) (auth + 1);
907325151a3SRui Paulo 
908325151a3SRui Paulo 	os_memcpy(auth->peer, data->auth.peer, ETH_ALEN);
909325151a3SRui Paulo 	os_memcpy(auth->bssid, data->auth.bssid, ETH_ALEN);
910325151a3SRui Paulo 	auth->auth_type = data->auth.auth_type;
911325151a3SRui Paulo 	auth->auth_transaction = data->auth.auth_transaction;
912325151a3SRui Paulo 	auth->status_code = data->auth.status_code;
913325151a3SRui Paulo 	if (data->auth.ies) {
914325151a3SRui Paulo 		os_memcpy(pos, data->auth.ies, data->auth.ies_len);
915325151a3SRui Paulo 		auth->ies_len = data->auth.ies_len;
916325151a3SRui Paulo 	}
917325151a3SRui Paulo 
918325151a3SRui Paulo 	wpa_priv_send_event(iface, PRIVSEP_EVENT_AUTH, buf, buflen);
919325151a3SRui Paulo 
920325151a3SRui Paulo 	os_free(buf);
921325151a3SRui Paulo }
922325151a3SRui Paulo 
923325151a3SRui Paulo 
wpa_priv_send_assoc(struct wpa_priv_interface * iface,int event,union wpa_event_data * data)92439beb93cSSam Leffler static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event,
92539beb93cSSam Leffler 				union wpa_event_data *data)
92639beb93cSSam Leffler {
92739beb93cSSam Leffler 	size_t buflen = 3 * sizeof(int);
92839beb93cSSam Leffler 	u8 *buf, *pos;
92939beb93cSSam Leffler 	int len;
93039beb93cSSam Leffler 
93139beb93cSSam Leffler 	if (data) {
93239beb93cSSam Leffler 		buflen += data->assoc_info.req_ies_len +
93339beb93cSSam Leffler 			data->assoc_info.resp_ies_len +
93439beb93cSSam Leffler 			data->assoc_info.beacon_ies_len;
93539beb93cSSam Leffler 	}
93639beb93cSSam Leffler 
93739beb93cSSam Leffler 	buf = os_malloc(buflen);
93839beb93cSSam Leffler 	if (buf == NULL)
93939beb93cSSam Leffler 		return;
94039beb93cSSam Leffler 
94139beb93cSSam Leffler 	pos = buf;
94239beb93cSSam Leffler 
94339beb93cSSam Leffler 	if (data && data->assoc_info.req_ies) {
94439beb93cSSam Leffler 		len = data->assoc_info.req_ies_len;
94539beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
94639beb93cSSam Leffler 		pos += sizeof(int);
94739beb93cSSam Leffler 		os_memcpy(pos, data->assoc_info.req_ies, len);
94839beb93cSSam Leffler 		pos += len;
94939beb93cSSam Leffler 	} else {
95039beb93cSSam Leffler 		len = 0;
95139beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
95239beb93cSSam Leffler 		pos += sizeof(int);
95339beb93cSSam Leffler 	}
95439beb93cSSam Leffler 
95539beb93cSSam Leffler 	if (data && data->assoc_info.resp_ies) {
95639beb93cSSam Leffler 		len = data->assoc_info.resp_ies_len;
95739beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
95839beb93cSSam Leffler 		pos += sizeof(int);
95939beb93cSSam Leffler 		os_memcpy(pos, data->assoc_info.resp_ies, len);
96039beb93cSSam Leffler 		pos += len;
96139beb93cSSam Leffler 	} else {
96239beb93cSSam Leffler 		len = 0;
96339beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
96439beb93cSSam Leffler 		pos += sizeof(int);
96539beb93cSSam Leffler 	}
96639beb93cSSam Leffler 
96739beb93cSSam Leffler 	if (data && data->assoc_info.beacon_ies) {
96839beb93cSSam Leffler 		len = data->assoc_info.beacon_ies_len;
96939beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
97039beb93cSSam Leffler 		pos += sizeof(int);
97139beb93cSSam Leffler 		os_memcpy(pos, data->assoc_info.beacon_ies, len);
97239beb93cSSam Leffler 		pos += len;
97339beb93cSSam Leffler 	} else {
97439beb93cSSam Leffler 		len = 0;
97539beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
97639beb93cSSam Leffler 		pos += sizeof(int);
97739beb93cSSam Leffler 	}
97839beb93cSSam Leffler 
97939beb93cSSam Leffler 	wpa_priv_send_event(iface, event, buf, buflen);
98039beb93cSSam Leffler 
98139beb93cSSam Leffler 	os_free(buf);
98239beb93cSSam Leffler }
98339beb93cSSam Leffler 
98439beb93cSSam Leffler 
wpa_priv_send_interface_status(struct wpa_priv_interface * iface,union wpa_event_data * data)98539beb93cSSam Leffler static void wpa_priv_send_interface_status(struct wpa_priv_interface *iface,
98639beb93cSSam Leffler 					   union wpa_event_data *data)
98739beb93cSSam Leffler {
98839beb93cSSam Leffler 	int ievent;
98939beb93cSSam Leffler 	size_t len, maxlen;
99039beb93cSSam Leffler 	u8 *buf;
99139beb93cSSam Leffler 	char *ifname;
99239beb93cSSam Leffler 
99339beb93cSSam Leffler 	if (data == NULL)
99439beb93cSSam Leffler 		return;
99539beb93cSSam Leffler 
99639beb93cSSam Leffler 	ievent = data->interface_status.ievent;
99739beb93cSSam Leffler 	maxlen = sizeof(data->interface_status.ifname);
99839beb93cSSam Leffler 	ifname = data->interface_status.ifname;
99939beb93cSSam Leffler 	for (len = 0; len < maxlen && ifname[len]; len++)
100039beb93cSSam Leffler 		;
100139beb93cSSam Leffler 
100239beb93cSSam Leffler 	buf = os_malloc(sizeof(int) + len);
100339beb93cSSam Leffler 	if (buf == NULL)
100439beb93cSSam Leffler 		return;
100539beb93cSSam Leffler 
100639beb93cSSam Leffler 	os_memcpy(buf, &ievent, sizeof(int));
100739beb93cSSam Leffler 	os_memcpy(buf + sizeof(int), ifname, len);
100839beb93cSSam Leffler 
100939beb93cSSam Leffler 	wpa_priv_send_event(iface, PRIVSEP_EVENT_INTERFACE_STATUS,
101039beb93cSSam Leffler 			    buf, sizeof(int) + len);
101139beb93cSSam Leffler 
101239beb93cSSam Leffler 	os_free(buf);
101339beb93cSSam Leffler 
101439beb93cSSam Leffler }
101539beb93cSSam Leffler 
101639beb93cSSam Leffler 
wpa_priv_send_ft_response(struct wpa_priv_interface * iface,union wpa_event_data * data)101739beb93cSSam Leffler static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface,
101839beb93cSSam Leffler 				      union wpa_event_data *data)
101939beb93cSSam Leffler {
102039beb93cSSam Leffler 	size_t len;
102139beb93cSSam Leffler 	u8 *buf, *pos;
102239beb93cSSam Leffler 
102339beb93cSSam Leffler 	if (data == NULL || data->ft_ies.ies == NULL)
102439beb93cSSam Leffler 		return;
102539beb93cSSam Leffler 
102639beb93cSSam Leffler 	len = sizeof(int) + ETH_ALEN + data->ft_ies.ies_len;
102739beb93cSSam Leffler 	buf = os_malloc(len);
102839beb93cSSam Leffler 	if (buf == NULL)
102939beb93cSSam Leffler 		return;
103039beb93cSSam Leffler 
103139beb93cSSam Leffler 	pos = buf;
103239beb93cSSam Leffler 	os_memcpy(pos, &data->ft_ies.ft_action, sizeof(int));
103339beb93cSSam Leffler 	pos += sizeof(int);
103439beb93cSSam Leffler 	os_memcpy(pos, data->ft_ies.target_ap, ETH_ALEN);
103539beb93cSSam Leffler 	pos += ETH_ALEN;
103639beb93cSSam Leffler 	os_memcpy(pos, data->ft_ies.ies, data->ft_ies.ies_len);
103739beb93cSSam Leffler 
103839beb93cSSam Leffler 	wpa_priv_send_event(iface, PRIVSEP_EVENT_FT_RESPONSE, buf, len);
103939beb93cSSam Leffler 
104039beb93cSSam Leffler 	os_free(buf);
104139beb93cSSam Leffler 
104239beb93cSSam Leffler }
104339beb93cSSam Leffler 
104439beb93cSSam Leffler 
wpa_supplicant_event(void * ctx,enum wpa_event_type event,union wpa_event_data * data)1045f05cddf9SRui Paulo void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
104639beb93cSSam Leffler 			  union wpa_event_data *data)
104739beb93cSSam Leffler {
104839beb93cSSam Leffler 	struct wpa_priv_interface *iface = ctx;
104939beb93cSSam Leffler 
105039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "%s - event=%d", __func__, event);
105139beb93cSSam Leffler 
105239beb93cSSam Leffler 	if (!iface->wpas_registered) {
105339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Driver event received, but "
105439beb93cSSam Leffler 			   "wpa_supplicant not registered");
105539beb93cSSam Leffler 		return;
105639beb93cSSam Leffler 	}
105739beb93cSSam Leffler 
105839beb93cSSam Leffler 	switch (event) {
105939beb93cSSam Leffler 	case EVENT_ASSOC:
106039beb93cSSam Leffler 		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOC, data);
106139beb93cSSam Leffler 		break;
106239beb93cSSam Leffler 	case EVENT_DISASSOC:
106339beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_DISASSOC, NULL, 0);
106439beb93cSSam Leffler 		break;
106539beb93cSSam Leffler 	case EVENT_ASSOCINFO:
106639beb93cSSam Leffler 		if (data == NULL)
106739beb93cSSam Leffler 			return;
106839beb93cSSam Leffler 		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOCINFO, data);
106939beb93cSSam Leffler 		break;
107039beb93cSSam Leffler 	case EVENT_MICHAEL_MIC_FAILURE:
107139beb93cSSam Leffler 		if (data == NULL)
107239beb93cSSam Leffler 			return;
107339beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
107439beb93cSSam Leffler 				    &data->michael_mic_failure.unicast,
107539beb93cSSam Leffler 				    sizeof(int));
107639beb93cSSam Leffler 		break;
1077325151a3SRui Paulo 	case EVENT_SCAN_STARTED:
1078325151a3SRui Paulo 		wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_STARTED, NULL,
1079325151a3SRui Paulo 				    0);
1080325151a3SRui Paulo 		break;
108139beb93cSSam Leffler 	case EVENT_SCAN_RESULTS:
108239beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_RESULTS, NULL,
108339beb93cSSam Leffler 				    0);
108439beb93cSSam Leffler 		break;
108539beb93cSSam Leffler 	case EVENT_INTERFACE_STATUS:
108639beb93cSSam Leffler 		wpa_priv_send_interface_status(iface, data);
108739beb93cSSam Leffler 		break;
108839beb93cSSam Leffler 	case EVENT_PMKID_CANDIDATE:
108939beb93cSSam Leffler 		if (data == NULL)
109039beb93cSSam Leffler 			return;
109139beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_PMKID_CANDIDATE,
109239beb93cSSam Leffler 				    &data->pmkid_candidate,
109339beb93cSSam Leffler 				    sizeof(struct pmkid_candidate));
109439beb93cSSam Leffler 		break;
109539beb93cSSam Leffler 	case EVENT_FT_RESPONSE:
109639beb93cSSam Leffler 		wpa_priv_send_ft_response(iface, data);
109739beb93cSSam Leffler 		break;
1098325151a3SRui Paulo 	case EVENT_AUTH:
1099325151a3SRui Paulo 		wpa_priv_send_auth(iface, data);
1100325151a3SRui Paulo 		break;
110139beb93cSSam Leffler 	default:
1102325151a3SRui Paulo 		wpa_printf(MSG_DEBUG, "Unsupported driver event %d (%s) - TODO",
1103325151a3SRui Paulo 			   event, event_to_string(event));
110439beb93cSSam Leffler 		break;
110539beb93cSSam Leffler 	}
110639beb93cSSam Leffler }
110739beb93cSSam Leffler 
110839beb93cSSam Leffler 
wpa_supplicant_event_global(void * ctx,enum wpa_event_type event,union wpa_event_data * data)1109780fb4a2SCy Schubert void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
1110780fb4a2SCy Schubert 				 union wpa_event_data *data)
1111780fb4a2SCy Schubert {
1112780fb4a2SCy Schubert 	struct wpa_priv_global *global = ctx;
1113780fb4a2SCy Schubert 	struct wpa_priv_interface *iface;
1114780fb4a2SCy Schubert 
1115780fb4a2SCy Schubert 	if (event != EVENT_INTERFACE_STATUS)
1116780fb4a2SCy Schubert 		return;
1117780fb4a2SCy Schubert 
1118780fb4a2SCy Schubert 	for (iface = global->interfaces; iface; iface = iface->next) {
1119780fb4a2SCy Schubert 		if (os_strcmp(iface->ifname, data->interface_status.ifname) ==
1120780fb4a2SCy Schubert 		    0)
1121780fb4a2SCy Schubert 			break;
1122780fb4a2SCy Schubert 	}
1123780fb4a2SCy Schubert 	if (iface && iface->driver->get_ifindex) {
1124780fb4a2SCy Schubert 		unsigned int ifindex;
1125780fb4a2SCy Schubert 
1126780fb4a2SCy Schubert 		ifindex = iface->driver->get_ifindex(iface->drv_priv);
1127780fb4a2SCy Schubert 		if (ifindex != data->interface_status.ifindex) {
1128780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
1129780fb4a2SCy Schubert 				   "%s: interface status ifindex %d mismatch (%d)",
1130780fb4a2SCy Schubert 				   iface->ifname, ifindex,
1131780fb4a2SCy Schubert 				   data->interface_status.ifindex);
1132780fb4a2SCy Schubert 			return;
1133780fb4a2SCy Schubert 		}
1134780fb4a2SCy Schubert 	}
1135780fb4a2SCy Schubert 	if (iface)
1136780fb4a2SCy Schubert 		wpa_supplicant_event(iface, event, data);
1137780fb4a2SCy Schubert }
1138780fb4a2SCy Schubert 
1139780fb4a2SCy Schubert 
wpa_supplicant_rx_eapol(void * ctx,const u8 * src_addr,const u8 * buf,size_t len,enum frame_encryption encrypted)114039beb93cSSam Leffler void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
1141*a90b9d01SCy Schubert 			     const u8 *buf, size_t len,
1142*a90b9d01SCy Schubert 			     enum frame_encryption encrypted)
114339beb93cSSam Leffler {
114439beb93cSSam Leffler 	struct wpa_priv_interface *iface = ctx;
114539beb93cSSam Leffler 	struct msghdr msg;
114639beb93cSSam Leffler 	struct iovec io[3];
114739beb93cSSam Leffler 	int event = PRIVSEP_EVENT_RX_EAPOL;
114839beb93cSSam Leffler 
114939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "RX EAPOL from driver");
115039beb93cSSam Leffler 	io[0].iov_base = &event;
115139beb93cSSam Leffler 	io[0].iov_len = sizeof(event);
115239beb93cSSam Leffler 	io[1].iov_base = (u8 *) src_addr;
115339beb93cSSam Leffler 	io[1].iov_len = ETH_ALEN;
115439beb93cSSam Leffler 	io[2].iov_base = (u8 *) buf;
115539beb93cSSam Leffler 	io[2].iov_len = len;
115639beb93cSSam Leffler 
115739beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
115839beb93cSSam Leffler 	msg.msg_iov = io;
115939beb93cSSam Leffler 	msg.msg_iovlen = 3;
116039beb93cSSam Leffler 	msg.msg_name = &iface->drv_addr;
116185732ac8SCy Schubert 	msg.msg_namelen = iface->drv_addr_len;
116239beb93cSSam Leffler 
116339beb93cSSam Leffler 	if (sendmsg(iface->fd, &msg, 0) < 0)
11645b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
11655b9c547cSRui Paulo 			   strerror(errno));
116639beb93cSSam Leffler }
116739beb93cSSam Leffler 
116839beb93cSSam Leffler 
wpa_priv_terminate(int sig,void * signal_ctx)1169f05cddf9SRui Paulo static void wpa_priv_terminate(int sig, void *signal_ctx)
117039beb93cSSam Leffler {
117139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "wpa_priv termination requested");
117239beb93cSSam Leffler 	eloop_terminate();
117339beb93cSSam Leffler }
117439beb93cSSam Leffler 
117539beb93cSSam Leffler 
wpa_priv_fd_workaround(void)117639beb93cSSam Leffler static void wpa_priv_fd_workaround(void)
117739beb93cSSam Leffler {
117839beb93cSSam Leffler #ifdef __linux__
117939beb93cSSam Leffler 	int s, i;
118039beb93cSSam Leffler 	/* When started from pcmcia-cs scripts, wpa_supplicant might start with
118139beb93cSSam Leffler 	 * fd 0, 1, and 2 closed. This will cause some issues because many
118239beb93cSSam Leffler 	 * places in wpa_supplicant are still printing out to stdout. As a
118339beb93cSSam Leffler 	 * workaround, make sure that fd's 0, 1, and 2 are not used for other
118439beb93cSSam Leffler 	 * sockets. */
118539beb93cSSam Leffler 	for (i = 0; i < 3; i++) {
118639beb93cSSam Leffler 		s = open("/dev/null", O_RDWR);
118739beb93cSSam Leffler 		if (s > 2) {
118839beb93cSSam Leffler 			close(s);
118939beb93cSSam Leffler 			break;
119039beb93cSSam Leffler 		}
119139beb93cSSam Leffler 	}
119239beb93cSSam Leffler #endif /* __linux__ */
119339beb93cSSam Leffler }
119439beb93cSSam Leffler 
119539beb93cSSam Leffler 
usage(void)119639beb93cSSam Leffler static void usage(void)
119739beb93cSSam Leffler {
1198c1d255d3SCy Schubert 	printf("wpa_priv v%s\n"
119985732ac8SCy Schubert 	       "Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
120039beb93cSSam Leffler 	       "contributors\n"
120139beb93cSSam Leffler 	       "\n"
120239beb93cSSam Leffler 	       "usage:\n"
1203325151a3SRui Paulo 	       "  wpa_priv [-Bdd] [-c<ctrl dir>] [-P<pid file>] "
1204325151a3SRui Paulo 	       "<driver:ifname> \\\n"
1205c1d255d3SCy Schubert 	       "           [driver:ifname ...]\n",
1206c1d255d3SCy Schubert 	       VERSION_STR);
120739beb93cSSam Leffler }
120839beb93cSSam Leffler 
120939beb93cSSam Leffler 
main(int argc,char * argv[])121039beb93cSSam Leffler int main(int argc, char *argv[])
121139beb93cSSam Leffler {
121239beb93cSSam Leffler 	int c, i;
121339beb93cSSam Leffler 	int ret = -1;
121439beb93cSSam Leffler 	char *pid_file = NULL;
121539beb93cSSam Leffler 	int daemonize = 0;
121639beb93cSSam Leffler 	char *ctrl_dir = "/var/run/wpa_priv";
1217780fb4a2SCy Schubert 	struct wpa_priv_global global;
1218780fb4a2SCy Schubert 	struct wpa_priv_interface *iface;
121939beb93cSSam Leffler 
122039beb93cSSam Leffler 	if (os_program_init())
122139beb93cSSam Leffler 		return -1;
122239beb93cSSam Leffler 
122339beb93cSSam Leffler 	wpa_priv_fd_workaround();
122439beb93cSSam Leffler 
1225780fb4a2SCy Schubert 	os_memset(&global, 0, sizeof(global));
1226780fb4a2SCy Schubert 	global.interfaces = NULL;
1227780fb4a2SCy Schubert 
122839beb93cSSam Leffler 	for (;;) {
122939beb93cSSam Leffler 		c = getopt(argc, argv, "Bc:dP:");
123039beb93cSSam Leffler 		if (c < 0)
123139beb93cSSam Leffler 			break;
123239beb93cSSam Leffler 		switch (c) {
123339beb93cSSam Leffler 		case 'B':
123439beb93cSSam Leffler 			daemonize++;
123539beb93cSSam Leffler 			break;
123639beb93cSSam Leffler 		case 'c':
123739beb93cSSam Leffler 			ctrl_dir = optarg;
123839beb93cSSam Leffler 			break;
123939beb93cSSam Leffler 		case 'd':
124039beb93cSSam Leffler 			wpa_debug_level--;
124139beb93cSSam Leffler 			break;
124239beb93cSSam Leffler 		case 'P':
124339beb93cSSam Leffler 			pid_file = os_rel2abs_path(optarg);
124439beb93cSSam Leffler 			break;
124539beb93cSSam Leffler 		default:
124639beb93cSSam Leffler 			usage();
1247325151a3SRui Paulo 			goto out2;
124839beb93cSSam Leffler 		}
124939beb93cSSam Leffler 	}
125039beb93cSSam Leffler 
125139beb93cSSam Leffler 	if (optind >= argc) {
125239beb93cSSam Leffler 		usage();
1253325151a3SRui Paulo 		goto out2;
125439beb93cSSam Leffler 	}
125539beb93cSSam Leffler 
125639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "wpa_priv control directory: '%s'", ctrl_dir);
125739beb93cSSam Leffler 
1258e28a4053SRui Paulo 	if (eloop_init()) {
125939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
1260325151a3SRui Paulo 		goto out2;
126139beb93cSSam Leffler 	}
126239beb93cSSam Leffler 
126339beb93cSSam Leffler 	for (i = optind; i < argc; i++) {
126439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
1265780fb4a2SCy Schubert 		iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]);
126639beb93cSSam Leffler 		if (iface == NULL)
126739beb93cSSam Leffler 			goto out;
1268780fb4a2SCy Schubert 		iface->next = global.interfaces;
1269780fb4a2SCy Schubert 		global.interfaces = iface;
127039beb93cSSam Leffler 	}
127139beb93cSSam Leffler 
1272780fb4a2SCy Schubert 	if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
127339beb93cSSam Leffler 		goto out;
127439beb93cSSam Leffler 
127539beb93cSSam Leffler 	eloop_register_signal_terminate(wpa_priv_terminate, NULL);
127639beb93cSSam Leffler 	eloop_run();
127739beb93cSSam Leffler 
127839beb93cSSam Leffler 	ret = 0;
127939beb93cSSam Leffler 
128039beb93cSSam Leffler out:
1281780fb4a2SCy Schubert 	iface = global.interfaces;
128239beb93cSSam Leffler 	while (iface) {
128339beb93cSSam Leffler 		struct wpa_priv_interface *prev = iface;
128439beb93cSSam Leffler 		iface = iface->next;
128539beb93cSSam Leffler 		wpa_priv_interface_deinit(prev);
128639beb93cSSam Leffler 	}
128739beb93cSSam Leffler 
128839beb93cSSam Leffler 	eloop_destroy();
128939beb93cSSam Leffler 
1290325151a3SRui Paulo out2:
1291325151a3SRui Paulo 	if (daemonize)
129239beb93cSSam Leffler 		os_daemonize_terminate(pid_file);
129339beb93cSSam Leffler 	os_free(pid_file);
129439beb93cSSam Leffler 	os_program_deinit();
129539beb93cSSam Leffler 
129639beb93cSSam Leffler 	return ret;
129739beb93cSSam Leffler }
1298