xref: /freebsd/contrib/wpa/wpa_supplicant/wpa_priv.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA Supplicant / privileged helper program
339beb93cSSam Leffler  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
539beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
639beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
739beb93cSSam Leffler  * published by the Free Software Foundation.
839beb93cSSam Leffler  *
939beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
1039beb93cSSam Leffler  * license.
1139beb93cSSam Leffler  *
1239beb93cSSam Leffler  * See README and COPYING for more details.
1339beb93cSSam Leffler  */
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #include "includes.h"
1639beb93cSSam Leffler #ifdef __linux__
1739beb93cSSam Leffler #include <fcntl.h>
1839beb93cSSam Leffler #endif /* __linux__ */
1939beb93cSSam Leffler #include <sys/un.h>
2039beb93cSSam Leffler #include <sys/stat.h>
2139beb93cSSam Leffler 
2239beb93cSSam Leffler #include "common.h"
2339beb93cSSam Leffler #include "eloop.h"
2439beb93cSSam Leffler #include "version.h"
2539beb93cSSam Leffler #include "drivers/driver.h"
2639beb93cSSam Leffler #include "l2_packet/l2_packet.h"
2739beb93cSSam Leffler #include "privsep_commands.h"
2839beb93cSSam Leffler #include "ieee802_11_defs.h"
2939beb93cSSam Leffler 
3039beb93cSSam Leffler #ifndef ETH_P_EAPOL
3139beb93cSSam Leffler #define ETH_P_EAPOL 0x888e
3239beb93cSSam Leffler #endif
3339beb93cSSam Leffler 
3439beb93cSSam Leffler #ifndef ETH_P_RSN_PREAUTH
3539beb93cSSam Leffler #define ETH_P_RSN_PREAUTH 0x88c7
3639beb93cSSam Leffler #endif
3739beb93cSSam Leffler 
3839beb93cSSam Leffler 
3939beb93cSSam Leffler struct wpa_priv_interface {
4039beb93cSSam Leffler 	struct wpa_priv_interface *next;
4139beb93cSSam Leffler 	char *driver_name;
4239beb93cSSam Leffler 	char *ifname;
4339beb93cSSam Leffler 	char *sock_name;
4439beb93cSSam Leffler 	int fd;
4539beb93cSSam Leffler 
4639beb93cSSam Leffler 	struct wpa_driver_ops *driver;
4739beb93cSSam Leffler 	void *drv_priv;
4839beb93cSSam Leffler 	struct sockaddr_un drv_addr;
4939beb93cSSam Leffler 	int wpas_registered;
5039beb93cSSam Leffler 
5139beb93cSSam Leffler 	/* TODO: add support for multiple l2 connections */
5239beb93cSSam Leffler 	struct l2_packet_data *l2;
5339beb93cSSam Leffler 	struct sockaddr_un l2_addr;
5439beb93cSSam Leffler };
5539beb93cSSam Leffler 
5639beb93cSSam Leffler 
5739beb93cSSam Leffler static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
5839beb93cSSam Leffler 				  struct sockaddr_un *from)
5939beb93cSSam Leffler {
6039beb93cSSam Leffler 	if (iface->drv_priv) {
6139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
6239beb93cSSam Leffler 		if (iface->driver->set_wpa)
6339beb93cSSam Leffler 			iface->driver->set_wpa(iface->drv_priv, 0);
6439beb93cSSam Leffler 		if (iface->driver->deinit)
6539beb93cSSam Leffler 			iface->driver->deinit(iface->drv_priv);
6639beb93cSSam Leffler 		iface->drv_priv = NULL;
6739beb93cSSam Leffler 		iface->wpas_registered = 0;
6839beb93cSSam Leffler 	}
6939beb93cSSam Leffler 
7039beb93cSSam Leffler 	if (iface->l2) {
7139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
7239beb93cSSam Leffler 			   "instance");
7339beb93cSSam Leffler 		l2_packet_deinit(iface->l2);
7439beb93cSSam Leffler 		iface->l2 = NULL;
7539beb93cSSam Leffler 	}
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 	if (iface->driver->init == NULL)
7839beb93cSSam Leffler 		return;
7939beb93cSSam Leffler 
8039beb93cSSam Leffler 	iface->drv_priv = iface->driver->init(iface, iface->ifname);
8139beb93cSSam Leffler 	if (iface->drv_priv == NULL) {
8239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to initialize driver wrapper");
8339beb93cSSam Leffler 		return;
8439beb93cSSam Leffler 	}
8539beb93cSSam Leffler 
8639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
8739beb93cSSam Leffler 		   "'%s'", iface->driver_name, iface->ifname);
8839beb93cSSam Leffler 
8939beb93cSSam Leffler 	os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr));
9039beb93cSSam Leffler 	iface->wpas_registered = 1;
9139beb93cSSam Leffler 
9239beb93cSSam Leffler 	if (iface->driver->set_param &&
9339beb93cSSam Leffler 	    iface->driver->set_param(iface->drv_priv, NULL) < 0) {
9439beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Driver interface rejected param");
9539beb93cSSam Leffler 	}
9639beb93cSSam Leffler 
9739beb93cSSam Leffler 	if (iface->driver->set_wpa)
9839beb93cSSam Leffler 		iface->driver->set_wpa(iface->drv_priv, 1);
9939beb93cSSam Leffler }
10039beb93cSSam Leffler 
10139beb93cSSam Leffler 
10239beb93cSSam Leffler static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface,
10339beb93cSSam Leffler 				    struct sockaddr_un *from)
10439beb93cSSam Leffler {
10539beb93cSSam Leffler 	if (iface->drv_priv) {
10639beb93cSSam Leffler 		if (iface->driver->set_wpa)
10739beb93cSSam Leffler 			iface->driver->set_wpa(iface->drv_priv, 0);
10839beb93cSSam Leffler 		if (iface->driver->deinit)
10939beb93cSSam Leffler 			iface->driver->deinit(iface->drv_priv);
11039beb93cSSam Leffler 		iface->drv_priv = NULL;
11139beb93cSSam Leffler 		iface->wpas_registered = 0;
11239beb93cSSam Leffler 	}
11339beb93cSSam Leffler }
11439beb93cSSam Leffler 
11539beb93cSSam Leffler 
11639beb93cSSam Leffler static void wpa_priv_cmd_set_wpa(struct wpa_priv_interface *iface,
11739beb93cSSam Leffler 				 char *buf, size_t len)
11839beb93cSSam Leffler {
11939beb93cSSam Leffler 	if (iface->drv_priv == NULL || len != sizeof(int))
12039beb93cSSam Leffler 		return;
12139beb93cSSam Leffler 
12239beb93cSSam Leffler 	if (iface->driver->set_wpa)
12339beb93cSSam Leffler 		iface->driver->set_wpa(iface->drv_priv, *((int *) buf));
12439beb93cSSam Leffler }
12539beb93cSSam Leffler 
12639beb93cSSam Leffler 
12739beb93cSSam Leffler static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
12839beb93cSSam Leffler 			      char *buf, size_t len)
12939beb93cSSam Leffler {
13039beb93cSSam Leffler 	if (iface->drv_priv == NULL)
13139beb93cSSam Leffler 		return;
13239beb93cSSam Leffler 
13339beb93cSSam Leffler 	if (iface->driver->scan)
13439beb93cSSam Leffler 		iface->driver->scan(iface->drv_priv, len ? (u8 *) buf : NULL,
13539beb93cSSam Leffler 				    len);
13639beb93cSSam Leffler }
13739beb93cSSam Leffler 
13839beb93cSSam Leffler 
13939beb93cSSam Leffler static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
14039beb93cSSam Leffler 				       struct sockaddr_un *from)
14139beb93cSSam Leffler {
14239beb93cSSam Leffler 	struct wpa_scan_results *res;
14339beb93cSSam Leffler 	u8 *buf = NULL, *pos, *end;
14439beb93cSSam Leffler 	int val;
14539beb93cSSam Leffler 	size_t i;
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 	res = iface->driver->get_scan_results2(iface->drv_priv);
14839beb93cSSam Leffler 	if (res == NULL)
14939beb93cSSam Leffler 		goto fail;
15039beb93cSSam Leffler 
15139beb93cSSam Leffler 	buf = os_malloc(60000);
15239beb93cSSam Leffler 	if (buf == NULL)
15339beb93cSSam Leffler 		goto fail;
15439beb93cSSam Leffler 	pos = buf;
15539beb93cSSam Leffler 	end = buf + 60000;
15639beb93cSSam Leffler 	val = res->num;
15739beb93cSSam Leffler 	os_memcpy(pos, &val, sizeof(int));
15839beb93cSSam Leffler 	pos += sizeof(int);
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 	for (i = 0; i < res->num; i++) {
16139beb93cSSam Leffler 		struct wpa_scan_res *r = res->res[i];
16239beb93cSSam Leffler 		val = sizeof(*r) + r->ie_len;
16339beb93cSSam Leffler 		if (end - pos < (int) sizeof(int) + val)
16439beb93cSSam Leffler 			break;
16539beb93cSSam Leffler 		os_memcpy(pos, &val, sizeof(int));
16639beb93cSSam Leffler 		pos += sizeof(int);
16739beb93cSSam Leffler 		os_memcpy(pos, r, val);
16839beb93cSSam Leffler 		pos += val;
16939beb93cSSam Leffler 	}
17039beb93cSSam Leffler 
17139beb93cSSam Leffler 	sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
17239beb93cSSam Leffler 	       sizeof(*from));
17339beb93cSSam Leffler 
17439beb93cSSam Leffler 	os_free(buf);
17539beb93cSSam Leffler 	os_free(res);
17639beb93cSSam Leffler 	return;
17739beb93cSSam Leffler 
17839beb93cSSam Leffler fail:
17939beb93cSSam Leffler 	os_free(buf);
18039beb93cSSam Leffler 	os_free(res);
18139beb93cSSam Leffler 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
18239beb93cSSam Leffler }
18339beb93cSSam Leffler 
18439beb93cSSam Leffler 
18539beb93cSSam Leffler static void wpa_priv_send_old_scan_results(struct wpa_priv_interface *iface,
18639beb93cSSam Leffler 					   struct sockaddr_un *from)
18739beb93cSSam Leffler {
18839beb93cSSam Leffler #define SCAN_AP_LIMIT 128
18939beb93cSSam Leffler 	int i, res, val;
19039beb93cSSam Leffler 	struct wpa_scan_result *results = NULL;
19139beb93cSSam Leffler 	u8 *buf = NULL, *pos, *end;
19239beb93cSSam Leffler 	struct wpa_scan_res nres;
19339beb93cSSam Leffler 
19439beb93cSSam Leffler 	results = os_malloc(SCAN_AP_LIMIT * sizeof(*results));
19539beb93cSSam Leffler 	if (results == NULL)
19639beb93cSSam Leffler 		goto fail;
19739beb93cSSam Leffler 
19839beb93cSSam Leffler 	res = iface->driver->get_scan_results(iface->drv_priv, results,
19939beb93cSSam Leffler 					      SCAN_AP_LIMIT);
20039beb93cSSam Leffler 	if (res < 0 || res > SCAN_AP_LIMIT)
20139beb93cSSam Leffler 		goto fail;
20239beb93cSSam Leffler 
20339beb93cSSam Leffler 	buf = os_malloc(60000);
20439beb93cSSam Leffler 	if (buf == NULL)
20539beb93cSSam Leffler 		goto fail;
20639beb93cSSam Leffler 	pos = buf;
20739beb93cSSam Leffler 	end = buf + 60000;
20839beb93cSSam Leffler 	os_memcpy(pos, &res, sizeof(int));
20939beb93cSSam Leffler 	pos += sizeof(int);
21039beb93cSSam Leffler 
21139beb93cSSam Leffler 	os_memset(&nres, 0, sizeof(nres));
21239beb93cSSam Leffler 	for (i = 0; i < res; i++) {
21339beb93cSSam Leffler 		struct wpa_scan_result *r = &results[i];
21439beb93cSSam Leffler 		size_t ie_len;
21539beb93cSSam Leffler 
21639beb93cSSam Leffler 		ie_len = 2 + r->ssid_len + r->rsn_ie_len + r->wpa_ie_len;
21739beb93cSSam Leffler 		if (r->maxrate)
21839beb93cSSam Leffler 			ie_len += 3;
21939beb93cSSam Leffler 		if (r->mdie_present)
22039beb93cSSam Leffler 			ie_len += 5;
22139beb93cSSam Leffler 
22239beb93cSSam Leffler 		val = sizeof(nres) + ie_len;
22339beb93cSSam Leffler 		if (end - pos < (int) sizeof(int) + val)
22439beb93cSSam Leffler 			break;
22539beb93cSSam Leffler 		os_memcpy(pos, &val, sizeof(int));
22639beb93cSSam Leffler 		pos += sizeof(int);
22739beb93cSSam Leffler 
22839beb93cSSam Leffler 		os_memcpy(nres.bssid, r->bssid, ETH_ALEN);
22939beb93cSSam Leffler 		nres.freq = r->freq;
23039beb93cSSam Leffler 		nres.caps = r->caps;
23139beb93cSSam Leffler 		nres.qual = r->qual;
23239beb93cSSam Leffler 		nres.noise = r->noise;
23339beb93cSSam Leffler 		nres.level = r->level;
23439beb93cSSam Leffler 		nres.tsf = r->tsf;
23539beb93cSSam Leffler 		nres.ie_len = ie_len;
23639beb93cSSam Leffler 
23739beb93cSSam Leffler 		os_memcpy(pos, &nres, sizeof(nres));
23839beb93cSSam Leffler 		pos += sizeof(nres);
23939beb93cSSam Leffler 
24039beb93cSSam Leffler 		/* SSID IE */
24139beb93cSSam Leffler 		*pos++ = WLAN_EID_SSID;
24239beb93cSSam Leffler 		*pos++ = r->ssid_len;
24339beb93cSSam Leffler 		os_memcpy(pos, r->ssid, r->ssid_len);
24439beb93cSSam Leffler 		pos += r->ssid_len;
24539beb93cSSam Leffler 
24639beb93cSSam Leffler 		if (r->maxrate) {
24739beb93cSSam Leffler 			/* Fake Supported Rate IE to include max rate */
24839beb93cSSam Leffler 			*pos++ = WLAN_EID_SUPP_RATES;
24939beb93cSSam Leffler 			*pos++ = 1;
25039beb93cSSam Leffler 			*pos++ = r->maxrate;
25139beb93cSSam Leffler 		}
25239beb93cSSam Leffler 
25339beb93cSSam Leffler 		if (r->rsn_ie_len) {
25439beb93cSSam Leffler 			os_memcpy(pos, r->rsn_ie, r->rsn_ie_len);
25539beb93cSSam Leffler 			pos += r->rsn_ie_len;
25639beb93cSSam Leffler 		}
25739beb93cSSam Leffler 
25839beb93cSSam Leffler 		if (r->mdie_present) {
25939beb93cSSam Leffler 			os_memcpy(pos, r->mdie, 5);
26039beb93cSSam Leffler 			pos += 5;
26139beb93cSSam Leffler 		}
26239beb93cSSam Leffler 
26339beb93cSSam Leffler 		if (r->wpa_ie_len) {
26439beb93cSSam Leffler 			os_memcpy(pos, r->wpa_ie, r->wpa_ie_len);
26539beb93cSSam Leffler 			pos += r->wpa_ie_len;
26639beb93cSSam Leffler 		}
26739beb93cSSam Leffler 	}
26839beb93cSSam Leffler 
26939beb93cSSam Leffler 	sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
27039beb93cSSam Leffler 	       sizeof(*from));
27139beb93cSSam Leffler 
27239beb93cSSam Leffler 	os_free(buf);
27339beb93cSSam Leffler 	os_free(results);
27439beb93cSSam Leffler 	return;
27539beb93cSSam Leffler 
27639beb93cSSam Leffler fail:
27739beb93cSSam Leffler 	os_free(buf);
27839beb93cSSam Leffler 	os_free(results);
27939beb93cSSam Leffler 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
28039beb93cSSam Leffler }
28139beb93cSSam Leffler 
28239beb93cSSam Leffler 
28339beb93cSSam Leffler static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
28439beb93cSSam Leffler 					  struct sockaddr_un *from)
28539beb93cSSam Leffler {
28639beb93cSSam Leffler 	if (iface->drv_priv == NULL)
28739beb93cSSam Leffler 		return;
28839beb93cSSam Leffler 
28939beb93cSSam Leffler 	if (iface->driver->get_scan_results2)
29039beb93cSSam Leffler 		wpa_priv_get_scan_results2(iface, from);
29139beb93cSSam Leffler 	else if (iface->driver->get_scan_results)
29239beb93cSSam Leffler 		wpa_priv_send_old_scan_results(iface, from);
29339beb93cSSam Leffler 	else
29439beb93cSSam Leffler 		sendto(iface->fd, "", 0, 0, (struct sockaddr *) from,
29539beb93cSSam Leffler 		       sizeof(*from));
29639beb93cSSam Leffler }
29739beb93cSSam Leffler 
29839beb93cSSam Leffler 
29939beb93cSSam Leffler static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface,
30039beb93cSSam Leffler 				   void *buf, size_t len)
30139beb93cSSam Leffler {
30239beb93cSSam Leffler 	struct wpa_driver_associate_params params;
30339beb93cSSam Leffler 	struct privsep_cmd_associate *assoc;
30439beb93cSSam Leffler 	u8 *bssid;
30539beb93cSSam Leffler 	int res;
30639beb93cSSam Leffler 
30739beb93cSSam Leffler 	if (iface->drv_priv == NULL || iface->driver->associate == NULL)
30839beb93cSSam Leffler 		return;
30939beb93cSSam Leffler 
31039beb93cSSam Leffler 	if (len < sizeof(*assoc)) {
31139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Invalid association request");
31239beb93cSSam Leffler 		return;
31339beb93cSSam Leffler 	}
31439beb93cSSam Leffler 
31539beb93cSSam Leffler 	assoc = buf;
31639beb93cSSam Leffler 	if (sizeof(*assoc) + assoc->wpa_ie_len > len) {
31739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Association request overflow");
31839beb93cSSam Leffler 		return;
31939beb93cSSam Leffler 	}
32039beb93cSSam Leffler 
32139beb93cSSam Leffler 	os_memset(&params, 0, sizeof(params));
32239beb93cSSam Leffler 	bssid = assoc->bssid;
32339beb93cSSam Leffler 	if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5])
32439beb93cSSam Leffler 		params.bssid = bssid;
32539beb93cSSam Leffler 	params.ssid = assoc->ssid;
32639beb93cSSam Leffler 	if (assoc->ssid_len > 32)
32739beb93cSSam Leffler 		return;
32839beb93cSSam Leffler 	params.ssid_len = assoc->ssid_len;
32939beb93cSSam Leffler 	params.freq = assoc->freq;
33039beb93cSSam Leffler 	if (assoc->wpa_ie_len) {
33139beb93cSSam Leffler 		params.wpa_ie = (u8 *) (assoc + 1);
33239beb93cSSam Leffler 		params.wpa_ie_len = assoc->wpa_ie_len;
33339beb93cSSam Leffler 	}
33439beb93cSSam Leffler 	params.pairwise_suite = assoc->pairwise_suite;
33539beb93cSSam Leffler 	params.group_suite = assoc->group_suite;
33639beb93cSSam Leffler 	params.key_mgmt_suite = assoc->key_mgmt_suite;
33739beb93cSSam Leffler 	params.auth_alg = assoc->auth_alg;
33839beb93cSSam Leffler 	params.mode = assoc->mode;
33939beb93cSSam Leffler 
34039beb93cSSam Leffler 	res = iface->driver->associate(iface->drv_priv, &params);
34139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "drv->associate: res=%d", res);
34239beb93cSSam Leffler }
34339beb93cSSam Leffler 
34439beb93cSSam Leffler 
34539beb93cSSam Leffler static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
34639beb93cSSam Leffler 				   struct sockaddr_un *from)
34739beb93cSSam Leffler {
34839beb93cSSam Leffler 	u8 bssid[ETH_ALEN];
34939beb93cSSam Leffler 
35039beb93cSSam Leffler 	if (iface->drv_priv == NULL)
35139beb93cSSam Leffler 		goto fail;
35239beb93cSSam Leffler 
35339beb93cSSam Leffler 	if (iface->driver->get_bssid == NULL ||
35439beb93cSSam Leffler 	    iface->driver->get_bssid(iface->drv_priv, bssid) < 0)
35539beb93cSSam Leffler 		goto fail;
35639beb93cSSam Leffler 
35739beb93cSSam Leffler 	sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
35839beb93cSSam Leffler 	       sizeof(*from));
35939beb93cSSam Leffler 	return;
36039beb93cSSam Leffler 
36139beb93cSSam Leffler fail:
36239beb93cSSam Leffler 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
36339beb93cSSam Leffler }
36439beb93cSSam Leffler 
36539beb93cSSam Leffler 
36639beb93cSSam Leffler static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
36739beb93cSSam Leffler 				  struct sockaddr_un *from)
36839beb93cSSam Leffler {
36939beb93cSSam Leffler 	u8 ssid[sizeof(int) + 32];
37039beb93cSSam Leffler 	int res;
37139beb93cSSam Leffler 
37239beb93cSSam Leffler 	if (iface->drv_priv == NULL)
37339beb93cSSam Leffler 		goto fail;
37439beb93cSSam Leffler 
37539beb93cSSam Leffler 	if (iface->driver->get_ssid == NULL)
37639beb93cSSam Leffler 		goto fail;
37739beb93cSSam Leffler 
37839beb93cSSam Leffler 	res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
37939beb93cSSam Leffler 	if (res < 0 || res > 32)
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,
38439beb93cSSam Leffler 	       sizeof(*from));
38539beb93cSSam Leffler 	return;
38639beb93cSSam Leffler 
38739beb93cSSam Leffler fail:
38839beb93cSSam Leffler 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
38939beb93cSSam Leffler }
39039beb93cSSam Leffler 
39139beb93cSSam Leffler 
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;
39739beb93cSSam Leffler 
39839beb93cSSam Leffler 	if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
39939beb93cSSam Leffler 		return;
40039beb93cSSam Leffler 
40139beb93cSSam Leffler 	if (len != sizeof(*params)) {
40239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Invalid set_key request");
40339beb93cSSam Leffler 		return;
40439beb93cSSam Leffler 	}
40539beb93cSSam Leffler 
40639beb93cSSam Leffler 	params = buf;
40739beb93cSSam Leffler 
40839beb93cSSam Leffler 	res = iface->driver->set_key(iface->drv_priv, params->alg,
40939beb93cSSam Leffler 				     params->addr, params->key_idx,
41039beb93cSSam Leffler 				     params->set_tx,
41139beb93cSSam Leffler 				     params->seq_len ? params->seq : NULL,
41239beb93cSSam Leffler 				     params->seq_len,
41339beb93cSSam Leffler 				     params->key_len ? params->key : NULL,
41439beb93cSSam Leffler 				     params->key_len);
41539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
41639beb93cSSam Leffler }
41739beb93cSSam Leffler 
41839beb93cSSam Leffler 
41939beb93cSSam Leffler static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
42039beb93cSSam Leffler 				  struct sockaddr_un *from)
42139beb93cSSam Leffler {
42239beb93cSSam Leffler 	struct wpa_driver_capa capa;
42339beb93cSSam Leffler 
42439beb93cSSam Leffler 	if (iface->drv_priv == NULL)
42539beb93cSSam Leffler 		goto fail;
42639beb93cSSam Leffler 
42739beb93cSSam Leffler 	if (iface->driver->get_capa == NULL ||
42839beb93cSSam Leffler 	    iface->driver->get_capa(iface->drv_priv, &capa) < 0)
42939beb93cSSam Leffler 		goto fail;
43039beb93cSSam Leffler 
43139beb93cSSam Leffler 	sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
43239beb93cSSam Leffler 	       sizeof(*from));
43339beb93cSSam Leffler 	return;
43439beb93cSSam Leffler 
43539beb93cSSam Leffler fail:
43639beb93cSSam Leffler 	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
43739beb93cSSam Leffler }
43839beb93cSSam Leffler 
43939beb93cSSam Leffler 
44039beb93cSSam Leffler static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
44139beb93cSSam Leffler 			   size_t len)
44239beb93cSSam Leffler {
44339beb93cSSam Leffler 	struct wpa_priv_interface *iface = ctx;
44439beb93cSSam Leffler 	struct msghdr msg;
44539beb93cSSam Leffler 	struct iovec io[2];
44639beb93cSSam Leffler 
44739beb93cSSam Leffler 	io[0].iov_base = (u8 *) src_addr;
44839beb93cSSam Leffler 	io[0].iov_len = ETH_ALEN;
44939beb93cSSam Leffler 	io[1].iov_base = (u8 *) buf;
45039beb93cSSam Leffler 	io[1].iov_len = len;
45139beb93cSSam Leffler 
45239beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
45339beb93cSSam Leffler 	msg.msg_iov = io;
45439beb93cSSam Leffler 	msg.msg_iovlen = 2;
45539beb93cSSam Leffler 	msg.msg_name = &iface->l2_addr;
45639beb93cSSam Leffler 	msg.msg_namelen = sizeof(iface->l2_addr);
45739beb93cSSam Leffler 
45839beb93cSSam Leffler 	if (sendmsg(iface->fd, &msg, 0) < 0) {
45939beb93cSSam Leffler 		perror("sendmsg(l2 rx)");
46039beb93cSSam Leffler 	}
46139beb93cSSam Leffler }
46239beb93cSSam Leffler 
46339beb93cSSam Leffler 
46439beb93cSSam Leffler static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
46539beb93cSSam Leffler 				     struct sockaddr_un *from,
46639beb93cSSam Leffler 				     void *buf, size_t len)
46739beb93cSSam Leffler {
46839beb93cSSam Leffler 	int *reg_cmd = buf;
46939beb93cSSam Leffler 	u8 own_addr[ETH_ALEN];
47039beb93cSSam Leffler 	int res;
47139beb93cSSam Leffler 	u16 proto;
47239beb93cSSam Leffler 
47339beb93cSSam Leffler 	if (len != 2 * sizeof(int)) {
47439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
47539beb93cSSam Leffler 			   (unsigned long) len);
47639beb93cSSam Leffler 		return;
47739beb93cSSam Leffler 	}
47839beb93cSSam Leffler 
47939beb93cSSam Leffler 	proto = reg_cmd[0];
48039beb93cSSam Leffler 	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
48139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
48239beb93cSSam Leffler 			   "ethertype 0x%x", proto);
48339beb93cSSam Leffler 		return;
48439beb93cSSam Leffler 	}
48539beb93cSSam Leffler 
48639beb93cSSam Leffler 	if (iface->l2) {
48739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
48839beb93cSSam Leffler 			   "instance");
48939beb93cSSam Leffler 		l2_packet_deinit(iface->l2);
49039beb93cSSam Leffler 		iface->l2 = NULL;
49139beb93cSSam Leffler 	}
49239beb93cSSam Leffler 
49339beb93cSSam Leffler 	os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr));
49439beb93cSSam Leffler 
49539beb93cSSam Leffler 	iface->l2 = l2_packet_init(iface->ifname, NULL, proto,
49639beb93cSSam Leffler 				   wpa_priv_l2_rx, iface, reg_cmd[1]);
49739beb93cSSam Leffler 	if (iface->l2 == NULL) {
49839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
49939beb93cSSam Leffler 			   "instance for protocol %d", proto);
50039beb93cSSam Leffler 		return;
50139beb93cSSam Leffler 	}
50239beb93cSSam Leffler 
50339beb93cSSam Leffler 	if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) {
50439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to get own address from "
50539beb93cSSam Leffler 			   "l2_packet");
50639beb93cSSam Leffler 		l2_packet_deinit(iface->l2);
50739beb93cSSam Leffler 		iface->l2 = NULL;
50839beb93cSSam Leffler 		return;
50939beb93cSSam Leffler 	}
51039beb93cSSam Leffler 
51139beb93cSSam Leffler 	res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
51239beb93cSSam Leffler 		     (struct sockaddr *) from, sizeof(*from));
51339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res);
51439beb93cSSam Leffler }
51539beb93cSSam Leffler 
51639beb93cSSam Leffler 
51739beb93cSSam Leffler static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
51839beb93cSSam Leffler 				       struct sockaddr_un *from)
51939beb93cSSam Leffler {
52039beb93cSSam Leffler 	if (iface->l2) {
52139beb93cSSam Leffler 		l2_packet_deinit(iface->l2);
52239beb93cSSam Leffler 		iface->l2 = NULL;
52339beb93cSSam Leffler 	}
52439beb93cSSam Leffler }
52539beb93cSSam Leffler 
52639beb93cSSam Leffler 
52739beb93cSSam Leffler static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
52839beb93cSSam Leffler 					      struct sockaddr_un *from)
52939beb93cSSam Leffler {
53039beb93cSSam Leffler 	if (iface->l2)
53139beb93cSSam Leffler 		l2_packet_notify_auth_start(iface->l2);
53239beb93cSSam Leffler }
53339beb93cSSam Leffler 
53439beb93cSSam Leffler 
53539beb93cSSam Leffler static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
53639beb93cSSam Leffler 				 struct sockaddr_un *from,
53739beb93cSSam Leffler 				 void *buf, size_t len)
53839beb93cSSam Leffler {
53939beb93cSSam Leffler 	u8 *dst_addr;
54039beb93cSSam Leffler 	u16 proto;
54139beb93cSSam Leffler 	int res;
54239beb93cSSam Leffler 
54339beb93cSSam Leffler 	if (iface->l2 == NULL)
54439beb93cSSam Leffler 		return;
54539beb93cSSam Leffler 
54639beb93cSSam Leffler 	if (len < ETH_ALEN + 2) {
54739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Too short L2 send packet (len=%lu)",
54839beb93cSSam Leffler 			   (unsigned long) len);
54939beb93cSSam Leffler 		return;
55039beb93cSSam Leffler 	}
55139beb93cSSam Leffler 
55239beb93cSSam Leffler 	dst_addr = buf;
55339beb93cSSam Leffler 	os_memcpy(&proto, buf + ETH_ALEN, 2);
55439beb93cSSam Leffler 
55539beb93cSSam Leffler 	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
55639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
55739beb93cSSam Leffler 			   "0x%x", proto);
55839beb93cSSam Leffler 		return;
55939beb93cSSam Leffler 	}
56039beb93cSSam Leffler 
56139beb93cSSam Leffler 	res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2,
56239beb93cSSam Leffler 			     len - ETH_ALEN - 2);
56339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "L2 send: res=%d", res);
56439beb93cSSam Leffler }
56539beb93cSSam Leffler 
56639beb93cSSam Leffler 
56739beb93cSSam Leffler static void wpa_priv_cmd_set_mode(struct wpa_priv_interface *iface,
56839beb93cSSam Leffler 				  void *buf, size_t len)
56939beb93cSSam Leffler {
57039beb93cSSam Leffler 	if (iface->drv_priv == NULL || iface->driver->set_mode == NULL ||
57139beb93cSSam Leffler 	    len != sizeof(int))
57239beb93cSSam Leffler 		return;
57339beb93cSSam Leffler 
57439beb93cSSam Leffler 	iface->driver->set_mode(iface->drv_priv, *((int *) buf));
57539beb93cSSam Leffler }
57639beb93cSSam Leffler 
57739beb93cSSam Leffler 
57839beb93cSSam Leffler static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface,
57939beb93cSSam Leffler 				     char *buf)
58039beb93cSSam Leffler {
58139beb93cSSam Leffler 	if (iface->drv_priv == NULL || iface->driver->set_country == NULL ||
58239beb93cSSam Leffler 	    *buf == '\0')
58339beb93cSSam Leffler 		return;
58439beb93cSSam Leffler 
58539beb93cSSam Leffler 	iface->driver->set_country(iface->drv_priv, buf);
58639beb93cSSam Leffler }
58739beb93cSSam Leffler 
58839beb93cSSam Leffler 
58939beb93cSSam Leffler static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
59039beb93cSSam Leffler {
59139beb93cSSam Leffler 	struct wpa_priv_interface *iface = eloop_ctx;
59239beb93cSSam Leffler 	char buf[2000], *pos;
59339beb93cSSam Leffler 	void *cmd_buf;
59439beb93cSSam Leffler 	size_t cmd_len;
59539beb93cSSam Leffler 	int res, cmd;
59639beb93cSSam Leffler 	struct sockaddr_un from;
59739beb93cSSam Leffler 	socklen_t fromlen = sizeof(from);
59839beb93cSSam Leffler 
59939beb93cSSam Leffler 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
60039beb93cSSam Leffler 		       &fromlen);
60139beb93cSSam Leffler 	if (res < 0) {
60239beb93cSSam Leffler 		perror("recvfrom");
60339beb93cSSam Leffler 		return;
60439beb93cSSam Leffler 	}
60539beb93cSSam Leffler 
60639beb93cSSam Leffler 	if (res < (int) sizeof(int)) {
60739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Too short command (len=%d)", res);
60839beb93cSSam Leffler 		return;
60939beb93cSSam Leffler 	}
61039beb93cSSam Leffler 
61139beb93cSSam Leffler 	os_memcpy(&cmd, buf, sizeof(int));
61239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Command %d for interface %s",
61339beb93cSSam Leffler 		   cmd, iface->ifname);
61439beb93cSSam Leffler 	cmd_buf = &buf[sizeof(int)];
61539beb93cSSam Leffler 	cmd_len = res - sizeof(int);
61639beb93cSSam Leffler 
61739beb93cSSam Leffler 	switch (cmd) {
61839beb93cSSam Leffler 	case PRIVSEP_CMD_REGISTER:
61939beb93cSSam Leffler 		wpa_priv_cmd_register(iface, &from);
62039beb93cSSam Leffler 		break;
62139beb93cSSam Leffler 	case PRIVSEP_CMD_UNREGISTER:
62239beb93cSSam Leffler 		wpa_priv_cmd_unregister(iface, &from);
62339beb93cSSam Leffler 		break;
62439beb93cSSam Leffler 	case PRIVSEP_CMD_SET_WPA:
62539beb93cSSam Leffler 		wpa_priv_cmd_set_wpa(iface, cmd_buf, cmd_len);
62639beb93cSSam Leffler 		break;
62739beb93cSSam Leffler 	case PRIVSEP_CMD_SCAN:
62839beb93cSSam Leffler 		wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
62939beb93cSSam Leffler 		break;
63039beb93cSSam Leffler 	case PRIVSEP_CMD_GET_SCAN_RESULTS:
63139beb93cSSam Leffler 		wpa_priv_cmd_get_scan_results(iface, &from);
63239beb93cSSam Leffler 		break;
63339beb93cSSam Leffler 	case PRIVSEP_CMD_ASSOCIATE:
63439beb93cSSam Leffler 		wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
63539beb93cSSam Leffler 		break;
63639beb93cSSam Leffler 	case PRIVSEP_CMD_GET_BSSID:
63739beb93cSSam Leffler 		wpa_priv_cmd_get_bssid(iface, &from);
63839beb93cSSam Leffler 		break;
63939beb93cSSam Leffler 	case PRIVSEP_CMD_GET_SSID:
64039beb93cSSam Leffler 		wpa_priv_cmd_get_ssid(iface, &from);
64139beb93cSSam Leffler 		break;
64239beb93cSSam Leffler 	case PRIVSEP_CMD_SET_KEY:
64339beb93cSSam Leffler 		wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
64439beb93cSSam Leffler 		break;
64539beb93cSSam Leffler 	case PRIVSEP_CMD_GET_CAPA:
64639beb93cSSam Leffler 		wpa_priv_cmd_get_capa(iface, &from);
64739beb93cSSam Leffler 		break;
64839beb93cSSam Leffler 	case PRIVSEP_CMD_L2_REGISTER:
64939beb93cSSam Leffler 		wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len);
65039beb93cSSam Leffler 		break;
65139beb93cSSam Leffler 	case PRIVSEP_CMD_L2_UNREGISTER:
65239beb93cSSam Leffler 		wpa_priv_cmd_l2_unregister(iface, &from);
65339beb93cSSam Leffler 		break;
65439beb93cSSam Leffler 	case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
65539beb93cSSam Leffler 		wpa_priv_cmd_l2_notify_auth_start(iface, &from);
65639beb93cSSam Leffler 		break;
65739beb93cSSam Leffler 	case PRIVSEP_CMD_L2_SEND:
65839beb93cSSam Leffler 		wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len);
65939beb93cSSam Leffler 		break;
66039beb93cSSam Leffler 	case PRIVSEP_CMD_SET_MODE:
66139beb93cSSam Leffler 		wpa_priv_cmd_set_mode(iface, cmd_buf, cmd_len);
66239beb93cSSam Leffler 		break;
66339beb93cSSam Leffler 	case PRIVSEP_CMD_SET_COUNTRY:
66439beb93cSSam Leffler 		pos = cmd_buf;
66539beb93cSSam Leffler 		if (pos + cmd_len >= buf + sizeof(buf))
66639beb93cSSam Leffler 			break;
66739beb93cSSam Leffler 		pos[cmd_len] = '\0';
66839beb93cSSam Leffler 		wpa_priv_cmd_set_country(iface, pos);
66939beb93cSSam Leffler 		break;
67039beb93cSSam Leffler 	}
67139beb93cSSam Leffler }
67239beb93cSSam Leffler 
67339beb93cSSam Leffler 
67439beb93cSSam Leffler static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
67539beb93cSSam Leffler {
67639beb93cSSam Leffler 	if (iface->drv_priv && iface->driver->deinit)
67739beb93cSSam Leffler 		iface->driver->deinit(iface->drv_priv);
67839beb93cSSam Leffler 
67939beb93cSSam Leffler 	if (iface->fd >= 0) {
68039beb93cSSam Leffler 		eloop_unregister_read_sock(iface->fd);
68139beb93cSSam Leffler 		close(iface->fd);
68239beb93cSSam Leffler 		unlink(iface->sock_name);
68339beb93cSSam Leffler 	}
68439beb93cSSam Leffler 
68539beb93cSSam Leffler 	if (iface->l2)
68639beb93cSSam Leffler 		l2_packet_deinit(iface->l2);
68739beb93cSSam Leffler 
68839beb93cSSam Leffler 	os_free(iface->ifname);
68939beb93cSSam Leffler 	os_free(iface->driver_name);
69039beb93cSSam Leffler 	os_free(iface->sock_name);
69139beb93cSSam Leffler 	os_free(iface);
69239beb93cSSam Leffler }
69339beb93cSSam Leffler 
69439beb93cSSam Leffler 
69539beb93cSSam Leffler extern struct wpa_driver_ops *wpa_supplicant_drivers[];
69639beb93cSSam Leffler 
69739beb93cSSam Leffler static struct wpa_priv_interface *
69839beb93cSSam Leffler wpa_priv_interface_init(const char *dir, const char *params)
69939beb93cSSam Leffler {
70039beb93cSSam Leffler 	struct wpa_priv_interface *iface;
70139beb93cSSam Leffler 	char *pos;
70239beb93cSSam Leffler 	size_t len;
70339beb93cSSam Leffler 	struct sockaddr_un addr;
70439beb93cSSam Leffler 	int i;
70539beb93cSSam Leffler 
70639beb93cSSam Leffler 	pos = os_strchr(params, ':');
70739beb93cSSam Leffler 	if (pos == NULL)
70839beb93cSSam Leffler 		return NULL;
70939beb93cSSam Leffler 
71039beb93cSSam Leffler 	iface = os_zalloc(sizeof(*iface));
71139beb93cSSam Leffler 	if (iface == NULL)
71239beb93cSSam Leffler 		return NULL;
71339beb93cSSam Leffler 	iface->fd = -1;
71439beb93cSSam Leffler 
71539beb93cSSam Leffler 	len = pos - params;
71639beb93cSSam Leffler 	iface->driver_name = os_malloc(len + 1);
71739beb93cSSam Leffler 	if (iface->driver_name == NULL) {
71839beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
71939beb93cSSam Leffler 		return NULL;
72039beb93cSSam Leffler 	}
72139beb93cSSam Leffler 	os_memcpy(iface->driver_name, params, len);
72239beb93cSSam Leffler 	iface->driver_name[len] = '\0';
72339beb93cSSam Leffler 
72439beb93cSSam Leffler 	for (i = 0; wpa_supplicant_drivers[i]; i++) {
72539beb93cSSam Leffler 		if (os_strcmp(iface->driver_name,
72639beb93cSSam Leffler 			      wpa_supplicant_drivers[i]->name) == 0) {
72739beb93cSSam Leffler 			iface->driver = wpa_supplicant_drivers[i];
72839beb93cSSam Leffler 			break;
72939beb93cSSam Leffler 		}
73039beb93cSSam Leffler 	}
73139beb93cSSam Leffler 	if (iface->driver == NULL) {
73239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Unsupported driver '%s'",
73339beb93cSSam Leffler 			   iface->driver_name);
73439beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
73539beb93cSSam Leffler 		return NULL;
73639beb93cSSam Leffler 	}
73739beb93cSSam Leffler 
73839beb93cSSam Leffler 	pos++;
73939beb93cSSam Leffler 	iface->ifname = os_strdup(pos);
74039beb93cSSam Leffler 	if (iface->ifname == NULL) {
74139beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
74239beb93cSSam Leffler 		return NULL;
74339beb93cSSam Leffler 	}
74439beb93cSSam Leffler 
74539beb93cSSam Leffler 	len = os_strlen(dir) + 1 + os_strlen(iface->ifname);
74639beb93cSSam Leffler 	iface->sock_name = os_malloc(len + 1);
74739beb93cSSam Leffler 	if (iface->sock_name == NULL) {
74839beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
74939beb93cSSam Leffler 		return NULL;
75039beb93cSSam Leffler 	}
75139beb93cSSam Leffler 
75239beb93cSSam Leffler 	os_snprintf(iface->sock_name, len + 1, "%s/%s", dir, iface->ifname);
75339beb93cSSam Leffler 	if (os_strlen(iface->sock_name) >= sizeof(addr.sun_path)) {
75439beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
75539beb93cSSam Leffler 		return NULL;
75639beb93cSSam Leffler 	}
75739beb93cSSam Leffler 
75839beb93cSSam Leffler 	iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
75939beb93cSSam Leffler 	if (iface->fd < 0) {
76039beb93cSSam Leffler 		perror("socket(PF_UNIX)");
76139beb93cSSam Leffler 		wpa_priv_interface_deinit(iface);
76239beb93cSSam Leffler 		return NULL;
76339beb93cSSam Leffler 	}
76439beb93cSSam Leffler 
76539beb93cSSam Leffler 	os_memset(&addr, 0, sizeof(addr));
76639beb93cSSam Leffler 	addr.sun_family = AF_UNIX;
76739beb93cSSam Leffler 	os_strlcpy(addr.sun_path, iface->sock_name, sizeof(addr.sun_path));
76839beb93cSSam Leffler 
76939beb93cSSam Leffler 	if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
77039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "bind(PF_UNIX) failed: %s",
77139beb93cSSam Leffler 			   strerror(errno));
77239beb93cSSam Leffler 		if (connect(iface->fd, (struct sockaddr *) &addr,
77339beb93cSSam Leffler 			    sizeof(addr)) < 0) {
77439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Socket exists, but does not "
77539beb93cSSam Leffler 				   "allow connections - assuming it was "
77639beb93cSSam Leffler 				   "leftover from forced program termination");
77739beb93cSSam Leffler 			if (unlink(iface->sock_name) < 0) {
77839beb93cSSam Leffler 				perror("unlink[ctrl_iface]");
77939beb93cSSam Leffler 				wpa_printf(MSG_ERROR, "Could not unlink "
78039beb93cSSam Leffler 					   "existing ctrl_iface socket '%s'",
78139beb93cSSam Leffler 					   iface->sock_name);
78239beb93cSSam Leffler 				goto fail;
78339beb93cSSam Leffler 			}
78439beb93cSSam Leffler 			if (bind(iface->fd, (struct sockaddr *) &addr,
78539beb93cSSam Leffler 				 sizeof(addr)) < 0) {
78639beb93cSSam Leffler 				perror("bind(PF_UNIX)");
78739beb93cSSam Leffler 				goto fail;
78839beb93cSSam Leffler 			}
78939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
79039beb93cSSam Leffler 				   "socket '%s'", iface->sock_name);
79139beb93cSSam Leffler 		} else {
79239beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Socket exists and seems to be "
79339beb93cSSam Leffler 				   "in use - cannot override it");
79439beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
79539beb93cSSam Leffler 				   "not used anymore", iface->sock_name);
79639beb93cSSam Leffler 			goto fail;
79739beb93cSSam Leffler 		}
79839beb93cSSam Leffler 	}
79939beb93cSSam Leffler 
80039beb93cSSam Leffler 	if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
80139beb93cSSam Leffler 		perror("chmod");
80239beb93cSSam Leffler 		goto fail;
80339beb93cSSam Leffler 	}
80439beb93cSSam Leffler 
80539beb93cSSam Leffler 	eloop_register_read_sock(iface->fd, wpa_priv_receive, iface, NULL);
80639beb93cSSam Leffler 
80739beb93cSSam Leffler 	return iface;
80839beb93cSSam Leffler 
80939beb93cSSam Leffler fail:
81039beb93cSSam Leffler 	wpa_priv_interface_deinit(iface);
81139beb93cSSam Leffler 	return NULL;
81239beb93cSSam Leffler }
81339beb93cSSam Leffler 
81439beb93cSSam Leffler 
81539beb93cSSam Leffler static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event,
81639beb93cSSam Leffler 			       const void *data, size_t data_len)
81739beb93cSSam Leffler {
81839beb93cSSam Leffler 	struct msghdr msg;
81939beb93cSSam Leffler 	struct iovec io[2];
82039beb93cSSam Leffler 
82139beb93cSSam Leffler 	io[0].iov_base = &event;
82239beb93cSSam Leffler 	io[0].iov_len = sizeof(event);
82339beb93cSSam Leffler 	io[1].iov_base = (u8 *) data;
82439beb93cSSam Leffler 	io[1].iov_len = data_len;
82539beb93cSSam Leffler 
82639beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
82739beb93cSSam Leffler 	msg.msg_iov = io;
82839beb93cSSam Leffler 	msg.msg_iovlen = data ? 2 : 1;
82939beb93cSSam Leffler 	msg.msg_name = &iface->drv_addr;
83039beb93cSSam Leffler 	msg.msg_namelen = sizeof(iface->drv_addr);
83139beb93cSSam Leffler 
83239beb93cSSam Leffler 	if (sendmsg(iface->fd, &msg, 0) < 0) {
83339beb93cSSam Leffler 		perror("sendmsg(wpas_socket)");
83439beb93cSSam Leffler 		return -1;
83539beb93cSSam Leffler 	}
83639beb93cSSam Leffler 
83739beb93cSSam Leffler 	return 0;
83839beb93cSSam Leffler }
83939beb93cSSam Leffler 
84039beb93cSSam Leffler 
84139beb93cSSam Leffler static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event,
84239beb93cSSam Leffler 				union wpa_event_data *data)
84339beb93cSSam Leffler {
84439beb93cSSam Leffler 	size_t buflen = 3 * sizeof(int);
84539beb93cSSam Leffler 	u8 *buf, *pos;
84639beb93cSSam Leffler 	int len;
84739beb93cSSam Leffler 
84839beb93cSSam Leffler 	if (data) {
84939beb93cSSam Leffler 		buflen += data->assoc_info.req_ies_len +
85039beb93cSSam Leffler 			data->assoc_info.resp_ies_len +
85139beb93cSSam Leffler 			data->assoc_info.beacon_ies_len;
85239beb93cSSam Leffler 	}
85339beb93cSSam Leffler 
85439beb93cSSam Leffler 	buf = os_malloc(buflen);
85539beb93cSSam Leffler 	if (buf == NULL)
85639beb93cSSam Leffler 		return;
85739beb93cSSam Leffler 
85839beb93cSSam Leffler 	pos = buf;
85939beb93cSSam Leffler 
86039beb93cSSam Leffler 	if (data && data->assoc_info.req_ies) {
86139beb93cSSam Leffler 		len = data->assoc_info.req_ies_len;
86239beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
86339beb93cSSam Leffler 		pos += sizeof(int);
86439beb93cSSam Leffler 		os_memcpy(pos, data->assoc_info.req_ies, len);
86539beb93cSSam Leffler 		pos += len;
86639beb93cSSam Leffler 	} else {
86739beb93cSSam Leffler 		len = 0;
86839beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
86939beb93cSSam Leffler 		pos += sizeof(int);
87039beb93cSSam Leffler 	}
87139beb93cSSam Leffler 
87239beb93cSSam Leffler 	if (data && data->assoc_info.resp_ies) {
87339beb93cSSam Leffler 		len = data->assoc_info.resp_ies_len;
87439beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
87539beb93cSSam Leffler 		pos += sizeof(int);
87639beb93cSSam Leffler 		os_memcpy(pos, data->assoc_info.resp_ies, len);
87739beb93cSSam Leffler 		pos += len;
87839beb93cSSam Leffler 	} else {
87939beb93cSSam Leffler 		len = 0;
88039beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
88139beb93cSSam Leffler 		pos += sizeof(int);
88239beb93cSSam Leffler 	}
88339beb93cSSam Leffler 
88439beb93cSSam Leffler 	if (data && data->assoc_info.beacon_ies) {
88539beb93cSSam Leffler 		len = data->assoc_info.beacon_ies_len;
88639beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
88739beb93cSSam Leffler 		pos += sizeof(int);
88839beb93cSSam Leffler 		os_memcpy(pos, data->assoc_info.beacon_ies, len);
88939beb93cSSam Leffler 		pos += len;
89039beb93cSSam Leffler 	} else {
89139beb93cSSam Leffler 		len = 0;
89239beb93cSSam Leffler 		os_memcpy(pos, &len, sizeof(int));
89339beb93cSSam Leffler 		pos += sizeof(int);
89439beb93cSSam Leffler 	}
89539beb93cSSam Leffler 
89639beb93cSSam Leffler 	wpa_priv_send_event(iface, event, buf, buflen);
89739beb93cSSam Leffler 
89839beb93cSSam Leffler 	os_free(buf);
89939beb93cSSam Leffler }
90039beb93cSSam Leffler 
90139beb93cSSam Leffler 
90239beb93cSSam Leffler static void wpa_priv_send_interface_status(struct wpa_priv_interface *iface,
90339beb93cSSam Leffler 					   union wpa_event_data *data)
90439beb93cSSam Leffler {
90539beb93cSSam Leffler 	int ievent;
90639beb93cSSam Leffler 	size_t len, maxlen;
90739beb93cSSam Leffler 	u8 *buf;
90839beb93cSSam Leffler 	char *ifname;
90939beb93cSSam Leffler 
91039beb93cSSam Leffler 	if (data == NULL)
91139beb93cSSam Leffler 		return;
91239beb93cSSam Leffler 
91339beb93cSSam Leffler 	ievent = data->interface_status.ievent;
91439beb93cSSam Leffler 	maxlen = sizeof(data->interface_status.ifname);
91539beb93cSSam Leffler 	ifname = data->interface_status.ifname;
91639beb93cSSam Leffler 	for (len = 0; len < maxlen && ifname[len]; len++)
91739beb93cSSam Leffler 		;
91839beb93cSSam Leffler 
91939beb93cSSam Leffler 	buf = os_malloc(sizeof(int) + len);
92039beb93cSSam Leffler 	if (buf == NULL)
92139beb93cSSam Leffler 		return;
92239beb93cSSam Leffler 
92339beb93cSSam Leffler 	os_memcpy(buf, &ievent, sizeof(int));
92439beb93cSSam Leffler 	os_memcpy(buf + sizeof(int), ifname, len);
92539beb93cSSam Leffler 
92639beb93cSSam Leffler 	wpa_priv_send_event(iface, PRIVSEP_EVENT_INTERFACE_STATUS,
92739beb93cSSam Leffler 			    buf, sizeof(int) + len);
92839beb93cSSam Leffler 
92939beb93cSSam Leffler 	os_free(buf);
93039beb93cSSam Leffler 
93139beb93cSSam Leffler }
93239beb93cSSam Leffler 
93339beb93cSSam Leffler 
93439beb93cSSam Leffler static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface,
93539beb93cSSam Leffler 				      union wpa_event_data *data)
93639beb93cSSam Leffler {
93739beb93cSSam Leffler 	size_t len;
93839beb93cSSam Leffler 	u8 *buf, *pos;
93939beb93cSSam Leffler 
94039beb93cSSam Leffler 	if (data == NULL || data->ft_ies.ies == NULL)
94139beb93cSSam Leffler 		return;
94239beb93cSSam Leffler 
94339beb93cSSam Leffler 	len = sizeof(int) + ETH_ALEN + data->ft_ies.ies_len;
94439beb93cSSam Leffler 	buf = os_malloc(len);
94539beb93cSSam Leffler 	if (buf == NULL)
94639beb93cSSam Leffler 		return;
94739beb93cSSam Leffler 
94839beb93cSSam Leffler 	pos = buf;
94939beb93cSSam Leffler 	os_memcpy(pos, &data->ft_ies.ft_action, sizeof(int));
95039beb93cSSam Leffler 	pos += sizeof(int);
95139beb93cSSam Leffler 	os_memcpy(pos, data->ft_ies.target_ap, ETH_ALEN);
95239beb93cSSam Leffler 	pos += ETH_ALEN;
95339beb93cSSam Leffler 	os_memcpy(pos, data->ft_ies.ies, data->ft_ies.ies_len);
95439beb93cSSam Leffler 
95539beb93cSSam Leffler 	wpa_priv_send_event(iface, PRIVSEP_EVENT_FT_RESPONSE, buf, len);
95639beb93cSSam Leffler 
95739beb93cSSam Leffler 	os_free(buf);
95839beb93cSSam Leffler 
95939beb93cSSam Leffler }
96039beb93cSSam Leffler 
96139beb93cSSam Leffler 
96239beb93cSSam Leffler void wpa_supplicant_event(void *ctx, wpa_event_type event,
96339beb93cSSam Leffler 			  union wpa_event_data *data)
96439beb93cSSam Leffler {
96539beb93cSSam Leffler 	struct wpa_priv_interface *iface = ctx;
96639beb93cSSam Leffler 
96739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "%s - event=%d", __func__, event);
96839beb93cSSam Leffler 
96939beb93cSSam Leffler 	if (!iface->wpas_registered) {
97039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Driver event received, but "
97139beb93cSSam Leffler 			   "wpa_supplicant not registered");
97239beb93cSSam Leffler 		return;
97339beb93cSSam Leffler 	}
97439beb93cSSam Leffler 
97539beb93cSSam Leffler 	switch (event) {
97639beb93cSSam Leffler 	case EVENT_ASSOC:
97739beb93cSSam Leffler 		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOC, data);
97839beb93cSSam Leffler 		break;
97939beb93cSSam Leffler 	case EVENT_DISASSOC:
98039beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_DISASSOC, NULL, 0);
98139beb93cSSam Leffler 		break;
98239beb93cSSam Leffler 	case EVENT_ASSOCINFO:
98339beb93cSSam Leffler 		if (data == NULL)
98439beb93cSSam Leffler 			return;
98539beb93cSSam Leffler 		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOCINFO, data);
98639beb93cSSam Leffler 		break;
98739beb93cSSam Leffler 	case EVENT_MICHAEL_MIC_FAILURE:
98839beb93cSSam Leffler 		if (data == NULL)
98939beb93cSSam Leffler 			return;
99039beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
99139beb93cSSam Leffler 				    &data->michael_mic_failure.unicast,
99239beb93cSSam Leffler 				    sizeof(int));
99339beb93cSSam Leffler 		break;
99439beb93cSSam Leffler 	case EVENT_SCAN_RESULTS:
99539beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_RESULTS, NULL,
99639beb93cSSam Leffler 				    0);
99739beb93cSSam Leffler 		break;
99839beb93cSSam Leffler 	case EVENT_INTERFACE_STATUS:
99939beb93cSSam Leffler 		wpa_priv_send_interface_status(iface, data);
100039beb93cSSam Leffler 		break;
100139beb93cSSam Leffler 	case EVENT_PMKID_CANDIDATE:
100239beb93cSSam Leffler 		if (data == NULL)
100339beb93cSSam Leffler 			return;
100439beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_PMKID_CANDIDATE,
100539beb93cSSam Leffler 				    &data->pmkid_candidate,
100639beb93cSSam Leffler 				    sizeof(struct pmkid_candidate));
100739beb93cSSam Leffler 		break;
100839beb93cSSam Leffler 	case EVENT_STKSTART:
100939beb93cSSam Leffler 		if (data == NULL)
101039beb93cSSam Leffler 			return;
101139beb93cSSam Leffler 		wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART,
101239beb93cSSam Leffler 				    &data->stkstart.peer, ETH_ALEN);
101339beb93cSSam Leffler 		break;
101439beb93cSSam Leffler 	case EVENT_FT_RESPONSE:
101539beb93cSSam Leffler 		wpa_priv_send_ft_response(iface, data);
101639beb93cSSam Leffler 		break;
101739beb93cSSam Leffler 	default:
101839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Unsupported driver event %d - TODO",
101939beb93cSSam Leffler 			   event);
102039beb93cSSam Leffler 		break;
102139beb93cSSam Leffler 	}
102239beb93cSSam Leffler }
102339beb93cSSam Leffler 
102439beb93cSSam Leffler 
102539beb93cSSam Leffler void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
102639beb93cSSam Leffler 			     const u8 *buf, size_t len)
102739beb93cSSam Leffler {
102839beb93cSSam Leffler 	struct wpa_priv_interface *iface = ctx;
102939beb93cSSam Leffler 	struct msghdr msg;
103039beb93cSSam Leffler 	struct iovec io[3];
103139beb93cSSam Leffler 	int event = PRIVSEP_EVENT_RX_EAPOL;
103239beb93cSSam Leffler 
103339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "RX EAPOL from driver");
103439beb93cSSam Leffler 	io[0].iov_base = &event;
103539beb93cSSam Leffler 	io[0].iov_len = sizeof(event);
103639beb93cSSam Leffler 	io[1].iov_base = (u8 *) src_addr;
103739beb93cSSam Leffler 	io[1].iov_len = ETH_ALEN;
103839beb93cSSam Leffler 	io[2].iov_base = (u8 *) buf;
103939beb93cSSam Leffler 	io[2].iov_len = len;
104039beb93cSSam Leffler 
104139beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
104239beb93cSSam Leffler 	msg.msg_iov = io;
104339beb93cSSam Leffler 	msg.msg_iovlen = 3;
104439beb93cSSam Leffler 	msg.msg_name = &iface->drv_addr;
104539beb93cSSam Leffler 	msg.msg_namelen = sizeof(iface->drv_addr);
104639beb93cSSam Leffler 
104739beb93cSSam Leffler 	if (sendmsg(iface->fd, &msg, 0) < 0)
104839beb93cSSam Leffler 		perror("sendmsg(wpas_socket)");
104939beb93cSSam Leffler }
105039beb93cSSam Leffler 
105139beb93cSSam Leffler 
105239beb93cSSam Leffler #ifdef CONFIG_CLIENT_MLME
105339beb93cSSam Leffler void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features,
105439beb93cSSam Leffler 					 size_t num_hw_features)
105539beb93cSSam Leffler {
105639beb93cSSam Leffler 	size_t i;
105739beb93cSSam Leffler 
105839beb93cSSam Leffler 	if (hw_features == NULL)
105939beb93cSSam Leffler 		return;
106039beb93cSSam Leffler 
106139beb93cSSam Leffler 	for (i = 0; i < num_hw_features; i++) {
106239beb93cSSam Leffler 		os_free(hw_features[i].channels);
106339beb93cSSam Leffler 		os_free(hw_features[i].rates);
106439beb93cSSam Leffler 	}
106539beb93cSSam Leffler 
106639beb93cSSam Leffler 	os_free(hw_features);
106739beb93cSSam Leffler }
106839beb93cSSam Leffler 
106939beb93cSSam Leffler 
107039beb93cSSam Leffler void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len,
107139beb93cSSam Leffler 			   struct ieee80211_rx_status *rx_status)
107239beb93cSSam Leffler {
107339beb93cSSam Leffler 	struct wpa_priv_interface *iface = ctx;
107439beb93cSSam Leffler 	struct msghdr msg;
107539beb93cSSam Leffler 	struct iovec io[3];
107639beb93cSSam Leffler 	int event = PRIVSEP_EVENT_STA_RX;
107739beb93cSSam Leffler 
107839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "STA RX from driver");
107939beb93cSSam Leffler 	io[0].iov_base = &event;
108039beb93cSSam Leffler 	io[0].iov_len = sizeof(event);
108139beb93cSSam Leffler 	io[1].iov_base = (u8 *) rx_status;
108239beb93cSSam Leffler 	io[1].iov_len = sizeof(*rx_status);
108339beb93cSSam Leffler 	io[2].iov_base = (u8 *) buf;
108439beb93cSSam Leffler 	io[2].iov_len = len;
108539beb93cSSam Leffler 
108639beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
108739beb93cSSam Leffler 	msg.msg_iov = io;
108839beb93cSSam Leffler 	msg.msg_iovlen = 3;
108939beb93cSSam Leffler 	msg.msg_name = &iface->drv_addr;
109039beb93cSSam Leffler 	msg.msg_namelen = sizeof(iface->drv_addr);
109139beb93cSSam Leffler 
109239beb93cSSam Leffler 	if (sendmsg(iface->fd, &msg, 0) < 0)
109339beb93cSSam Leffler 		perror("sendmsg(wpas_socket)");
109439beb93cSSam Leffler }
109539beb93cSSam Leffler #endif /* CONFIG_CLIENT_MLME */
109639beb93cSSam Leffler 
109739beb93cSSam Leffler 
109839beb93cSSam Leffler static void wpa_priv_terminate(int sig, void *eloop_ctx, void *signal_ctx)
109939beb93cSSam Leffler {
110039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "wpa_priv termination requested");
110139beb93cSSam Leffler 	eloop_terminate();
110239beb93cSSam Leffler }
110339beb93cSSam Leffler 
110439beb93cSSam Leffler 
110539beb93cSSam Leffler static void wpa_priv_fd_workaround(void)
110639beb93cSSam Leffler {
110739beb93cSSam Leffler #ifdef __linux__
110839beb93cSSam Leffler 	int s, i;
110939beb93cSSam Leffler 	/* When started from pcmcia-cs scripts, wpa_supplicant might start with
111039beb93cSSam Leffler 	 * fd 0, 1, and 2 closed. This will cause some issues because many
111139beb93cSSam Leffler 	 * places in wpa_supplicant are still printing out to stdout. As a
111239beb93cSSam Leffler 	 * workaround, make sure that fd's 0, 1, and 2 are not used for other
111339beb93cSSam Leffler 	 * sockets. */
111439beb93cSSam Leffler 	for (i = 0; i < 3; i++) {
111539beb93cSSam Leffler 		s = open("/dev/null", O_RDWR);
111639beb93cSSam Leffler 		if (s > 2) {
111739beb93cSSam Leffler 			close(s);
111839beb93cSSam Leffler 			break;
111939beb93cSSam Leffler 		}
112039beb93cSSam Leffler 	}
112139beb93cSSam Leffler #endif /* __linux__ */
112239beb93cSSam Leffler }
112339beb93cSSam Leffler 
112439beb93cSSam Leffler 
112539beb93cSSam Leffler static void usage(void)
112639beb93cSSam Leffler {
112739beb93cSSam Leffler 	printf("wpa_priv v" VERSION_STR "\n"
112839beb93cSSam Leffler 	       "Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> and "
112939beb93cSSam Leffler 	       "contributors\n"
113039beb93cSSam Leffler 	       "\n"
113139beb93cSSam Leffler 	       "usage:\n"
113239beb93cSSam Leffler 	       "  wpa_priv [-Bdd] [-P<pid file>] <driver:ifname> "
113339beb93cSSam Leffler 	       "[driver:ifname ...]\n");
113439beb93cSSam Leffler }
113539beb93cSSam Leffler 
113639beb93cSSam Leffler 
113739beb93cSSam Leffler extern int wpa_debug_level;
113839beb93cSSam Leffler 
113939beb93cSSam Leffler int main(int argc, char *argv[])
114039beb93cSSam Leffler {
114139beb93cSSam Leffler 	int c, i;
114239beb93cSSam Leffler 	int ret = -1;
114339beb93cSSam Leffler 	char *pid_file = NULL;
114439beb93cSSam Leffler 	int daemonize = 0;
114539beb93cSSam Leffler 	char *ctrl_dir = "/var/run/wpa_priv";
114639beb93cSSam Leffler 	struct wpa_priv_interface *interfaces = NULL, *iface;
114739beb93cSSam Leffler 
114839beb93cSSam Leffler 	if (os_program_init())
114939beb93cSSam Leffler 		return -1;
115039beb93cSSam Leffler 
115139beb93cSSam Leffler 	wpa_priv_fd_workaround();
115239beb93cSSam Leffler 
115339beb93cSSam Leffler 	for (;;) {
115439beb93cSSam Leffler 		c = getopt(argc, argv, "Bc:dP:");
115539beb93cSSam Leffler 		if (c < 0)
115639beb93cSSam Leffler 			break;
115739beb93cSSam Leffler 		switch (c) {
115839beb93cSSam Leffler 		case 'B':
115939beb93cSSam Leffler 			daemonize++;
116039beb93cSSam Leffler 			break;
116139beb93cSSam Leffler 		case 'c':
116239beb93cSSam Leffler 			ctrl_dir = optarg;
116339beb93cSSam Leffler 			break;
116439beb93cSSam Leffler 		case 'd':
116539beb93cSSam Leffler 			wpa_debug_level--;
116639beb93cSSam Leffler 			break;
116739beb93cSSam Leffler 		case 'P':
116839beb93cSSam Leffler 			pid_file = os_rel2abs_path(optarg);
116939beb93cSSam Leffler 			break;
117039beb93cSSam Leffler 		default:
117139beb93cSSam Leffler 			usage();
117239beb93cSSam Leffler 			goto out;
117339beb93cSSam Leffler 		}
117439beb93cSSam Leffler 	}
117539beb93cSSam Leffler 
117639beb93cSSam Leffler 	if (optind >= argc) {
117739beb93cSSam Leffler 		usage();
117839beb93cSSam Leffler 		goto out;
117939beb93cSSam Leffler 	}
118039beb93cSSam Leffler 
118139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "wpa_priv control directory: '%s'", ctrl_dir);
118239beb93cSSam Leffler 
118339beb93cSSam Leffler 	if (eloop_init(NULL)) {
118439beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
118539beb93cSSam Leffler 		goto out;
118639beb93cSSam Leffler 	}
118739beb93cSSam Leffler 
118839beb93cSSam Leffler 	for (i = optind; i < argc; i++) {
118939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
119039beb93cSSam Leffler 		iface = wpa_priv_interface_init(ctrl_dir, argv[i]);
119139beb93cSSam Leffler 		if (iface == NULL)
119239beb93cSSam Leffler 			goto out;
119339beb93cSSam Leffler 		iface->next = interfaces;
119439beb93cSSam Leffler 		interfaces = iface;
119539beb93cSSam Leffler 	}
119639beb93cSSam Leffler 
119739beb93cSSam Leffler 	if (daemonize && os_daemonize(pid_file))
119839beb93cSSam Leffler 		goto out;
119939beb93cSSam Leffler 
120039beb93cSSam Leffler 	eloop_register_signal_terminate(wpa_priv_terminate, NULL);
120139beb93cSSam Leffler 	eloop_run();
120239beb93cSSam Leffler 
120339beb93cSSam Leffler 	ret = 0;
120439beb93cSSam Leffler 
120539beb93cSSam Leffler out:
120639beb93cSSam Leffler 	iface = interfaces;
120739beb93cSSam Leffler 	while (iface) {
120839beb93cSSam Leffler 		struct wpa_priv_interface *prev = iface;
120939beb93cSSam Leffler 		iface = iface->next;
121039beb93cSSam Leffler 		wpa_priv_interface_deinit(prev);
121139beb93cSSam Leffler 	}
121239beb93cSSam Leffler 
121339beb93cSSam Leffler 	eloop_destroy();
121439beb93cSSam Leffler 
121539beb93cSSam Leffler 	os_daemonize_terminate(pid_file);
121639beb93cSSam Leffler 	os_free(pid_file);
121739beb93cSSam Leffler 	os_program_deinit();
121839beb93cSSam Leffler 
121939beb93cSSam Leffler 	return ret;
122039beb93cSSam Leffler }
1221