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(¶ms, 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, ¶ms);
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(¶ms, 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, ¶ms);
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(¶ms, 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, ¶ms);
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