1/*
2 * WPA Supplicant - privilege separated driver interface
3 * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16#include <sys/un.h>
17
18#include "common.h"
19#include "driver.h"
20#include "eloop.h"
21#include "privsep_commands.h"
22
23
24struct wpa_driver_privsep_data {
25	void *ctx;
26	u8 own_addr[ETH_ALEN];
27	int priv_socket;
28	char *own_socket_path;
29	int cmd_socket;
30	char *own_cmd_path;
31	struct sockaddr_un priv_addr;
32	char ifname[16];
33};
34
35
36static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
37{
38	int res;
39
40	res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
41		     (struct sockaddr *) &drv->priv_addr,
42		     sizeof(drv->priv_addr));
43	if (res < 0)
44		perror("sendto");
45	return res < 0 ? -1 : 0;
46}
47
48
49static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
50			const void *data, size_t data_len,
51			void *reply, size_t *reply_len)
52{
53	struct msghdr msg;
54	struct iovec io[2];
55
56	io[0].iov_base = &cmd;
57	io[0].iov_len = sizeof(cmd);
58	io[1].iov_base = (u8 *) data;
59	io[1].iov_len = data_len;
60
61	os_memset(&msg, 0, sizeof(msg));
62	msg.msg_iov = io;
63	msg.msg_iovlen = data ? 2 : 1;
64	msg.msg_name = &drv->priv_addr;
65	msg.msg_namelen = sizeof(drv->priv_addr);
66
67	if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
68		perror("sendmsg(cmd_socket)");
69		return -1;
70	}
71
72	if (reply) {
73		fd_set rfds;
74		struct timeval tv;
75		int res;
76
77		FD_ZERO(&rfds);
78		FD_SET(drv->cmd_socket, &rfds);
79		tv.tv_sec = 5;
80		tv.tv_usec = 0;
81		res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
82		if (res < 0 && errno != EINTR) {
83			perror("select");
84			return -1;
85		}
86
87		if (FD_ISSET(drv->cmd_socket, &rfds)) {
88			res = recv(drv->cmd_socket, reply, *reply_len, 0);
89			if (res < 0) {
90				perror("recv");
91				return -1;
92			}
93			*reply_len = res;
94		} else {
95			wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
96				   "for reply (cmd=%d)", cmd);
97			return -1;
98		}
99	}
100
101	return 0;
102}
103
104
105static int wpa_driver_privsep_set_wpa(void *priv, int enabled)
106{
107	struct wpa_driver_privsep_data *drv = priv;
108	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
109	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_WPA, &enabled,
110			    sizeof(enabled), NULL, NULL);
111}
112
113
114static int wpa_driver_privsep_scan(void *priv, const u8 *ssid, size_t ssid_len)
115{
116	struct wpa_driver_privsep_data *drv = priv;
117	wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
118	return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
119			    NULL, NULL);
120}
121
122
123static struct wpa_scan_results *
124wpa_driver_privsep_get_scan_results2(void *priv)
125{
126	struct wpa_driver_privsep_data *drv = priv;
127	int res, num;
128	u8 *buf, *pos, *end;
129	size_t reply_len = 60000;
130	struct wpa_scan_results *results;
131	struct wpa_scan_res *r;
132
133	buf = os_malloc(reply_len);
134	if (buf == NULL)
135		return NULL;
136	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
137			   NULL, 0, buf, &reply_len);
138	if (res < 0) {
139		os_free(buf);
140		return NULL;
141	}
142
143	wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
144		   (unsigned long) reply_len);
145	if (reply_len < sizeof(int)) {
146		wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
147			   (unsigned long) reply_len);
148		os_free(buf);
149		return NULL;
150	}
151
152	pos = buf;
153	end = buf + reply_len;
154	os_memcpy(&num, pos, sizeof(int));
155	if (num < 0 || num > 1000) {
156		os_free(buf);
157		return NULL;
158	}
159	pos += sizeof(int);
160
161	results = os_zalloc(sizeof(*results));
162	if (results == NULL) {
163		os_free(buf);
164		return NULL;
165	}
166
167	results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
168	if (results->res == NULL) {
169		os_free(results);
170		os_free(buf);
171		return NULL;
172	}
173
174	while (results->num < (size_t) num && pos + sizeof(int) < end) {
175		int len;
176		os_memcpy(&len, pos, sizeof(int));
177		pos += sizeof(int);
178		if (len < 0 || len > 10000 || pos + len > end)
179			break;
180
181		r = os_malloc(len);
182		if (r == NULL)
183			break;
184		os_memcpy(r, pos, len);
185		pos += len;
186		if (sizeof(*r) + r->ie_len > (size_t) len) {
187			os_free(r);
188			break;
189		}
190
191		results->res[results->num++] = r;
192	}
193
194	os_free(buf);
195	return results;
196}
197
198
199static int wpa_driver_privsep_set_key(void *priv, wpa_alg alg, const u8 *addr,
200				   int key_idx, int set_tx,
201				   const u8 *seq, size_t seq_len,
202				   const u8 *key, size_t key_len)
203{
204	struct wpa_driver_privsep_data *drv = priv;
205	struct privsep_cmd_set_key cmd;
206
207	wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
208		   __func__, priv, alg, key_idx, set_tx);
209
210	os_memset(&cmd, 0, sizeof(cmd));
211	cmd.alg = alg;
212	if (addr)
213		os_memcpy(cmd.addr, addr, ETH_ALEN);
214	else
215		os_memset(cmd.addr, 0xff, ETH_ALEN);
216	cmd.key_idx = key_idx;
217	cmd.set_tx = set_tx;
218	if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
219		os_memcpy(cmd.seq, seq, seq_len);
220		cmd.seq_len = seq_len;
221	}
222	if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
223		os_memcpy(cmd.key, key, key_len);
224		cmd.key_len = key_len;
225	}
226
227	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
228			    NULL, NULL);
229}
230
231
232static int wpa_driver_privsep_associate(
233	void *priv, struct wpa_driver_associate_params *params)
234{
235	struct wpa_driver_privsep_data *drv = priv;
236	struct privsep_cmd_associate *data;
237	int res;
238	size_t buflen;
239
240	wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
241		   "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
242		   __func__, priv, params->freq, params->pairwise_suite,
243		   params->group_suite, params->key_mgmt_suite,
244		   params->auth_alg, params->mode);
245
246	buflen = sizeof(*data) + params->wpa_ie_len;
247	data = os_zalloc(buflen);
248	if (data == NULL)
249		return -1;
250
251	if (params->bssid)
252		os_memcpy(data->bssid, params->bssid, ETH_ALEN);
253	os_memcpy(data->ssid, params->ssid, params->ssid_len);
254	data->ssid_len = params->ssid_len;
255	data->freq = params->freq;
256	data->pairwise_suite = params->pairwise_suite;
257	data->group_suite = params->group_suite;
258	data->key_mgmt_suite = params->key_mgmt_suite;
259	data->auth_alg = params->auth_alg;
260	data->mode = params->mode;
261	data->wpa_ie_len = params->wpa_ie_len;
262	if (params->wpa_ie)
263		os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
264	/* TODO: add support for other assoc parameters */
265
266	res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
267			   NULL, NULL);
268	os_free(data);
269
270	return res;
271}
272
273
274static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
275{
276	struct wpa_driver_privsep_data *drv = priv;
277	int res;
278	size_t len = ETH_ALEN;
279
280	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
281	if (res < 0 || len != ETH_ALEN)
282		return -1;
283	return 0;
284}
285
286
287static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
288{
289	struct wpa_driver_privsep_data *drv = priv;
290	int res, ssid_len;
291	u8 reply[sizeof(int) + 32];
292	size_t len = sizeof(reply);
293
294	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
295	if (res < 0 || len < sizeof(int))
296		return -1;
297	os_memcpy(&ssid_len, reply, sizeof(int));
298	if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
299		wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
300		return -1;
301	}
302	os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
303	return ssid_len;
304}
305
306
307static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
308					  int reason_code)
309{
310	//struct wpa_driver_privsep_data *drv = priv;
311	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
312		   __func__, MAC2STR(addr), reason_code);
313	wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
314	return 0;
315}
316
317
318static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
319					int reason_code)
320{
321	//struct wpa_driver_privsep_data *drv = priv;
322	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
323		   __func__, MAC2STR(addr), reason_code);
324	wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
325	return 0;
326}
327
328
329static void wpa_driver_privsep_event_assoc(void *ctx, wpa_event_type event,
330					   u8 *buf, size_t len)
331{
332	union wpa_event_data data;
333	int inc_data = 0;
334	u8 *pos, *end;
335	int ie_len;
336
337	os_memset(&data, 0, sizeof(data));
338
339	pos = buf;
340	end = buf + len;
341
342	if (end - pos < (int) sizeof(int))
343		return;
344	os_memcpy(&ie_len, pos, sizeof(int));
345	pos += sizeof(int);
346	if (ie_len < 0 || ie_len > end - pos)
347		return;
348	if (ie_len) {
349		data.assoc_info.req_ies = pos;
350		data.assoc_info.req_ies_len = ie_len;
351		pos += ie_len;
352		inc_data = 1;
353	}
354
355	wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
356}
357
358
359static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
360						      size_t len)
361{
362	union wpa_event_data data;
363	int ievent;
364
365	if (len < sizeof(int) ||
366	    len - sizeof(int) > sizeof(data.interface_status.ifname))
367		return;
368
369	os_memcpy(&ievent, buf, sizeof(int));
370
371	os_memset(&data, 0, sizeof(data));
372	data.interface_status.ievent = ievent;
373	os_memcpy(data.interface_status.ifname, buf + sizeof(int),
374		  len - sizeof(int));
375	wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
376}
377
378
379static void wpa_driver_privsep_event_michael_mic_failure(
380	void *ctx, u8 *buf, size_t len)
381{
382	union wpa_event_data data;
383
384	if (len != sizeof(int))
385		return;
386
387	os_memset(&data, 0, sizeof(data));
388	os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
389	wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
390}
391
392
393static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
394						     size_t len)
395{
396	union wpa_event_data data;
397
398	if (len != sizeof(struct pmkid_candidate))
399		return;
400
401	os_memset(&data, 0, sizeof(data));
402	os_memcpy(&data.pmkid_candidate, buf, len);
403	wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
404}
405
406
407static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
408{
409	union wpa_event_data data;
410
411	if (len != ETH_ALEN)
412		return;
413
414	os_memset(&data, 0, sizeof(data));
415	os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
416	wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
417}
418
419
420static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
421						 size_t len)
422{
423	union wpa_event_data data;
424
425	if (len < sizeof(int) + ETH_ALEN)
426		return;
427
428	os_memset(&data, 0, sizeof(data));
429	os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
430	os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
431	data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
432	data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
433	wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
434}
435
436
437static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
438{
439	if (len < ETH_ALEN)
440		return;
441
442	wpa_supplicant_rx_eapol(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
443}
444
445
446static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len)
447{
448#ifdef CONFIG_CLIENT_MLME
449	struct ieee80211_rx_status *rx_status;
450
451	if (len < sizeof(*rx_status))
452		return;
453	rx_status = (struct ieee80211_rx_status *) buf;
454	buf += sizeof(*rx_status);
455	len -= sizeof(*rx_status);
456
457	wpa_supplicant_sta_rx(ctx, buf, len, rx_status);
458#endif /* CONFIG_CLIENT_MLME */
459}
460
461
462static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
463				       void *sock_ctx)
464{
465	struct wpa_driver_privsep_data *drv = eloop_ctx;
466	u8 *buf, *event_buf;
467	size_t event_len;
468	int res, event;
469	enum privsep_event e;
470	struct sockaddr_un from;
471	socklen_t fromlen = sizeof(from);
472	const size_t buflen = 2000;
473
474	buf = os_malloc(buflen);
475	if (buf == NULL)
476		return;
477	res = recvfrom(sock, buf, buflen, 0,
478		       (struct sockaddr *) &from, &fromlen);
479	if (res < 0) {
480		perror("recvfrom(priv_socket)");
481		os_free(buf);
482		return;
483	}
484
485	wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
486
487	if (res < (int) sizeof(int)) {
488		wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
489		return;
490	}
491
492	os_memcpy(&event, buf, sizeof(int));
493	event_buf = &buf[sizeof(int)];
494	event_len = res - sizeof(int);
495	wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
496		   event, (unsigned long) event_len);
497
498	e = event;
499	switch (e) {
500	case PRIVSEP_EVENT_SCAN_RESULTS:
501		wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
502		break;
503	case PRIVSEP_EVENT_ASSOC:
504		wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
505					       event_buf, event_len);
506		break;
507	case PRIVSEP_EVENT_DISASSOC:
508		wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
509		break;
510	case PRIVSEP_EVENT_ASSOCINFO:
511		wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
512					       event_buf, event_len);
513		break;
514	case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
515		wpa_driver_privsep_event_michael_mic_failure(
516			drv->ctx, event_buf, event_len);
517		break;
518	case PRIVSEP_EVENT_INTERFACE_STATUS:
519		wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
520							  event_len);
521		break;
522	case PRIVSEP_EVENT_PMKID_CANDIDATE:
523		wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
524							 event_len);
525		break;
526	case PRIVSEP_EVENT_STKSTART:
527		wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
528						  event_len);
529		break;
530	case PRIVSEP_EVENT_FT_RESPONSE:
531		wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
532						     event_len);
533		break;
534	case PRIVSEP_EVENT_RX_EAPOL:
535		wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
536						  event_len);
537		break;
538	case PRIVSEP_EVENT_STA_RX:
539		wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf,
540						event_len);
541		break;
542	}
543
544	os_free(buf);
545}
546
547
548static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
549{
550	struct wpa_driver_privsep_data *drv;
551
552	drv = os_zalloc(sizeof(*drv));
553	if (drv == NULL)
554		return NULL;
555	drv->ctx = ctx;
556	drv->priv_socket = -1;
557	drv->cmd_socket = -1;
558	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
559
560	return drv;
561}
562
563
564static void wpa_driver_privsep_deinit(void *priv)
565{
566	struct wpa_driver_privsep_data *drv = priv;
567
568	if (drv->priv_socket >= 0) {
569		wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
570		eloop_unregister_read_sock(drv->priv_socket);
571		close(drv->priv_socket);
572	}
573
574	if (drv->own_socket_path) {
575		unlink(drv->own_socket_path);
576		os_free(drv->own_socket_path);
577	}
578
579	if (drv->cmd_socket >= 0) {
580		eloop_unregister_read_sock(drv->cmd_socket);
581		close(drv->cmd_socket);
582	}
583
584	if (drv->own_cmd_path) {
585		unlink(drv->own_cmd_path);
586		os_free(drv->own_cmd_path);
587	}
588
589	os_free(drv);
590}
591
592
593static int wpa_driver_privsep_set_param(void *priv, const char *param)
594{
595	struct wpa_driver_privsep_data *drv = priv;
596	const char *pos;
597	char *own_dir, *priv_dir;
598	static unsigned int counter = 0;
599	size_t len;
600	struct sockaddr_un addr;
601
602	wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
603	if (param == NULL)
604		pos = NULL;
605	else
606		pos = os_strstr(param, "own_dir=");
607	if (pos) {
608		char *end;
609		own_dir = os_strdup(pos + 8);
610		if (own_dir == NULL)
611			return -1;
612		end = os_strchr(own_dir, ' ');
613		if (end)
614			*end = '\0';
615	} else {
616		own_dir = os_strdup("/tmp");
617		if (own_dir == NULL)
618			return -1;
619	}
620
621	if (param == NULL)
622		pos = NULL;
623	else
624		pos = os_strstr(param, "priv_dir=");
625	if (pos) {
626		char *end;
627		priv_dir = os_strdup(pos + 9);
628		if (priv_dir == NULL) {
629			os_free(own_dir);
630			return -1;
631		}
632		end = os_strchr(priv_dir, ' ');
633		if (end)
634			*end = '\0';
635	} else {
636		priv_dir = os_strdup("/var/run/wpa_priv");
637		if (priv_dir == NULL) {
638			os_free(own_dir);
639			return -1;
640		}
641	}
642
643	len = os_strlen(own_dir) + 50;
644	drv->own_socket_path = os_malloc(len);
645	if (drv->own_socket_path == NULL) {
646		os_free(priv_dir);
647		os_free(own_dir);
648		return -1;
649	}
650	os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
651		    own_dir, getpid(), counter++);
652
653	len = os_strlen(own_dir) + 50;
654	drv->own_cmd_path = os_malloc(len);
655	if (drv->own_cmd_path == NULL) {
656		os_free(drv->own_socket_path);
657		drv->own_socket_path = NULL;
658		os_free(priv_dir);
659		os_free(own_dir);
660		return -1;
661	}
662	os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
663		    own_dir, getpid(), counter++);
664
665	os_free(own_dir);
666
667	drv->priv_addr.sun_family = AF_UNIX;
668	os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
669		    "%s/%s", priv_dir, drv->ifname);
670	os_free(priv_dir);
671
672	drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
673	if (drv->priv_socket < 0) {
674		perror("socket(PF_UNIX)");
675		os_free(drv->own_socket_path);
676		drv->own_socket_path = NULL;
677		return -1;
678	}
679
680	os_memset(&addr, 0, sizeof(addr));
681	addr.sun_family = AF_UNIX;
682	os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
683	if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
684	    0) {
685		perror("bind(PF_UNIX)");
686		close(drv->priv_socket);
687		drv->priv_socket = -1;
688		unlink(drv->own_socket_path);
689		os_free(drv->own_socket_path);
690		drv->own_socket_path = NULL;
691		return -1;
692	}
693
694	eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
695				 drv, NULL);
696
697	drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
698	if (drv->cmd_socket < 0) {
699		perror("socket(PF_UNIX)");
700		os_free(drv->own_cmd_path);
701		drv->own_cmd_path = NULL;
702		return -1;
703	}
704
705	os_memset(&addr, 0, sizeof(addr));
706	addr.sun_family = AF_UNIX;
707	os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
708	if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
709	{
710		perror("bind(PF_UNIX)");
711		close(drv->cmd_socket);
712		drv->cmd_socket = -1;
713		unlink(drv->own_cmd_path);
714		os_free(drv->own_cmd_path);
715		drv->own_cmd_path = NULL;
716		return -1;
717	}
718
719	if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
720		wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
721		return -1;
722	}
723
724	return 0;
725}
726
727
728static int wpa_driver_privsep_get_capa(void *priv,
729				       struct wpa_driver_capa *capa)
730{
731	struct wpa_driver_privsep_data *drv = priv;
732	int res;
733	size_t len = sizeof(*capa);
734
735	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
736	if (res < 0 || len != sizeof(*capa))
737		return -1;
738	return 0;
739}
740
741
742static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
743{
744	struct wpa_driver_privsep_data *drv = priv;
745	wpa_printf(MSG_DEBUG, "%s", __func__);
746	return drv->own_addr;
747}
748
749
750static int wpa_driver_privsep_set_mode(void *priv, int mode)
751{
752	struct wpa_driver_privsep_data *drv = priv;
753	wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode);
754	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode),
755			    NULL, NULL);
756}
757
758
759static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
760{
761	struct wpa_driver_privsep_data *drv = priv;
762	wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
763	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
764			    os_strlen(alpha2), NULL, NULL);
765}
766
767
768struct wpa_driver_ops wpa_driver_privsep_ops = {
769	"privsep",
770	"wpa_supplicant privilege separated driver",
771	wpa_driver_privsep_get_bssid,
772	wpa_driver_privsep_get_ssid,
773	wpa_driver_privsep_set_wpa,
774	wpa_driver_privsep_set_key,
775	wpa_driver_privsep_init,
776	wpa_driver_privsep_deinit,
777	wpa_driver_privsep_set_param,
778	NULL /* set_countermeasures */,
779	NULL /* set_drop_unencrypted */,
780	wpa_driver_privsep_scan,
781	NULL /*  get_scan_results */,
782	wpa_driver_privsep_deauthenticate,
783	wpa_driver_privsep_disassociate,
784	wpa_driver_privsep_associate,
785	NULL /* set_auth_alg */,
786	NULL /* add_pmkid */,
787	NULL /* remove_pmkid */,
788	NULL /* flush_pmkid */,
789	wpa_driver_privsep_get_capa,
790	NULL /* poll */,
791	NULL /* get_ifname */,
792	wpa_driver_privsep_get_mac_addr,
793	NULL /* send_eapol */,
794	NULL /* set_operstate */,
795	NULL /* mlme_setprotection */,
796	NULL /* get_hw_feature_data */,
797	NULL /* set_channel */,
798	NULL /* set_ssid */,
799	NULL /* set_bssid */,
800	NULL /* send_mlme */,
801	NULL /* mlme_add_sta */,
802	NULL /* mlme_remove_sta */,
803	NULL /* update_ft_ies */,
804	NULL /* send_ft_action */,
805	wpa_driver_privsep_get_scan_results2,
806	NULL /* set_probe_req_ie */,
807	wpa_driver_privsep_set_mode,
808	wpa_driver_privsep_set_country,
809	NULL /* global_init */,
810	NULL /* global_deinit */,
811	NULL /* init2 */,
812	NULL /* get_interfaces */
813};
814
815
816struct wpa_driver_ops *wpa_supplicant_drivers[] =
817{
818	&wpa_driver_privsep_ops,
819	NULL
820};
821