xref: /freebsd/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA Supplicant / UNIX domain socket -based control interface
3c1d255d3SCy Schubert  * Copyright (c) 2004-2020, 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 #include <sys/un.h>
1139beb93cSSam Leffler #include <sys/stat.h>
1239beb93cSSam Leffler #include <grp.h>
13470736a0SSam Leffler #include <stddef.h>
14f05cddf9SRui Paulo #include <unistd.h>
15f05cddf9SRui Paulo #include <fcntl.h>
16325151a3SRui Paulo #ifdef __linux__
17325151a3SRui Paulo #include <sys/ioctl.h>
18325151a3SRui Paulo #endif /* __linux__ */
19f05cddf9SRui Paulo #ifdef ANDROID
20f05cddf9SRui Paulo #include <cutils/sockets.h>
21f05cddf9SRui Paulo #endif /* ANDROID */
2239beb93cSSam Leffler 
23e28a4053SRui Paulo #include "utils/common.h"
24e28a4053SRui Paulo #include "utils/eloop.h"
25e28a4053SRui Paulo #include "utils/list.h"
26780fb4a2SCy Schubert #include "common/ctrl_iface_common.h"
2739beb93cSSam Leffler #include "eapol_supp/eapol_supp_sm.h"
28e28a4053SRui Paulo #include "config.h"
2939beb93cSSam Leffler #include "wpa_supplicant_i.h"
3039beb93cSSam Leffler #include "ctrl_iface.h"
3139beb93cSSam Leffler 
3239beb93cSSam Leffler /* Per-interface ctrl_iface */
3339beb93cSSam Leffler 
3439beb93cSSam Leffler struct ctrl_iface_priv {
3539beb93cSSam Leffler 	struct wpa_supplicant *wpa_s;
3639beb93cSSam Leffler 	int sock;
37e28a4053SRui Paulo 	struct dl_list ctrl_dst;
385b9c547cSRui Paulo 	int android_control_socket;
39780fb4a2SCy Schubert 	struct dl_list msg_queue;
40780fb4a2SCy Schubert 	unsigned int throttle_count;
4139beb93cSSam Leffler };
4239beb93cSSam Leffler 
4339beb93cSSam Leffler 
445b9c547cSRui Paulo struct ctrl_iface_global_priv {
455b9c547cSRui Paulo 	struct wpa_global *global;
465b9c547cSRui Paulo 	int sock;
475b9c547cSRui Paulo 	struct dl_list ctrl_dst;
485b9c547cSRui Paulo 	int android_control_socket;
49780fb4a2SCy Schubert 	struct dl_list msg_queue;
50780fb4a2SCy Schubert 	unsigned int throttle_count;
51780fb4a2SCy Schubert };
52780fb4a2SCy Schubert 
53780fb4a2SCy Schubert struct ctrl_iface_msg {
54780fb4a2SCy Schubert 	struct dl_list list;
55780fb4a2SCy Schubert 	struct wpa_supplicant *wpa_s;
56780fb4a2SCy Schubert 	int level;
57780fb4a2SCy Schubert 	enum wpa_msg_type type;
58780fb4a2SCy Schubert 	const char *txt;
59780fb4a2SCy Schubert 	size_t len;
605b9c547cSRui Paulo };
615b9c547cSRui Paulo 
625b9c547cSRui Paulo 
635b9c547cSRui Paulo static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
645b9c547cSRui Paulo 					   const char *ifname, int sock,
655b9c547cSRui Paulo 					   struct dl_list *ctrl_dst,
6639beb93cSSam Leffler 					   int level, const char *buf,
675b9c547cSRui Paulo 					   size_t len,
685b9c547cSRui Paulo 					   struct ctrl_iface_priv *priv,
695b9c547cSRui Paulo 					   struct ctrl_iface_global_priv *gp);
705b9c547cSRui Paulo static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
715b9c547cSRui Paulo 				  struct ctrl_iface_priv *priv);
725b9c547cSRui Paulo static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
735b9c547cSRui Paulo 					 struct ctrl_iface_global_priv *priv);
7439beb93cSSam Leffler 
7539beb93cSSam Leffler 
wpas_ctrl_sock_debug(const char * title,int sock,const char * buf,size_t len)76325151a3SRui Paulo static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
77325151a3SRui Paulo 				 size_t len)
78325151a3SRui Paulo {
79325151a3SRui Paulo #ifdef __linux__
80325151a3SRui Paulo 	socklen_t optlen;
81325151a3SRui Paulo 	int sndbuf, outq;
82325151a3SRui Paulo 	int level = MSG_MSGDUMP;
83325151a3SRui Paulo 
84325151a3SRui Paulo 	if (len >= 5 && os_strncmp(buf, "PONG\n", 5) == 0)
85325151a3SRui Paulo 		level = MSG_EXCESSIVE;
86325151a3SRui Paulo 
87325151a3SRui Paulo 	optlen = sizeof(sndbuf);
88325151a3SRui Paulo 	sndbuf = 0;
89325151a3SRui Paulo 	if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
90325151a3SRui Paulo 		sndbuf = -1;
91325151a3SRui Paulo 
92780fb4a2SCy Schubert 	if (ioctl(sock, TIOCOUTQ, &outq) < 0)
93325151a3SRui Paulo 		outq = -1;
94325151a3SRui Paulo 
95325151a3SRui Paulo 	wpa_printf(level,
96325151a3SRui Paulo 		   "CTRL-DEBUG: %s: sock=%d sndbuf=%d outq=%d send_len=%d",
97325151a3SRui Paulo 		   title, sock, sndbuf, outq, (int) len);
98325151a3SRui Paulo #endif /* __linux__ */
99325151a3SRui Paulo }
100325151a3SRui Paulo 
101325151a3SRui Paulo 
wpa_supplicant_ctrl_iface_attach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen,int global)1025b9c547cSRui Paulo static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
103780fb4a2SCy Schubert 					    struct sockaddr_storage *from,
1045b9c547cSRui Paulo 					    socklen_t fromlen, int global)
10539beb93cSSam Leffler {
10685732ac8SCy Schubert 	return ctrl_iface_attach(ctrl_dst, from, fromlen, NULL);
10739beb93cSSam Leffler }
10839beb93cSSam Leffler 
10939beb93cSSam Leffler 
wpa_supplicant_ctrl_iface_detach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen)1105b9c547cSRui Paulo static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
111780fb4a2SCy Schubert 					    struct sockaddr_storage *from,
11239beb93cSSam Leffler 					    socklen_t fromlen)
11339beb93cSSam Leffler {
114780fb4a2SCy Schubert 	return ctrl_iface_detach(ctrl_dst, from, fromlen);
11539beb93cSSam Leffler }
11639beb93cSSam Leffler 
11739beb93cSSam Leffler 
wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv * priv,struct sockaddr_storage * from,socklen_t fromlen,char * level)11839beb93cSSam Leffler static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
119780fb4a2SCy Schubert 					   struct sockaddr_storage *from,
12039beb93cSSam Leffler 					   socklen_t fromlen,
12139beb93cSSam Leffler 					   char *level)
12239beb93cSSam Leffler {
12339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
12439beb93cSSam Leffler 
125780fb4a2SCy Schubert 	return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level);
12639beb93cSSam Leffler }
12739beb93cSSam Leffler 
12839beb93cSSam Leffler 
wpa_supplicant_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)12939beb93cSSam Leffler static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
13039beb93cSSam Leffler 					      void *sock_ctx)
13139beb93cSSam Leffler {
13239beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = eloop_ctx;
13339beb93cSSam Leffler 	struct ctrl_iface_priv *priv = sock_ctx;
134c1d255d3SCy Schubert 	char *buf;
13539beb93cSSam Leffler 	int res;
136780fb4a2SCy Schubert 	struct sockaddr_storage from;
13739beb93cSSam Leffler 	socklen_t fromlen = sizeof(from);
1385b9c547cSRui Paulo 	char *reply = NULL, *reply_buf = NULL;
13939beb93cSSam Leffler 	size_t reply_len = 0;
14039beb93cSSam Leffler 	int new_attached = 0;
14139beb93cSSam Leffler 
142c1d255d3SCy Schubert 	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
143c1d255d3SCy Schubert 	if (!buf)
144c1d255d3SCy Schubert 		return;
145c1d255d3SCy Schubert 	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
14639beb93cSSam Leffler 		       (struct sockaddr *) &from, &fromlen);
14739beb93cSSam Leffler 	if (res < 0) {
1485b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
1495b9c547cSRui Paulo 			   strerror(errno));
150c1d255d3SCy Schubert 		os_free(buf);
151c1d255d3SCy Schubert 		return;
152c1d255d3SCy Schubert 	}
153c1d255d3SCy Schubert 	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
154c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
155c1d255d3SCy Schubert 		os_free(buf);
15639beb93cSSam Leffler 		return;
15739beb93cSSam Leffler 	}
15839beb93cSSam Leffler 	buf[res] = '\0';
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 	if (os_strcmp(buf, "ATTACH") == 0) {
1615b9c547cSRui Paulo 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
1625b9c547cSRui Paulo 						     fromlen, 0))
16339beb93cSSam Leffler 			reply_len = 1;
16439beb93cSSam Leffler 		else {
16539beb93cSSam Leffler 			new_attached = 1;
16639beb93cSSam Leffler 			reply_len = 2;
16739beb93cSSam Leffler 		}
16839beb93cSSam Leffler 	} else if (os_strcmp(buf, "DETACH") == 0) {
1695b9c547cSRui Paulo 		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
1705b9c547cSRui Paulo 						     fromlen))
17139beb93cSSam Leffler 			reply_len = 1;
17239beb93cSSam Leffler 		else
17339beb93cSSam Leffler 			reply_len = 2;
17439beb93cSSam Leffler 	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
17539beb93cSSam Leffler 		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
17639beb93cSSam Leffler 						    buf + 6))
17739beb93cSSam Leffler 			reply_len = 1;
17839beb93cSSam Leffler 		else
17939beb93cSSam Leffler 			reply_len = 2;
18039beb93cSSam Leffler 	} else {
181*a90b9d01SCy Schubert 		sockaddr_print(wpas_ctrl_cmd_debug_level(buf),
182*a90b9d01SCy Schubert 			       "Control interface recv command from:",
183*a90b9d01SCy Schubert 			       &from, fromlen);
1845b9c547cSRui Paulo 		reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
18539beb93cSSam Leffler 							      &reply_len);
1865b9c547cSRui Paulo 		reply = reply_buf;
187325151a3SRui Paulo 
188325151a3SRui Paulo 		/*
189325151a3SRui Paulo 		 * There could be some password/key material in the command, so
190325151a3SRui Paulo 		 * clear the buffer explicitly now that it is not needed
191325151a3SRui Paulo 		 * anymore.
192325151a3SRui Paulo 		 */
193325151a3SRui Paulo 		os_memset(buf, 0, res);
1945b9c547cSRui Paulo 	}
1955b9c547cSRui Paulo 
1965b9c547cSRui Paulo 	if (!reply && reply_len == 1) {
1975b9c547cSRui Paulo 		reply = "FAIL\n";
1985b9c547cSRui Paulo 		reply_len = 5;
1995b9c547cSRui Paulo 	} else if (!reply && reply_len == 2) {
2005b9c547cSRui Paulo 		reply = "OK\n";
2015b9c547cSRui Paulo 		reply_len = 3;
20239beb93cSSam Leffler 	}
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 	if (reply) {
205325151a3SRui Paulo 		wpas_ctrl_sock_debug("ctrl_sock-sendto", sock, reply,
206325151a3SRui Paulo 				     reply_len);
2075b9c547cSRui Paulo 		if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
2085b9c547cSRui Paulo 			   fromlen) < 0) {
2095b9c547cSRui Paulo 			int _errno = errno;
2105b9c547cSRui Paulo 			wpa_dbg(wpa_s, MSG_DEBUG,
2115b9c547cSRui Paulo 				"ctrl_iface sendto failed: %d - %s",
2125b9c547cSRui Paulo 				_errno, strerror(_errno));
2135b9c547cSRui Paulo 			if (_errno == ENOBUFS || _errno == EAGAIN) {
2145b9c547cSRui Paulo 				/*
2155b9c547cSRui Paulo 				 * The socket send buffer could be full. This
2165b9c547cSRui Paulo 				 * may happen if client programs are not
2175b9c547cSRui Paulo 				 * receiving their pending messages. Close and
2185b9c547cSRui Paulo 				 * reopen the socket as a workaround to avoid
2195b9c547cSRui Paulo 				 * getting stuck being unable to send any new
2205b9c547cSRui Paulo 				 * responses.
2215b9c547cSRui Paulo 				 */
2225b9c547cSRui Paulo 				sock = wpas_ctrl_iface_reinit(wpa_s, priv);
2235b9c547cSRui Paulo 				if (sock < 0) {
2245b9c547cSRui Paulo 					wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
22539beb93cSSam Leffler 				}
2265b9c547cSRui Paulo 			}
2275b9c547cSRui Paulo 			if (new_attached) {
2285b9c547cSRui Paulo 				wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
2295b9c547cSRui Paulo 				new_attached = 0;
2305b9c547cSRui Paulo 				wpa_supplicant_ctrl_iface_detach(
2315b9c547cSRui Paulo 					&priv->ctrl_dst, &from, fromlen);
2325b9c547cSRui Paulo 			}
2335b9c547cSRui Paulo 		}
2345b9c547cSRui Paulo 	}
2355b9c547cSRui Paulo 	os_free(reply_buf);
236c1d255d3SCy Schubert 	os_free(buf);
23739beb93cSSam Leffler 
23839beb93cSSam Leffler 	if (new_attached)
23939beb93cSSam Leffler 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
24039beb93cSSam Leffler }
24139beb93cSSam Leffler 
24239beb93cSSam Leffler 
wpa_supplicant_ctrl_iface_path(struct wpa_supplicant * wpa_s)24339beb93cSSam Leffler static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
24439beb93cSSam Leffler {
24539beb93cSSam Leffler 	char *buf;
24639beb93cSSam Leffler 	size_t len;
2475b9c547cSRui Paulo 	char *pbuf, *dir = NULL;
24839beb93cSSam Leffler 	int res;
24939beb93cSSam Leffler 
25039beb93cSSam Leffler 	if (wpa_s->conf->ctrl_interface == NULL)
25139beb93cSSam Leffler 		return NULL;
25239beb93cSSam Leffler 
25339beb93cSSam Leffler 	pbuf = os_strdup(wpa_s->conf->ctrl_interface);
25439beb93cSSam Leffler 	if (pbuf == NULL)
25539beb93cSSam Leffler 		return NULL;
25639beb93cSSam Leffler 	if (os_strncmp(pbuf, "DIR=", 4) == 0) {
2575b9c547cSRui Paulo 		char *gid_str;
25839beb93cSSam Leffler 		dir = pbuf + 4;
25939beb93cSSam Leffler 		gid_str = os_strstr(dir, " GROUP=");
2605b9c547cSRui Paulo 		if (gid_str)
26139beb93cSSam Leffler 			*gid_str = '\0';
26239beb93cSSam Leffler 	} else
26339beb93cSSam Leffler 		dir = pbuf;
26439beb93cSSam Leffler 
26539beb93cSSam Leffler 	len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
26639beb93cSSam Leffler 	buf = os_malloc(len);
26739beb93cSSam Leffler 	if (buf == NULL) {
26839beb93cSSam Leffler 		os_free(pbuf);
26939beb93cSSam Leffler 		return NULL;
27039beb93cSSam Leffler 	}
27139beb93cSSam Leffler 
27239beb93cSSam Leffler 	res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
2735b9c547cSRui Paulo 	if (os_snprintf_error(len, res)) {
27439beb93cSSam Leffler 		os_free(pbuf);
27539beb93cSSam Leffler 		os_free(buf);
27639beb93cSSam Leffler 		return NULL;
27739beb93cSSam Leffler 	}
27839beb93cSSam Leffler #ifdef __CYGWIN__
27939beb93cSSam Leffler 	{
28039beb93cSSam Leffler 		/* Windows/WinPcap uses interface names that are not suitable
28139beb93cSSam Leffler 		 * as a file name - convert invalid chars to underscores */
28239beb93cSSam Leffler 		char *pos = buf;
28339beb93cSSam Leffler 		while (*pos) {
28439beb93cSSam Leffler 			if (*pos == '\\')
28539beb93cSSam Leffler 				*pos = '_';
28639beb93cSSam Leffler 			pos++;
28739beb93cSSam Leffler 		}
28839beb93cSSam Leffler 	}
28939beb93cSSam Leffler #endif /* __CYGWIN__ */
29039beb93cSSam Leffler 	os_free(pbuf);
29139beb93cSSam Leffler 	return buf;
29239beb93cSSam Leffler }
29339beb93cSSam Leffler 
29439beb93cSSam Leffler 
wpas_ctrl_iface_throttle(int sock)295780fb4a2SCy Schubert static int wpas_ctrl_iface_throttle(int sock)
296780fb4a2SCy Schubert {
297780fb4a2SCy Schubert #ifdef __linux__
298780fb4a2SCy Schubert 	socklen_t optlen;
299780fb4a2SCy Schubert 	int sndbuf, outq;
300780fb4a2SCy Schubert 
301780fb4a2SCy Schubert 	optlen = sizeof(sndbuf);
302780fb4a2SCy Schubert 	sndbuf = 0;
303780fb4a2SCy Schubert 	if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 ||
304780fb4a2SCy Schubert 	    ioctl(sock, TIOCOUTQ, &outq) < 0 ||
305780fb4a2SCy Schubert 	    sndbuf <= 0 || outq < 0)
306780fb4a2SCy Schubert 		return 0;
307780fb4a2SCy Schubert 	return outq > sndbuf / 2;
308780fb4a2SCy Schubert #else /* __linux__ */
309780fb4a2SCy Schubert 	return 0;
310780fb4a2SCy Schubert #endif /* __linux__ */
311780fb4a2SCy Schubert }
312780fb4a2SCy Schubert 
313780fb4a2SCy Schubert 
wpas_ctrl_msg_send_pending_global(struct wpa_global * global)314780fb4a2SCy Schubert static void wpas_ctrl_msg_send_pending_global(struct wpa_global *global)
315780fb4a2SCy Schubert {
316780fb4a2SCy Schubert 	struct ctrl_iface_global_priv *gpriv;
317780fb4a2SCy Schubert 	struct ctrl_iface_msg *msg;
318780fb4a2SCy Schubert 
319780fb4a2SCy Schubert 	gpriv = global->ctrl_iface;
320780fb4a2SCy Schubert 	while (gpriv && !dl_list_empty(&gpriv->msg_queue) &&
321780fb4a2SCy Schubert 	       !wpas_ctrl_iface_throttle(gpriv->sock)) {
322780fb4a2SCy Schubert 		msg = dl_list_first(&gpriv->msg_queue, struct ctrl_iface_msg,
323780fb4a2SCy Schubert 				    list);
324780fb4a2SCy Schubert 		if (!msg)
325780fb4a2SCy Schubert 			break;
326780fb4a2SCy Schubert 		dl_list_del(&msg->list);
327780fb4a2SCy Schubert 		wpa_supplicant_ctrl_iface_send(
328780fb4a2SCy Schubert 			msg->wpa_s,
329780fb4a2SCy Schubert 			msg->type != WPA_MSG_PER_INTERFACE ?
330780fb4a2SCy Schubert 			NULL : msg->wpa_s->ifname,
331780fb4a2SCy Schubert 			gpriv->sock, &gpriv->ctrl_dst, msg->level,
332780fb4a2SCy Schubert 			msg->txt, msg->len, NULL, gpriv);
333780fb4a2SCy Schubert 		os_free(msg);
334780fb4a2SCy Schubert 	}
335780fb4a2SCy Schubert }
336780fb4a2SCy Schubert 
337780fb4a2SCy Schubert 
wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant * wpa_s)338780fb4a2SCy Schubert static void wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant *wpa_s)
339780fb4a2SCy Schubert {
340780fb4a2SCy Schubert 	struct ctrl_iface_priv *priv;
341780fb4a2SCy Schubert 	struct ctrl_iface_msg *msg;
342780fb4a2SCy Schubert 
343780fb4a2SCy Schubert 	priv = wpa_s->ctrl_iface;
344780fb4a2SCy Schubert 	while (priv && !dl_list_empty(&priv->msg_queue) &&
345780fb4a2SCy Schubert 	       !wpas_ctrl_iface_throttle(priv->sock)) {
346780fb4a2SCy Schubert 		msg = dl_list_first(&priv->msg_queue, struct ctrl_iface_msg,
347780fb4a2SCy Schubert 				    list);
348780fb4a2SCy Schubert 		if (!msg)
349780fb4a2SCy Schubert 			break;
350780fb4a2SCy Schubert 		dl_list_del(&msg->list);
351780fb4a2SCy Schubert 		wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
352780fb4a2SCy Schubert 					       &priv->ctrl_dst, msg->level,
353780fb4a2SCy Schubert 					       msg->txt, msg->len, priv, NULL);
354780fb4a2SCy Schubert 		os_free(msg);
355780fb4a2SCy Schubert 	}
356780fb4a2SCy Schubert }
357780fb4a2SCy Schubert 
358780fb4a2SCy Schubert 
wpas_ctrl_msg_queue_timeout(void * eloop_ctx,void * timeout_ctx)359780fb4a2SCy Schubert static void wpas_ctrl_msg_queue_timeout(void *eloop_ctx, void *timeout_ctx)
360780fb4a2SCy Schubert {
361780fb4a2SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
362780fb4a2SCy Schubert 	struct ctrl_iface_priv *priv;
363780fb4a2SCy Schubert 	struct ctrl_iface_global_priv *gpriv;
364780fb4a2SCy Schubert 	int sock = -1, gsock = -1;
365780fb4a2SCy Schubert 
366780fb4a2SCy Schubert 	wpas_ctrl_msg_send_pending_global(wpa_s->global);
367780fb4a2SCy Schubert 	wpas_ctrl_msg_send_pending_iface(wpa_s);
368780fb4a2SCy Schubert 
369780fb4a2SCy Schubert 	priv = wpa_s->ctrl_iface;
370780fb4a2SCy Schubert 	if (priv && !dl_list_empty(&priv->msg_queue))
371780fb4a2SCy Schubert 		sock = priv->sock;
372780fb4a2SCy Schubert 
373780fb4a2SCy Schubert 	gpriv = wpa_s->global->ctrl_iface;
374780fb4a2SCy Schubert 	if (gpriv && !dl_list_empty(&gpriv->msg_queue))
375780fb4a2SCy Schubert 		gsock = gpriv->sock;
376780fb4a2SCy Schubert 
377780fb4a2SCy Schubert 	if (sock > -1 || gsock > -1) {
378780fb4a2SCy Schubert 		/* Continue pending message transmission from a timeout */
379780fb4a2SCy Schubert 		wpa_printf(MSG_MSGDUMP,
380780fb4a2SCy Schubert 			   "CTRL: Had to throttle pending event message transmission for (sock %d gsock %d)",
381780fb4a2SCy Schubert 			   sock, gsock);
382780fb4a2SCy Schubert 		eloop_register_timeout(0, 20000, wpas_ctrl_msg_queue_timeout,
383780fb4a2SCy Schubert 				       wpa_s, NULL);
384780fb4a2SCy Schubert 	}
385780fb4a2SCy Schubert }
386780fb4a2SCy Schubert 
387780fb4a2SCy Schubert 
wpas_ctrl_msg_queue(struct dl_list * queue,struct wpa_supplicant * wpa_s,int level,enum wpa_msg_type type,const char * txt,size_t len)388780fb4a2SCy Schubert static void wpas_ctrl_msg_queue(struct dl_list *queue,
389780fb4a2SCy Schubert 				struct wpa_supplicant *wpa_s, int level,
390780fb4a2SCy Schubert 				enum wpa_msg_type type,
391780fb4a2SCy Schubert 				const char *txt, size_t len)
392780fb4a2SCy Schubert {
393780fb4a2SCy Schubert 	struct ctrl_iface_msg *msg;
394780fb4a2SCy Schubert 
395780fb4a2SCy Schubert 	msg = os_zalloc(sizeof(*msg) + len);
396780fb4a2SCy Schubert 	if (!msg)
397780fb4a2SCy Schubert 		return;
398780fb4a2SCy Schubert 
399780fb4a2SCy Schubert 	msg->wpa_s = wpa_s;
400780fb4a2SCy Schubert 	msg->level = level;
401780fb4a2SCy Schubert 	msg->type = type;
402780fb4a2SCy Schubert 	os_memcpy(msg + 1, txt, len);
403780fb4a2SCy Schubert 	msg->txt = (const char *) (msg + 1);
404780fb4a2SCy Schubert 	msg->len = len;
405780fb4a2SCy Schubert 	dl_list_add_tail(queue, &msg->list);
406780fb4a2SCy Schubert 	eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
407780fb4a2SCy Schubert 	eloop_register_timeout(0, 0, wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
408780fb4a2SCy Schubert }
409780fb4a2SCy Schubert 
410780fb4a2SCy Schubert 
wpas_ctrl_msg_queue_limit(unsigned int throttle_count,struct dl_list * queue)411780fb4a2SCy Schubert static void wpas_ctrl_msg_queue_limit(unsigned int throttle_count,
412780fb4a2SCy Schubert 				      struct dl_list *queue)
413780fb4a2SCy Schubert {
414780fb4a2SCy Schubert 	struct ctrl_iface_msg *msg;
415780fb4a2SCy Schubert 
416780fb4a2SCy Schubert 	if (throttle_count < 2000)
417780fb4a2SCy Schubert 		return;
418780fb4a2SCy Schubert 
419780fb4a2SCy Schubert 	msg = dl_list_first(queue, struct ctrl_iface_msg, list);
420780fb4a2SCy Schubert 	if (msg) {
421780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "CTRL: Dropped oldest pending message");
422780fb4a2SCy Schubert 		dl_list_del(&msg->list);
423780fb4a2SCy Schubert 		os_free(msg);
424780fb4a2SCy Schubert 	}
425780fb4a2SCy Schubert }
426780fb4a2SCy Schubert 
427780fb4a2SCy Schubert 
wpa_supplicant_ctrl_iface_msg_cb(void * ctx,int level,enum wpa_msg_type type,const char * txt,size_t len)428325151a3SRui Paulo static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
429325151a3SRui Paulo 					     enum wpa_msg_type type,
43039beb93cSSam Leffler 					     const char *txt, size_t len)
43139beb93cSSam Leffler {
43239beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
433780fb4a2SCy Schubert 	struct ctrl_iface_priv *priv;
434780fb4a2SCy Schubert 	struct ctrl_iface_global_priv *gpriv;
4355b9c547cSRui Paulo 
4365b9c547cSRui Paulo 	if (wpa_s == NULL)
43739beb93cSSam Leffler 		return;
4385b9c547cSRui Paulo 
439780fb4a2SCy Schubert 	gpriv = wpa_s->global->ctrl_iface;
440780fb4a2SCy Schubert 
441780fb4a2SCy Schubert 	if (type != WPA_MSG_NO_GLOBAL && gpriv &&
442780fb4a2SCy Schubert 	    !dl_list_empty(&gpriv->ctrl_dst)) {
443780fb4a2SCy Schubert 		if (!dl_list_empty(&gpriv->msg_queue) ||
444780fb4a2SCy Schubert 		    wpas_ctrl_iface_throttle(gpriv->sock)) {
445780fb4a2SCy Schubert 			if (gpriv->throttle_count == 0) {
446780fb4a2SCy Schubert 				wpa_printf(MSG_MSGDUMP,
447780fb4a2SCy Schubert 					   "CTRL: Had to throttle global event message for sock %d",
448780fb4a2SCy Schubert 					   gpriv->sock);
449780fb4a2SCy Schubert 			}
450780fb4a2SCy Schubert 			gpriv->throttle_count++;
451780fb4a2SCy Schubert 			wpas_ctrl_msg_queue_limit(gpriv->throttle_count,
452780fb4a2SCy Schubert 						  &gpriv->msg_queue);
453780fb4a2SCy Schubert 			wpas_ctrl_msg_queue(&gpriv->msg_queue, wpa_s, level,
454780fb4a2SCy Schubert 					    type, txt, len);
455780fb4a2SCy Schubert 		} else {
456780fb4a2SCy Schubert 			if (gpriv->throttle_count) {
457780fb4a2SCy Schubert 				wpa_printf(MSG_MSGDUMP,
458780fb4a2SCy Schubert 					   "CTRL: Had to throttle %u global event message(s) for sock %d",
459780fb4a2SCy Schubert 					   gpriv->throttle_count, gpriv->sock);
460780fb4a2SCy Schubert 			}
461780fb4a2SCy Schubert 			gpriv->throttle_count = 0;
462325151a3SRui Paulo 			wpa_supplicant_ctrl_iface_send(
463325151a3SRui Paulo 				wpa_s,
464325151a3SRui Paulo 				type != WPA_MSG_PER_INTERFACE ?
465325151a3SRui Paulo 				NULL : wpa_s->ifname,
466780fb4a2SCy Schubert 				gpriv->sock, &gpriv->ctrl_dst, level,
467780fb4a2SCy Schubert 				txt, len, NULL, gpriv);
4685b9c547cSRui Paulo 		}
4695b9c547cSRui Paulo 	}
4705b9c547cSRui Paulo 
471780fb4a2SCy Schubert 	priv = wpa_s->ctrl_iface;
472780fb4a2SCy Schubert 
473780fb4a2SCy Schubert 	if (type != WPA_MSG_ONLY_GLOBAL && priv) {
474780fb4a2SCy Schubert 		if (!dl_list_empty(&priv->msg_queue) ||
475780fb4a2SCy Schubert 		    wpas_ctrl_iface_throttle(priv->sock)) {
476780fb4a2SCy Schubert 			if (priv->throttle_count == 0) {
477780fb4a2SCy Schubert 				wpa_printf(MSG_MSGDUMP,
478780fb4a2SCy Schubert 					   "CTRL: Had to throttle event message for sock %d",
479780fb4a2SCy Schubert 					   priv->sock);
480780fb4a2SCy Schubert 			}
481780fb4a2SCy Schubert 			priv->throttle_count++;
482780fb4a2SCy Schubert 			wpas_ctrl_msg_queue_limit(priv->throttle_count,
483780fb4a2SCy Schubert 						  &priv->msg_queue);
484780fb4a2SCy Schubert 			wpas_ctrl_msg_queue(&priv->msg_queue, wpa_s, level,
485780fb4a2SCy Schubert 					    type, txt, len);
486780fb4a2SCy Schubert 		} else {
487780fb4a2SCy Schubert 			if (priv->throttle_count) {
488780fb4a2SCy Schubert 				wpa_printf(MSG_MSGDUMP,
489780fb4a2SCy Schubert 					   "CTRL: Had to throttle %u event message(s) for sock %d",
490780fb4a2SCy Schubert 					   priv->throttle_count, priv->sock);
491780fb4a2SCy Schubert 			}
492780fb4a2SCy Schubert 			priv->throttle_count = 0;
493780fb4a2SCy Schubert 			wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
494780fb4a2SCy Schubert 						       &priv->ctrl_dst, level,
495780fb4a2SCy Schubert 						       txt, len, priv, NULL);
496780fb4a2SCy Schubert 		}
497780fb4a2SCy Schubert 	}
49839beb93cSSam Leffler }
49939beb93cSSam Leffler 
50039beb93cSSam Leffler 
wpas_ctrl_iface_open_sock(struct wpa_supplicant * wpa_s,struct ctrl_iface_priv * priv)5015b9c547cSRui Paulo static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
5025b9c547cSRui Paulo 				     struct ctrl_iface_priv *priv)
50339beb93cSSam Leffler {
50439beb93cSSam Leffler 	struct sockaddr_un addr;
50539beb93cSSam Leffler 	char *fname = NULL;
50639beb93cSSam Leffler 	gid_t gid = 0;
50739beb93cSSam Leffler 	int gid_set = 0;
50839beb93cSSam Leffler 	char *buf, *dir = NULL, *gid_str = NULL;
50939beb93cSSam Leffler 	struct group *grp;
51039beb93cSSam Leffler 	char *endp;
511f05cddf9SRui Paulo 	int flags;
5121edc20b7SBjoern A. Zeeb #if defined(__FreeBSD__)
5131edc20b7SBjoern A. Zeeb 	int optval, rc;
5141edc20b7SBjoern A. Zeeb 	socklen_t optlen;
5151edc20b7SBjoern A. Zeeb #endif
51639beb93cSSam Leffler 
51739beb93cSSam Leffler 	buf = os_strdup(wpa_s->conf->ctrl_interface);
51839beb93cSSam Leffler 	if (buf == NULL)
51939beb93cSSam Leffler 		goto fail;
520f05cddf9SRui Paulo #ifdef ANDROID
521f05cddf9SRui Paulo 	os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
522f05cddf9SRui Paulo 		    wpa_s->conf->ctrl_interface);
523f05cddf9SRui Paulo 	priv->sock = android_get_control_socket(addr.sun_path);
5245b9c547cSRui Paulo 	if (priv->sock >= 0) {
5255b9c547cSRui Paulo 		priv->android_control_socket = 1;
526f05cddf9SRui Paulo 		goto havesock;
5275b9c547cSRui Paulo 	}
528f05cddf9SRui Paulo #endif /* ANDROID */
52939beb93cSSam Leffler 	if (os_strncmp(buf, "DIR=", 4) == 0) {
53039beb93cSSam Leffler 		dir = buf + 4;
53139beb93cSSam Leffler 		gid_str = os_strstr(dir, " GROUP=");
53239beb93cSSam Leffler 		if (gid_str) {
53339beb93cSSam Leffler 			*gid_str = '\0';
53439beb93cSSam Leffler 			gid_str += 7;
53539beb93cSSam Leffler 		}
53639beb93cSSam Leffler 	} else {
53739beb93cSSam Leffler 		dir = buf;
53839beb93cSSam Leffler 		gid_str = wpa_s->conf->ctrl_interface_group;
53939beb93cSSam Leffler 	}
54039beb93cSSam Leffler 
54139beb93cSSam Leffler 	if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
54239beb93cSSam Leffler 		if (errno == EEXIST) {
54339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Using existing control "
54439beb93cSSam Leffler 				   "interface directory.");
54539beb93cSSam Leffler 		} else {
5465b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s",
5475b9c547cSRui Paulo 				   dir, strerror(errno));
54839beb93cSSam Leffler 			goto fail;
54939beb93cSSam Leffler 		}
55039beb93cSSam Leffler 	}
55139beb93cSSam Leffler 
552f05cddf9SRui Paulo #ifdef ANDROID
553f05cddf9SRui Paulo 	/*
554f05cddf9SRui Paulo 	 * wpa_supplicant is started from /init.*.rc on Android and that seems
555f05cddf9SRui Paulo 	 * to be using umask 0077 which would leave the control interface
556f05cddf9SRui Paulo 	 * directory without group access. This breaks things since Wi-Fi
557f05cddf9SRui Paulo 	 * framework assumes that this directory can be accessed by other
558f05cddf9SRui Paulo 	 * applications in the wifi group. Fix this by adding group access even
559f05cddf9SRui Paulo 	 * if umask value would prevent this.
560f05cddf9SRui Paulo 	 */
561f05cddf9SRui Paulo 	if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
562f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
563f05cddf9SRui Paulo 			   strerror(errno));
564f05cddf9SRui Paulo 		/* Try to continue anyway */
565f05cddf9SRui Paulo 	}
566f05cddf9SRui Paulo #endif /* ANDROID */
567f05cddf9SRui Paulo 
56839beb93cSSam Leffler 	if (gid_str) {
56939beb93cSSam Leffler 		grp = getgrnam(gid_str);
57039beb93cSSam Leffler 		if (grp) {
57139beb93cSSam Leffler 			gid = grp->gr_gid;
57239beb93cSSam Leffler 			gid_set = 1;
57339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
57439beb93cSSam Leffler 				   " (from group name '%s')",
57539beb93cSSam Leffler 				   (int) gid, gid_str);
57639beb93cSSam Leffler 		} else {
57739beb93cSSam Leffler 			/* Group name not found - try to parse this as gid */
57839beb93cSSam Leffler 			gid = strtol(gid_str, &endp, 10);
57939beb93cSSam Leffler 			if (*gid_str == '\0' || *endp != '\0') {
58039beb93cSSam Leffler 				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
58139beb93cSSam Leffler 					   "'%s'", gid_str);
58239beb93cSSam Leffler 				goto fail;
58339beb93cSSam Leffler 			}
58439beb93cSSam Leffler 			gid_set = 1;
58539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
58639beb93cSSam Leffler 				   (int) gid);
58739beb93cSSam Leffler 		}
58839beb93cSSam Leffler 	}
58939beb93cSSam Leffler 
5904bc52338SCy Schubert 	if (gid_set && lchown(dir, -1, gid) < 0) {
5914bc52338SCy Schubert 		wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
5925b9c547cSRui Paulo 			   dir, (int) gid, strerror(errno));
59339beb93cSSam Leffler 		goto fail;
59439beb93cSSam Leffler 	}
59539beb93cSSam Leffler 
5963157ba21SRui Paulo 	/* Make sure the group can enter and read the directory */
5973157ba21SRui Paulo 	if (gid_set &&
5983157ba21SRui Paulo 	    chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) {
5993157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s",
6003157ba21SRui Paulo 			   strerror(errno));
6013157ba21SRui Paulo 		goto fail;
6023157ba21SRui Paulo 	}
6033157ba21SRui Paulo 
60439beb93cSSam Leffler 	if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
60539beb93cSSam Leffler 	    sizeof(addr.sun_path)) {
60639beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded");
60739beb93cSSam Leffler 		goto fail;
60839beb93cSSam Leffler 	}
60939beb93cSSam Leffler 
61039beb93cSSam Leffler 	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
61139beb93cSSam Leffler 	if (priv->sock < 0) {
6125b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
61339beb93cSSam Leffler 		goto fail;
61439beb93cSSam Leffler 	}
61539beb93cSSam Leffler 
61639beb93cSSam Leffler 	os_memset(&addr, 0, sizeof(addr));
617e28a4053SRui Paulo #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
618470736a0SSam Leffler 	addr.sun_len = sizeof(addr);
6193157ba21SRui Paulo #endif /* __FreeBSD__ */
62039beb93cSSam Leffler 	addr.sun_family = AF_UNIX;
62139beb93cSSam Leffler 	fname = wpa_supplicant_ctrl_iface_path(wpa_s);
62239beb93cSSam Leffler 	if (fname == NULL)
62339beb93cSSam Leffler 		goto fail;
62439beb93cSSam Leffler 	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
62539beb93cSSam Leffler 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
62639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
62739beb93cSSam Leffler 			   strerror(errno));
62839beb93cSSam Leffler 		if (connect(priv->sock, (struct sockaddr *) &addr,
62939beb93cSSam Leffler 			    sizeof(addr)) < 0) {
63039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
63139beb93cSSam Leffler 				   " allow connections - assuming it was left"
63239beb93cSSam Leffler 				   "over from forced program termination");
63339beb93cSSam Leffler 			if (unlink(fname) < 0) {
6345b9c547cSRui Paulo 				wpa_printf(MSG_ERROR,
6355b9c547cSRui Paulo 					   "Could not unlink existing ctrl_iface socket '%s': %s",
6365b9c547cSRui Paulo 					   fname, strerror(errno));
63739beb93cSSam Leffler 				goto fail;
63839beb93cSSam Leffler 			}
63939beb93cSSam Leffler 			if (bind(priv->sock, (struct sockaddr *) &addr,
64039beb93cSSam Leffler 				 sizeof(addr)) < 0) {
6415b9c547cSRui Paulo 				wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s",
6425b9c547cSRui Paulo 					   strerror(errno));
64339beb93cSSam Leffler 				goto fail;
64439beb93cSSam Leffler 			}
64539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
64639beb93cSSam Leffler 				   "ctrl_iface socket '%s'", fname);
64739beb93cSSam Leffler 		} else {
64839beb93cSSam Leffler 			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
64939beb93cSSam Leffler 				   "be in use - cannot override it");
65039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
65139beb93cSSam Leffler 				   "not used anymore", fname);
65239beb93cSSam Leffler 			os_free(fname);
65339beb93cSSam Leffler 			fname = NULL;
65439beb93cSSam Leffler 			goto fail;
65539beb93cSSam Leffler 		}
65639beb93cSSam Leffler 	}
65739beb93cSSam Leffler 
6584bc52338SCy Schubert 	if (gid_set && lchown(fname, -1, gid) < 0) {
6594bc52338SCy Schubert 		wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
6605b9c547cSRui Paulo 			   fname, (int) gid, strerror(errno));
66139beb93cSSam Leffler 		goto fail;
66239beb93cSSam Leffler 	}
66339beb93cSSam Leffler 
66439beb93cSSam Leffler 	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
6655b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s",
6665b9c547cSRui Paulo 			   fname, strerror(errno));
66739beb93cSSam Leffler 		goto fail;
66839beb93cSSam Leffler 	}
66939beb93cSSam Leffler 	os_free(fname);
67039beb93cSSam Leffler 
671f05cddf9SRui Paulo #ifdef ANDROID
672f05cddf9SRui Paulo havesock:
673f05cddf9SRui Paulo #endif /* ANDROID */
674f05cddf9SRui Paulo 
675f05cddf9SRui Paulo 	/*
676f05cddf9SRui Paulo 	 * Make socket non-blocking so that we don't hang forever if
677f05cddf9SRui Paulo 	 * target dies unexpectedly.
678f05cddf9SRui Paulo 	 */
679f05cddf9SRui Paulo 	flags = fcntl(priv->sock, F_GETFL);
680f05cddf9SRui Paulo 	if (flags >= 0) {
681f05cddf9SRui Paulo 		flags |= O_NONBLOCK;
682f05cddf9SRui Paulo 		if (fcntl(priv->sock, F_SETFL, flags) < 0) {
6835b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
6845b9c547cSRui Paulo 				   strerror(errno));
685f05cddf9SRui Paulo 			/* Not fatal, continue on.*/
686f05cddf9SRui Paulo 		}
687f05cddf9SRui Paulo 	}
688f05cddf9SRui Paulo 
6891edc20b7SBjoern A. Zeeb #if defined(__FreeBSD__)
6901edc20b7SBjoern A. Zeeb 	/* Ensure we can send a full length message atomically. */
6911edc20b7SBjoern A. Zeeb 	optval = 0;
6921edc20b7SBjoern A. Zeeb 	optlen = sizeof(optval);
6931edc20b7SBjoern A. Zeeb 	if (getsockopt(priv->sock, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) == -1) {
6941edc20b7SBjoern A. Zeeb 		wpa_printf(MSG_INFO, "failed to get sndbuf for sock=%d: %s",
6951edc20b7SBjoern A. Zeeb 			   priv->sock, strerror(errno));
6961edc20b7SBjoern A. Zeeb 	} else if (optval < CTRL_IFACE_MAX_LEN) {
6971edc20b7SBjoern A. Zeeb 		optval = CTRL_IFACE_MAX_LEN;
6981edc20b7SBjoern A. Zeeb 		if (setsockopt(priv->sock, SOL_SOCKET, SO_SNDBUF, &optval,
6991edc20b7SBjoern A. Zeeb 			       sizeof(optval)) == -1)
7001edc20b7SBjoern A. Zeeb 			wpa_printf(MSG_ERROR, "failed to set sndbuf for "
7011edc20b7SBjoern A. Zeeb 				   "sock=%d: %s", priv->sock, strerror(errno));
7021edc20b7SBjoern A. Zeeb 	}
7031edc20b7SBjoern A. Zeeb #endif
7041edc20b7SBjoern A. Zeeb 
70539beb93cSSam Leffler 	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
70639beb93cSSam Leffler 				 wpa_s, priv);
70739beb93cSSam Leffler 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
70839beb93cSSam Leffler 
70939beb93cSSam Leffler 	os_free(buf);
7105b9c547cSRui Paulo 	return 0;
71139beb93cSSam Leffler 
71239beb93cSSam Leffler fail:
7135b9c547cSRui Paulo 	if (priv->sock >= 0) {
71439beb93cSSam Leffler 		close(priv->sock);
7155b9c547cSRui Paulo 		priv->sock = -1;
7165b9c547cSRui Paulo 	}
71739beb93cSSam Leffler 	if (fname) {
71839beb93cSSam Leffler 		unlink(fname);
71939beb93cSSam Leffler 		os_free(fname);
72039beb93cSSam Leffler 	}
72139beb93cSSam Leffler 	os_free(buf);
7225b9c547cSRui Paulo 	return -1;
7235b9c547cSRui Paulo }
7245b9c547cSRui Paulo 
7255b9c547cSRui Paulo 
7265b9c547cSRui Paulo struct ctrl_iface_priv *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant * wpa_s)7275b9c547cSRui Paulo wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
7285b9c547cSRui Paulo {
7295b9c547cSRui Paulo 	struct ctrl_iface_priv *priv;
7305b9c547cSRui Paulo 
7315b9c547cSRui Paulo 	priv = os_zalloc(sizeof(*priv));
7325b9c547cSRui Paulo 	if (priv == NULL)
73339beb93cSSam Leffler 		return NULL;
7345b9c547cSRui Paulo 	dl_list_init(&priv->ctrl_dst);
735780fb4a2SCy Schubert 	dl_list_init(&priv->msg_queue);
7365b9c547cSRui Paulo 	priv->wpa_s = wpa_s;
7375b9c547cSRui Paulo 	priv->sock = -1;
7385b9c547cSRui Paulo 
7395b9c547cSRui Paulo 	if (wpa_s->conf->ctrl_interface == NULL)
7405b9c547cSRui Paulo 		return priv;
7415b9c547cSRui Paulo 
742325151a3SRui Paulo #ifdef ANDROID
743325151a3SRui Paulo 	if (wpa_s->global->params.ctrl_interface) {
744325151a3SRui Paulo 		int same = 0;
745325151a3SRui Paulo 
746325151a3SRui Paulo 		if (wpa_s->global->params.ctrl_interface[0] == '/') {
747325151a3SRui Paulo 			if (os_strcmp(wpa_s->global->params.ctrl_interface,
748325151a3SRui Paulo 				      wpa_s->conf->ctrl_interface) == 0)
749325151a3SRui Paulo 				same = 1;
750325151a3SRui Paulo 		} else if (os_strncmp(wpa_s->global->params.ctrl_interface,
751325151a3SRui Paulo 				      "@android:", 9) == 0 ||
752325151a3SRui Paulo 			   os_strncmp(wpa_s->global->params.ctrl_interface,
753325151a3SRui Paulo 				      "@abstract:", 10) == 0) {
754325151a3SRui Paulo 			char *pos;
755325151a3SRui Paulo 
756325151a3SRui Paulo 			/*
757325151a3SRui Paulo 			 * Currently, Android uses @android:wpa_* as the naming
758325151a3SRui Paulo 			 * convention for the global ctrl interface. This logic
759325151a3SRui Paulo 			 * needs to be revisited if the above naming convention
760325151a3SRui Paulo 			 * is modified.
761325151a3SRui Paulo 			 */
762325151a3SRui Paulo 			pos = os_strchr(wpa_s->global->params.ctrl_interface,
763325151a3SRui Paulo 					'_');
764325151a3SRui Paulo 			if (pos &&
765325151a3SRui Paulo 			    os_strcmp(pos + 1,
766325151a3SRui Paulo 				      wpa_s->conf->ctrl_interface) == 0)
767325151a3SRui Paulo 				same = 1;
768325151a3SRui Paulo 		}
769325151a3SRui Paulo 
770325151a3SRui Paulo 		if (same) {
771325151a3SRui Paulo 			/*
772325151a3SRui Paulo 			 * The invalid configuration combination might be
773325151a3SRui Paulo 			 * possible to hit in an Android OTA upgrade case, so
774325151a3SRui Paulo 			 * instead of refusing to start the wpa_supplicant
775325151a3SRui Paulo 			 * process, do not open the per-interface ctrl_iface
776325151a3SRui Paulo 			 * and continue with the global control interface that
777325151a3SRui Paulo 			 * was set from the command line since the Wi-Fi
778325151a3SRui Paulo 			 * framework will use it for operations.
779325151a3SRui Paulo 			 */
780325151a3SRui Paulo 			wpa_printf(MSG_ERROR,
781325151a3SRui Paulo 				   "global ctrl interface %s matches ctrl interface %s - do not open per-interface ctrl interface",
782325151a3SRui Paulo 				   wpa_s->global->params.ctrl_interface,
783325151a3SRui Paulo 				   wpa_s->conf->ctrl_interface);
784325151a3SRui Paulo 			return priv;
785325151a3SRui Paulo 		}
786325151a3SRui Paulo 	}
787325151a3SRui Paulo #endif /* ANDROID */
788325151a3SRui Paulo 
7895b9c547cSRui Paulo 	if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
7905b9c547cSRui Paulo 		os_free(priv);
7915b9c547cSRui Paulo 		return NULL;
7925b9c547cSRui Paulo 	}
7935b9c547cSRui Paulo 
7945b9c547cSRui Paulo 	return priv;
7955b9c547cSRui Paulo }
7965b9c547cSRui Paulo 
7975b9c547cSRui Paulo 
wpas_ctrl_iface_reinit(struct wpa_supplicant * wpa_s,struct ctrl_iface_priv * priv)7985b9c547cSRui Paulo static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
7995b9c547cSRui Paulo 				  struct ctrl_iface_priv *priv)
8005b9c547cSRui Paulo {
8015b9c547cSRui Paulo 	int res;
8025b9c547cSRui Paulo 
8035b9c547cSRui Paulo 	if (priv->sock <= 0)
8045b9c547cSRui Paulo 		return -1;
8055b9c547cSRui Paulo 
8065b9c547cSRui Paulo 	/*
8075b9c547cSRui Paulo 	 * On Android, the control socket being used may be the socket
8085b9c547cSRui Paulo 	 * that is created when wpa_supplicant is started as a /init.*.rc
8095b9c547cSRui Paulo 	 * service. Such a socket is maintained as a key-value pair in
8105b9c547cSRui Paulo 	 * Android's environment. Closing this control socket would leave us
8115b9c547cSRui Paulo 	 * in a bad state with an invalid socket descriptor.
8125b9c547cSRui Paulo 	 */
8135b9c547cSRui Paulo 	if (priv->android_control_socket)
8145b9c547cSRui Paulo 		return priv->sock;
8155b9c547cSRui Paulo 
8165b9c547cSRui Paulo 	eloop_unregister_read_sock(priv->sock);
8175b9c547cSRui Paulo 	close(priv->sock);
8185b9c547cSRui Paulo 	priv->sock = -1;
8195b9c547cSRui Paulo 	res = wpas_ctrl_iface_open_sock(wpa_s, priv);
8205b9c547cSRui Paulo 	if (res < 0)
8215b9c547cSRui Paulo 		return -1;
8225b9c547cSRui Paulo 	return priv->sock;
82339beb93cSSam Leffler }
82439beb93cSSam Leffler 
82539beb93cSSam Leffler 
826c1d255d3SCy Schubert static void
wpas_global_ctrl_iface_flush_queued_msg(struct wpa_global * global,struct wpa_supplicant * wpa_s)827c1d255d3SCy Schubert wpas_global_ctrl_iface_flush_queued_msg(struct wpa_global *global,
828c1d255d3SCy Schubert 					struct wpa_supplicant *wpa_s)
829c1d255d3SCy Schubert {
830c1d255d3SCy Schubert 	struct ctrl_iface_global_priv *gpriv;
831c1d255d3SCy Schubert 	struct ctrl_iface_msg *msg, *prev_msg;
832c1d255d3SCy Schubert 	unsigned int count = 0;
833c1d255d3SCy Schubert 
834c1d255d3SCy Schubert 	if (!global || !global->ctrl_iface)
835c1d255d3SCy Schubert 		return;
836c1d255d3SCy Schubert 
837c1d255d3SCy Schubert 	gpriv = global->ctrl_iface;
838c1d255d3SCy Schubert 	dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue,
839c1d255d3SCy Schubert 			      struct ctrl_iface_msg, list) {
840c1d255d3SCy Schubert 		if (msg->wpa_s == wpa_s) {
841c1d255d3SCy Schubert 			count++;
842c1d255d3SCy Schubert 			dl_list_del(&msg->list);
843c1d255d3SCy Schubert 			os_free(msg);
844c1d255d3SCy Schubert 		}
845c1d255d3SCy Schubert 	}
846c1d255d3SCy Schubert 
847c1d255d3SCy Schubert 	if (count) {
848c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
849c1d255d3SCy Schubert 			   "CTRL: Dropped %u pending message(s) for interface that is being removed",
850c1d255d3SCy Schubert 			count);
851c1d255d3SCy Schubert 	}
852c1d255d3SCy Schubert }
853c1d255d3SCy Schubert 
854c1d255d3SCy Schubert 
wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant * wpa_s,struct ctrl_iface_priv * priv)855c1d255d3SCy Schubert void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
856c1d255d3SCy Schubert 				      struct ctrl_iface_priv *priv)
85739beb93cSSam Leffler {
85839beb93cSSam Leffler 	struct wpa_ctrl_dst *dst, *prev;
859780fb4a2SCy Schubert 	struct ctrl_iface_msg *msg, *prev_msg;
860780fb4a2SCy Schubert 	struct ctrl_iface_global_priv *gpriv;
86139beb93cSSam Leffler 
862c1d255d3SCy Schubert 	if (!priv) {
863c1d255d3SCy Schubert 		/* Control interface has not yet been initialized, so there is
864c1d255d3SCy Schubert 		 * nothing to deinitialize here. However, there might be a
865c1d255d3SCy Schubert 		 * pending message for this interface, so get rid of any such
866c1d255d3SCy Schubert 		 * entry before completing interface removal. */
867c1d255d3SCy Schubert 		wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s);
868c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
869c1d255d3SCy Schubert 		return;
870c1d255d3SCy Schubert 	}
871c1d255d3SCy Schubert 
87239beb93cSSam Leffler 	if (priv->sock > -1) {
87339beb93cSSam Leffler 		char *fname;
8745b9c547cSRui Paulo 		char *buf, *dir = NULL;
87539beb93cSSam Leffler 		eloop_unregister_read_sock(priv->sock);
876e28a4053SRui Paulo 		if (!dl_list_empty(&priv->ctrl_dst)) {
87739beb93cSSam Leffler 			/*
8785b9c547cSRui Paulo 			 * Wait before closing the control socket if
87939beb93cSSam Leffler 			 * there are any attached monitors in order to allow
88039beb93cSSam Leffler 			 * them to receive any pending messages.
88139beb93cSSam Leffler 			 */
88239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
88339beb93cSSam Leffler 				   "monitors to receive messages");
8845b9c547cSRui Paulo 			os_sleep(0, 100000);
88539beb93cSSam Leffler 		}
88639beb93cSSam Leffler 		close(priv->sock);
88739beb93cSSam Leffler 		priv->sock = -1;
88839beb93cSSam Leffler 		fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
88939beb93cSSam Leffler 		if (fname) {
89039beb93cSSam Leffler 			unlink(fname);
89139beb93cSSam Leffler 			os_free(fname);
89239beb93cSSam Leffler 		}
89339beb93cSSam Leffler 
8945b9c547cSRui Paulo 		if (priv->wpa_s->conf->ctrl_interface == NULL)
8955b9c547cSRui Paulo 			goto free_dst;
89639beb93cSSam Leffler 		buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
89739beb93cSSam Leffler 		if (buf == NULL)
89839beb93cSSam Leffler 			goto free_dst;
89939beb93cSSam Leffler 		if (os_strncmp(buf, "DIR=", 4) == 0) {
9005b9c547cSRui Paulo 			char *gid_str;
90139beb93cSSam Leffler 			dir = buf + 4;
90239beb93cSSam Leffler 			gid_str = os_strstr(dir, " GROUP=");
9035b9c547cSRui Paulo 			if (gid_str)
90439beb93cSSam Leffler 				*gid_str = '\0';
90539beb93cSSam Leffler 		} else
90639beb93cSSam Leffler 			dir = buf;
90739beb93cSSam Leffler 
90839beb93cSSam Leffler 		if (rmdir(dir) < 0) {
90939beb93cSSam Leffler 			if (errno == ENOTEMPTY) {
91039beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Control interface "
91139beb93cSSam Leffler 					   "directory not empty - leaving it "
91239beb93cSSam Leffler 					   "behind");
91339beb93cSSam Leffler 			} else {
9145b9c547cSRui Paulo 				wpa_printf(MSG_ERROR,
9155b9c547cSRui Paulo 					   "rmdir[ctrl_interface=%s]: %s",
9165b9c547cSRui Paulo 					   dir, strerror(errno));
91739beb93cSSam Leffler 			}
91839beb93cSSam Leffler 		}
91939beb93cSSam Leffler 		os_free(buf);
92039beb93cSSam Leffler 	}
92139beb93cSSam Leffler 
92239beb93cSSam Leffler free_dst:
923e28a4053SRui Paulo 	dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
924780fb4a2SCy Schubert 			      list) {
925780fb4a2SCy Schubert 		dl_list_del(&dst->list);
926e28a4053SRui Paulo 		os_free(dst);
927780fb4a2SCy Schubert 	}
928780fb4a2SCy Schubert 	dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
929780fb4a2SCy Schubert 			      struct ctrl_iface_msg, list) {
930780fb4a2SCy Schubert 		dl_list_del(&msg->list);
931780fb4a2SCy Schubert 		os_free(msg);
932780fb4a2SCy Schubert 	}
933780fb4a2SCy Schubert 	gpriv = priv->wpa_s->global->ctrl_iface;
934780fb4a2SCy Schubert 	if (gpriv) {
935780fb4a2SCy Schubert 		dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue,
936780fb4a2SCy Schubert 				      struct ctrl_iface_msg, list) {
937780fb4a2SCy Schubert 			if (msg->wpa_s == priv->wpa_s) {
938780fb4a2SCy Schubert 				dl_list_del(&msg->list);
939780fb4a2SCy Schubert 				os_free(msg);
940780fb4a2SCy Schubert 			}
941780fb4a2SCy Schubert 		}
942780fb4a2SCy Schubert 	}
943c1d255d3SCy Schubert 	wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s);
944780fb4a2SCy Schubert 	eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL);
94539beb93cSSam Leffler 	os_free(priv);
94639beb93cSSam Leffler }
94739beb93cSSam Leffler 
94839beb93cSSam Leffler 
94939beb93cSSam Leffler /**
95039beb93cSSam Leffler  * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
9515b9c547cSRui Paulo  * @ifname: Interface name for global control socket or %NULL
9525b9c547cSRui Paulo  * @sock: Local socket fd
9535b9c547cSRui Paulo  * @ctrl_dst: List of attached listeners
95439beb93cSSam Leffler  * @level: Priority level of the message
95539beb93cSSam Leffler  * @buf: Message data
95639beb93cSSam Leffler  * @len: Message length
95739beb93cSSam Leffler  *
95839beb93cSSam Leffler  * Send a packet to all monitor programs attached to the control interface.
95939beb93cSSam Leffler  */
wpa_supplicant_ctrl_iface_send(struct wpa_supplicant * wpa_s,const char * ifname,int sock,struct dl_list * ctrl_dst,int level,const char * buf,size_t len,struct ctrl_iface_priv * priv,struct ctrl_iface_global_priv * gp)9605b9c547cSRui Paulo static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
9615b9c547cSRui Paulo 					   const char *ifname, int sock,
9625b9c547cSRui Paulo 					   struct dl_list *ctrl_dst,
96339beb93cSSam Leffler 					   int level, const char *buf,
9645b9c547cSRui Paulo 					   size_t len,
9655b9c547cSRui Paulo 					   struct ctrl_iface_priv *priv,
9665b9c547cSRui Paulo 					   struct ctrl_iface_global_priv *gp)
96739beb93cSSam Leffler {
96839beb93cSSam Leffler 	struct wpa_ctrl_dst *dst, *next;
96939beb93cSSam Leffler 	char levelstr[10];
97039beb93cSSam Leffler 	int idx, res;
97139beb93cSSam Leffler 	struct msghdr msg;
9725b9c547cSRui Paulo 	struct iovec io[5];
97339beb93cSSam Leffler 
9745b9c547cSRui Paulo 	if (sock < 0 || dl_list_empty(ctrl_dst))
97539beb93cSSam Leffler 		return;
97639beb93cSSam Leffler 
97739beb93cSSam Leffler 	res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
9785b9c547cSRui Paulo 	if (os_snprintf_error(sizeof(levelstr), res))
97939beb93cSSam Leffler 		return;
9805b9c547cSRui Paulo 	idx = 0;
9815b9c547cSRui Paulo 	if (ifname) {
9825b9c547cSRui Paulo 		io[idx].iov_base = "IFNAME=";
9835b9c547cSRui Paulo 		io[idx].iov_len = 7;
9845b9c547cSRui Paulo 		idx++;
9855b9c547cSRui Paulo 		io[idx].iov_base = (char *) ifname;
9865b9c547cSRui Paulo 		io[idx].iov_len = os_strlen(ifname);
9875b9c547cSRui Paulo 		idx++;
9885b9c547cSRui Paulo 		io[idx].iov_base = " ";
9895b9c547cSRui Paulo 		io[idx].iov_len = 1;
9905b9c547cSRui Paulo 		idx++;
9915b9c547cSRui Paulo 	}
9925b9c547cSRui Paulo 	io[idx].iov_base = levelstr;
9935b9c547cSRui Paulo 	io[idx].iov_len = os_strlen(levelstr);
9945b9c547cSRui Paulo 	idx++;
9955b9c547cSRui Paulo 	io[idx].iov_base = (char *) buf;
9965b9c547cSRui Paulo 	io[idx].iov_len = len;
9975b9c547cSRui Paulo 	idx++;
99839beb93cSSam Leffler 	os_memset(&msg, 0, sizeof(msg));
99939beb93cSSam Leffler 	msg.msg_iov = io;
10005b9c547cSRui Paulo 	msg.msg_iovlen = idx;
100139beb93cSSam Leffler 
10025b9c547cSRui Paulo 	dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
10035b9c547cSRui Paulo 		int _errno;
1004780fb4a2SCy Schubert 		char txt[200];
10055b9c547cSRui Paulo 
10065b9c547cSRui Paulo 		if (level < dst->debug_level)
10075b9c547cSRui Paulo 			continue;
10085b9c547cSRui Paulo 
100939beb93cSSam Leffler 		msg.msg_name = (void *) &dst->addr;
101039beb93cSSam Leffler 		msg.msg_namelen = dst->addrlen;
1011325151a3SRui Paulo 		wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len);
10125b9c547cSRui Paulo 		if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
1013780fb4a2SCy Schubert 			sockaddr_print(MSG_MSGDUMP,
1014780fb4a2SCy Schubert 				       "CTRL_IFACE monitor sent successfully to",
1015780fb4a2SCy Schubert 				       &dst->addr, dst->addrlen);
10165b9c547cSRui Paulo 			dst->errors = 0;
10175b9c547cSRui Paulo 			continue;
10185b9c547cSRui Paulo 		}
10195b9c547cSRui Paulo 
10205b9c547cSRui Paulo 		_errno = errno;
1021780fb4a2SCy Schubert 		os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for",
1022780fb4a2SCy Schubert 			    _errno, strerror(_errno));
1023780fb4a2SCy Schubert 		sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen);
102439beb93cSSam Leffler 		dst->errors++;
10255b9c547cSRui Paulo 
10265b9c547cSRui Paulo 		if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
1027780fb4a2SCy Schubert 			sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:",
1028780fb4a2SCy Schubert 				       &dst->addr, dst->addrlen);
10295b9c547cSRui Paulo 			wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
103039beb93cSSam Leffler 							 dst->addrlen);
103139beb93cSSam Leffler 		}
10325b9c547cSRui Paulo 
10335b9c547cSRui Paulo 		if (_errno == ENOBUFS || _errno == EAGAIN) {
10345b9c547cSRui Paulo 			/*
10355b9c547cSRui Paulo 			 * The socket send buffer could be full. This may happen
10365b9c547cSRui Paulo 			 * if client programs are not receiving their pending
10375b9c547cSRui Paulo 			 * messages. Close and reopen the socket as a workaround
10385b9c547cSRui Paulo 			 * to avoid getting stuck being unable to send any new
10395b9c547cSRui Paulo 			 * responses.
10405b9c547cSRui Paulo 			 */
10415b9c547cSRui Paulo 			if (priv)
10425b9c547cSRui Paulo 				sock = wpas_ctrl_iface_reinit(wpa_s, priv);
10435b9c547cSRui Paulo 			else if (gp)
10445b9c547cSRui Paulo 				sock = wpas_ctrl_iface_global_reinit(
10455b9c547cSRui Paulo 					wpa_s->global, gp);
10465b9c547cSRui Paulo 			else
10475b9c547cSRui Paulo 				break;
10485b9c547cSRui Paulo 			if (sock < 0) {
10495b9c547cSRui Paulo 				wpa_dbg(wpa_s, MSG_DEBUG,
10505b9c547cSRui Paulo 					"Failed to reinitialize ctrl_iface socket");
10515b9c547cSRui Paulo 				break;
105239beb93cSSam Leffler 			}
10535b9c547cSRui Paulo 		}
105439beb93cSSam Leffler 	}
105539beb93cSSam Leffler }
105639beb93cSSam Leffler 
105739beb93cSSam Leffler 
wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv * priv)105839beb93cSSam Leffler void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
105939beb93cSSam Leffler {
106039beb93cSSam Leffler 	char buf[256];
106139beb93cSSam Leffler 	int res;
1062780fb4a2SCy Schubert 	struct sockaddr_storage from;
106339beb93cSSam Leffler 	socklen_t fromlen = sizeof(from);
106439beb93cSSam Leffler 
1065780fb4a2SCy Schubert 	if (priv->sock == -1)
1066780fb4a2SCy Schubert 		return;
1067780fb4a2SCy Schubert 
106839beb93cSSam Leffler 	for (;;) {
106939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
107039beb93cSSam Leffler 			   "attach", priv->wpa_s->ifname);
107139beb93cSSam Leffler 		eloop_wait_for_read_sock(priv->sock);
107239beb93cSSam Leffler 
107339beb93cSSam Leffler 		res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
107439beb93cSSam Leffler 			       (struct sockaddr *) &from, &fromlen);
107539beb93cSSam Leffler 		if (res < 0) {
10765b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
10775b9c547cSRui Paulo 				   strerror(errno));
107839beb93cSSam Leffler 			continue;
107939beb93cSSam Leffler 		}
108039beb93cSSam Leffler 		buf[res] = '\0';
108139beb93cSSam Leffler 
108239beb93cSSam Leffler 		if (os_strcmp(buf, "ATTACH") == 0) {
108339beb93cSSam Leffler 			/* handle ATTACH signal of first monitor interface */
10845b9c547cSRui Paulo 			if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
10855b9c547cSRui Paulo 							      &from, fromlen,
10865b9c547cSRui Paulo 							      0)) {
10875b9c547cSRui Paulo 				if (sendto(priv->sock, "OK\n", 3, 0,
10885b9c547cSRui Paulo 					   (struct sockaddr *) &from, fromlen) <
10895b9c547cSRui Paulo 				    0) {
10905b9c547cSRui Paulo 					wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
10915b9c547cSRui Paulo 						   strerror(errno));
10925b9c547cSRui Paulo 				}
109339beb93cSSam Leffler 				/* OK to continue */
109439beb93cSSam Leffler 				return;
109539beb93cSSam Leffler 			} else {
10965b9c547cSRui Paulo 				if (sendto(priv->sock, "FAIL\n", 5, 0,
10975b9c547cSRui Paulo 					   (struct sockaddr *) &from, fromlen) <
10985b9c547cSRui Paulo 				    0) {
10995b9c547cSRui Paulo 					wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
11005b9c547cSRui Paulo 						   strerror(errno));
11015b9c547cSRui Paulo 				}
110239beb93cSSam Leffler 			}
110339beb93cSSam Leffler 		} else {
110439beb93cSSam Leffler 			/* return FAIL for all other signals */
11055b9c547cSRui Paulo 			if (sendto(priv->sock, "FAIL\n", 5, 0,
11065b9c547cSRui Paulo 				   (struct sockaddr *) &from, fromlen) < 0) {
11075b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG,
11085b9c547cSRui Paulo 					   "ctrl_iface sendto failed: %s",
11095b9c547cSRui Paulo 					   strerror(errno));
11105b9c547cSRui Paulo 			}
111139beb93cSSam Leffler 		}
111239beb93cSSam Leffler 	}
111339beb93cSSam Leffler }
111439beb93cSSam Leffler 
111539beb93cSSam Leffler 
111639beb93cSSam Leffler /* Global ctrl_iface */
111739beb93cSSam Leffler 
wpa_supplicant_global_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)111839beb93cSSam Leffler static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
111939beb93cSSam Leffler 						     void *sock_ctx)
112039beb93cSSam Leffler {
112139beb93cSSam Leffler 	struct wpa_global *global = eloop_ctx;
11225b9c547cSRui Paulo 	struct ctrl_iface_global_priv *priv = sock_ctx;
1123c1d255d3SCy Schubert 	char *buf;
112439beb93cSSam Leffler 	int res;
1125780fb4a2SCy Schubert 	struct sockaddr_storage from;
112639beb93cSSam Leffler 	socklen_t fromlen = sizeof(from);
11275b9c547cSRui Paulo 	char *reply = NULL, *reply_buf = NULL;
112839beb93cSSam Leffler 	size_t reply_len;
112939beb93cSSam Leffler 
1130c1d255d3SCy Schubert 	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
1131c1d255d3SCy Schubert 	if (!buf)
1132c1d255d3SCy Schubert 		return;
1133c1d255d3SCy Schubert 	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
113439beb93cSSam Leffler 		       (struct sockaddr *) &from, &fromlen);
113539beb93cSSam Leffler 	if (res < 0) {
11365b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
11375b9c547cSRui Paulo 			   strerror(errno));
1138c1d255d3SCy Schubert 		os_free(buf);
1139c1d255d3SCy Schubert 		return;
1140c1d255d3SCy Schubert 	}
1141c1d255d3SCy Schubert 	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
1142c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
1143c1d255d3SCy Schubert 		os_free(buf);
114439beb93cSSam Leffler 		return;
114539beb93cSSam Leffler 	}
114639beb93cSSam Leffler 	buf[res] = '\0';
114739beb93cSSam Leffler 
11485b9c547cSRui Paulo 	if (os_strcmp(buf, "ATTACH") == 0) {
11495b9c547cSRui Paulo 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
11505b9c547cSRui Paulo 						     fromlen, 1))
11515b9c547cSRui Paulo 			reply_len = 1;
11525b9c547cSRui Paulo 		else
11535b9c547cSRui Paulo 			reply_len = 2;
11545b9c547cSRui Paulo 	} else if (os_strcmp(buf, "DETACH") == 0) {
11555b9c547cSRui Paulo 		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
11565b9c547cSRui Paulo 						     fromlen))
11575b9c547cSRui Paulo 			reply_len = 1;
11585b9c547cSRui Paulo 		else
11595b9c547cSRui Paulo 			reply_len = 2;
11605b9c547cSRui Paulo 	} else {
11615b9c547cSRui Paulo 		reply_buf = wpa_supplicant_global_ctrl_iface_process(
11625b9c547cSRui Paulo 			global, buf, &reply_len);
11635b9c547cSRui Paulo 		reply = reply_buf;
1164325151a3SRui Paulo 
1165325151a3SRui Paulo 		/*
1166325151a3SRui Paulo 		 * There could be some password/key material in the command, so
1167325151a3SRui Paulo 		 * clear the buffer explicitly now that it is not needed
1168325151a3SRui Paulo 		 * anymore.
1169325151a3SRui Paulo 		 */
1170325151a3SRui Paulo 		os_memset(buf, 0, res);
11715b9c547cSRui Paulo 	}
11725b9c547cSRui Paulo 
11735b9c547cSRui Paulo 	if (!reply && reply_len == 1) {
11745b9c547cSRui Paulo 		reply = "FAIL\n";
11755b9c547cSRui Paulo 		reply_len = 5;
11765b9c547cSRui Paulo 	} else if (!reply && reply_len == 2) {
11775b9c547cSRui Paulo 		reply = "OK\n";
11785b9c547cSRui Paulo 		reply_len = 3;
11795b9c547cSRui Paulo 	}
118039beb93cSSam Leffler 
118139beb93cSSam Leffler 	if (reply) {
1182325151a3SRui Paulo 		wpas_ctrl_sock_debug("global_ctrl_sock-sendto",
1183325151a3SRui Paulo 				     sock, reply, reply_len);
11845b9c547cSRui Paulo 		if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
11855b9c547cSRui Paulo 			   fromlen) < 0) {
11865b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
11875b9c547cSRui Paulo 				strerror(errno));
118839beb93cSSam Leffler 		}
118939beb93cSSam Leffler 	}
11905b9c547cSRui Paulo 	os_free(reply_buf);
1191c1d255d3SCy Schubert 	os_free(buf);
11925b9c547cSRui Paulo }
119339beb93cSSam Leffler 
119439beb93cSSam Leffler 
wpas_global_ctrl_iface_open_sock(struct wpa_global * global,struct ctrl_iface_global_priv * priv)11955b9c547cSRui Paulo static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
11965b9c547cSRui Paulo 					    struct ctrl_iface_global_priv *priv)
119739beb93cSSam Leffler {
119839beb93cSSam Leffler 	struct sockaddr_un addr;
11995b9c547cSRui Paulo 	const char *ctrl = global->params.ctrl_interface;
12005b9c547cSRui Paulo 	int flags;
120139beb93cSSam Leffler 
12025b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
120339beb93cSSam Leffler 
1204f05cddf9SRui Paulo #ifdef ANDROID
12055b9c547cSRui Paulo 	if (os_strncmp(ctrl, "@android:", 9) == 0) {
12065b9c547cSRui Paulo 		priv->sock = android_get_control_socket(ctrl + 9);
12075b9c547cSRui Paulo 		if (priv->sock < 0) {
12085b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "Failed to open Android control "
12095b9c547cSRui Paulo 				   "socket '%s'", ctrl + 9);
12105b9c547cSRui Paulo 			goto fail;
12115b9c547cSRui Paulo 		}
12125b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
12135b9c547cSRui Paulo 			   ctrl + 9);
12145b9c547cSRui Paulo 		priv->android_control_socket = 1;
1215f05cddf9SRui Paulo 		goto havesock;
12165b9c547cSRui Paulo 	}
1217f05cddf9SRui Paulo 
12185b9c547cSRui Paulo 	if (os_strncmp(ctrl, "@abstract:", 10) != 0) {
12195b9c547cSRui Paulo 		/*
12205b9c547cSRui Paulo 		 * Backwards compatibility - try to open an Android control
12215b9c547cSRui Paulo 		 * socket and if that fails, assume this was a UNIX domain
12225b9c547cSRui Paulo 		 * socket instead.
12235b9c547cSRui Paulo 		 */
12245b9c547cSRui Paulo 		priv->sock = android_get_control_socket(ctrl);
12255b9c547cSRui Paulo 		if (priv->sock >= 0) {
12265b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
12275b9c547cSRui Paulo 				   "Using Android control socket '%s'",
12285b9c547cSRui Paulo 				   ctrl);
12295b9c547cSRui Paulo 			priv->android_control_socket = 1;
12305b9c547cSRui Paulo 			goto havesock;
12315b9c547cSRui Paulo 		}
12325b9c547cSRui Paulo 	}
12335b9c547cSRui Paulo #endif /* ANDROID */
123439beb93cSSam Leffler 
123539beb93cSSam Leffler 	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
123639beb93cSSam Leffler 	if (priv->sock < 0) {
12375b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
123839beb93cSSam Leffler 		goto fail;
123939beb93cSSam Leffler 	}
124039beb93cSSam Leffler 
124139beb93cSSam Leffler 	os_memset(&addr, 0, sizeof(addr));
1242e28a4053SRui Paulo #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1243470736a0SSam Leffler 	addr.sun_len = sizeof(addr);
12443157ba21SRui Paulo #endif /* __FreeBSD__ */
124539beb93cSSam Leffler 	addr.sun_family = AF_UNIX;
12465b9c547cSRui Paulo 
12475b9c547cSRui Paulo 	if (os_strncmp(ctrl, "@abstract:", 10) == 0) {
12485b9c547cSRui Paulo 		addr.sun_path[0] = '\0';
12495b9c547cSRui Paulo 		os_strlcpy(addr.sun_path + 1, ctrl + 10,
12505b9c547cSRui Paulo 			   sizeof(addr.sun_path) - 1);
12515b9c547cSRui Paulo 		if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
12525b9c547cSRui Paulo 		    0) {
12535b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
12545b9c547cSRui Paulo 				   "bind(PF_UNIX;%s) failed: %s",
12555b9c547cSRui Paulo 				   ctrl, strerror(errno));
12565b9c547cSRui Paulo 			goto fail;
12575b9c547cSRui Paulo 		}
12585b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
12595b9c547cSRui Paulo 			   ctrl + 10);
12605b9c547cSRui Paulo 		goto havesock;
12615b9c547cSRui Paulo 	}
12625b9c547cSRui Paulo 
12635b9c547cSRui Paulo 	os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
126439beb93cSSam Leffler 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
12655b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s",
12665b9c547cSRui Paulo 			   ctrl, strerror(errno));
126739beb93cSSam Leffler 		if (connect(priv->sock, (struct sockaddr *) &addr,
126839beb93cSSam Leffler 			    sizeof(addr)) < 0) {
126939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
127039beb93cSSam Leffler 				   " allow connections - assuming it was left"
127139beb93cSSam Leffler 				   "over from forced program termination");
12725b9c547cSRui Paulo 			if (unlink(ctrl) < 0) {
12735b9c547cSRui Paulo 				wpa_printf(MSG_ERROR,
12745b9c547cSRui Paulo 					   "Could not unlink existing ctrl_iface socket '%s': %s",
12755b9c547cSRui Paulo 					   ctrl, strerror(errno));
127639beb93cSSam Leffler 				goto fail;
127739beb93cSSam Leffler 			}
127839beb93cSSam Leffler 			if (bind(priv->sock, (struct sockaddr *) &addr,
127939beb93cSSam Leffler 				 sizeof(addr)) < 0) {
12805b9c547cSRui Paulo 				wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s",
12815b9c547cSRui Paulo 					   ctrl, strerror(errno));
128239beb93cSSam Leffler 				goto fail;
128339beb93cSSam Leffler 			}
128439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
128539beb93cSSam Leffler 				   "ctrl_iface socket '%s'",
12865b9c547cSRui Paulo 				   ctrl);
128739beb93cSSam Leffler 		} else {
128839beb93cSSam Leffler 			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
128939beb93cSSam Leffler 				   "be in use - cannot override it");
129039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
129139beb93cSSam Leffler 				   "not used anymore",
12925b9c547cSRui Paulo 				   ctrl);
129339beb93cSSam Leffler 			goto fail;
129439beb93cSSam Leffler 		}
129539beb93cSSam Leffler 	}
129639beb93cSSam Leffler 
12975b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl);
12985b9c547cSRui Paulo 
12995b9c547cSRui Paulo 	if (global->params.ctrl_interface_group) {
13005b9c547cSRui Paulo 		char *gid_str = global->params.ctrl_interface_group;
13015b9c547cSRui Paulo 		gid_t gid = 0;
13025b9c547cSRui Paulo 		struct group *grp;
13035b9c547cSRui Paulo 		char *endp;
13045b9c547cSRui Paulo 
13055b9c547cSRui Paulo 		grp = getgrnam(gid_str);
13065b9c547cSRui Paulo 		if (grp) {
13075b9c547cSRui Paulo 			gid = grp->gr_gid;
13085b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
13095b9c547cSRui Paulo 				   " (from group name '%s')",
13105b9c547cSRui Paulo 				   (int) gid, gid_str);
13115b9c547cSRui Paulo 		} else {
13125b9c547cSRui Paulo 			/* Group name not found - try to parse this as gid */
13135b9c547cSRui Paulo 			gid = strtol(gid_str, &endp, 10);
13145b9c547cSRui Paulo 			if (*gid_str == '\0' || *endp != '\0') {
13155b9c547cSRui Paulo 				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
13165b9c547cSRui Paulo 					   "'%s'", gid_str);
13175b9c547cSRui Paulo 				goto fail;
13185b9c547cSRui Paulo 			}
13195b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
13205b9c547cSRui Paulo 				   (int) gid);
13215b9c547cSRui Paulo 		}
13224bc52338SCy Schubert 		if (lchown(ctrl, -1, gid) < 0) {
13235b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
13244bc52338SCy Schubert 				   "lchown[global_ctrl_interface=%s,gid=%d]: %s",
13255b9c547cSRui Paulo 				   ctrl, (int) gid, strerror(errno));
13265b9c547cSRui Paulo 			goto fail;
13275b9c547cSRui Paulo 		}
13285b9c547cSRui Paulo 
13295b9c547cSRui Paulo 		if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
13305b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
13315b9c547cSRui Paulo 				   "chmod[global_ctrl_interface=%s]: %s",
13325b9c547cSRui Paulo 				   ctrl, strerror(errno));
13335b9c547cSRui Paulo 			goto fail;
13345b9c547cSRui Paulo 		}
13355b9c547cSRui Paulo 	} else {
13365b9c547cSRui Paulo 		if (chmod(ctrl, S_IRWXU) < 0) {
13375b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
13385b9c547cSRui Paulo 				   "chmod[global_ctrl_interface=%s](S_IRWXU): %s",
13395b9c547cSRui Paulo 				   ctrl, strerror(errno));
13405b9c547cSRui Paulo 			/* continue anyway since group change was not required
13415b9c547cSRui Paulo 			 */
13425b9c547cSRui Paulo 		}
13435b9c547cSRui Paulo 	}
13445b9c547cSRui Paulo 
1345f05cddf9SRui Paulo havesock:
13465b9c547cSRui Paulo 
13475b9c547cSRui Paulo 	/*
13485b9c547cSRui Paulo 	 * Make socket non-blocking so that we don't hang forever if
13495b9c547cSRui Paulo 	 * target dies unexpectedly.
13505b9c547cSRui Paulo 	 */
13515b9c547cSRui Paulo 	flags = fcntl(priv->sock, F_GETFL);
13525b9c547cSRui Paulo 	if (flags >= 0) {
13535b9c547cSRui Paulo 		flags |= O_NONBLOCK;
13545b9c547cSRui Paulo 		if (fcntl(priv->sock, F_SETFL, flags) < 0) {
13555b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
13565b9c547cSRui Paulo 				   strerror(errno));
13575b9c547cSRui Paulo 			/* Not fatal, continue on.*/
13585b9c547cSRui Paulo 		}
13595b9c547cSRui Paulo 	}
13605b9c547cSRui Paulo 
136139beb93cSSam Leffler 	eloop_register_read_sock(priv->sock,
136239beb93cSSam Leffler 				 wpa_supplicant_global_ctrl_iface_receive,
13635b9c547cSRui Paulo 				 global, priv);
136439beb93cSSam Leffler 
13655b9c547cSRui Paulo 	return 0;
136639beb93cSSam Leffler 
136739beb93cSSam Leffler fail:
13685b9c547cSRui Paulo 	if (priv->sock >= 0) {
136939beb93cSSam Leffler 		close(priv->sock);
13705b9c547cSRui Paulo 		priv->sock = -1;
13715b9c547cSRui Paulo 	}
13725b9c547cSRui Paulo 	return -1;
13735b9c547cSRui Paulo }
13745b9c547cSRui Paulo 
13755b9c547cSRui Paulo 
13765b9c547cSRui Paulo struct ctrl_iface_global_priv *
wpa_supplicant_global_ctrl_iface_init(struct wpa_global * global)13775b9c547cSRui Paulo wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
13785b9c547cSRui Paulo {
13795b9c547cSRui Paulo 	struct ctrl_iface_global_priv *priv;
13805b9c547cSRui Paulo 
13815b9c547cSRui Paulo 	priv = os_zalloc(sizeof(*priv));
13825b9c547cSRui Paulo 	if (priv == NULL)
13835b9c547cSRui Paulo 		return NULL;
13845b9c547cSRui Paulo 	dl_list_init(&priv->ctrl_dst);
1385780fb4a2SCy Schubert 	dl_list_init(&priv->msg_queue);
13865b9c547cSRui Paulo 	priv->global = global;
13875b9c547cSRui Paulo 	priv->sock = -1;
13885b9c547cSRui Paulo 
13895b9c547cSRui Paulo 	if (global->params.ctrl_interface == NULL)
13905b9c547cSRui Paulo 		return priv;
13915b9c547cSRui Paulo 
13925b9c547cSRui Paulo 	if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
139339beb93cSSam Leffler 		os_free(priv);
139439beb93cSSam Leffler 		return NULL;
139539beb93cSSam Leffler 	}
139639beb93cSSam Leffler 
13975b9c547cSRui Paulo 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
13985b9c547cSRui Paulo 
13995b9c547cSRui Paulo 	return priv;
14005b9c547cSRui Paulo }
14015b9c547cSRui Paulo 
14025b9c547cSRui Paulo 
wpas_ctrl_iface_global_reinit(struct wpa_global * global,struct ctrl_iface_global_priv * priv)14035b9c547cSRui Paulo static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
14045b9c547cSRui Paulo 					 struct ctrl_iface_global_priv *priv)
14055b9c547cSRui Paulo {
14065b9c547cSRui Paulo 	int res;
14075b9c547cSRui Paulo 
14085b9c547cSRui Paulo 	if (priv->sock <= 0)
14095b9c547cSRui Paulo 		return -1;
14105b9c547cSRui Paulo 
14115b9c547cSRui Paulo 	/*
14125b9c547cSRui Paulo 	 * On Android, the control socket being used may be the socket
14135b9c547cSRui Paulo 	 * that is created when wpa_supplicant is started as a /init.*.rc
14145b9c547cSRui Paulo 	 * service. Such a socket is maintained as a key-value pair in
14155b9c547cSRui Paulo 	 * Android's environment. Closing this control socket would leave us
14165b9c547cSRui Paulo 	 * in a bad state with an invalid socket descriptor.
14175b9c547cSRui Paulo 	 */
14185b9c547cSRui Paulo 	if (priv->android_control_socket)
14195b9c547cSRui Paulo 		return priv->sock;
14205b9c547cSRui Paulo 
14215b9c547cSRui Paulo 	eloop_unregister_read_sock(priv->sock);
14225b9c547cSRui Paulo 	close(priv->sock);
14235b9c547cSRui Paulo 	priv->sock = -1;
14245b9c547cSRui Paulo 	res = wpas_global_ctrl_iface_open_sock(global, priv);
14255b9c547cSRui Paulo 	if (res < 0)
14265b9c547cSRui Paulo 		return -1;
14275b9c547cSRui Paulo 	return priv->sock;
14285b9c547cSRui Paulo }
14295b9c547cSRui Paulo 
143039beb93cSSam Leffler 
143139beb93cSSam Leffler void
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv * priv)143239beb93cSSam Leffler wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
143339beb93cSSam Leffler {
14345b9c547cSRui Paulo 	struct wpa_ctrl_dst *dst, *prev;
1435780fb4a2SCy Schubert 	struct ctrl_iface_msg *msg, *prev_msg;
14365b9c547cSRui Paulo 
143739beb93cSSam Leffler 	if (priv->sock >= 0) {
143839beb93cSSam Leffler 		eloop_unregister_read_sock(priv->sock);
143939beb93cSSam Leffler 		close(priv->sock);
144039beb93cSSam Leffler 	}
144139beb93cSSam Leffler 	if (priv->global->params.ctrl_interface)
144239beb93cSSam Leffler 		unlink(priv->global->params.ctrl_interface);
14435b9c547cSRui Paulo 	dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
1444780fb4a2SCy Schubert 			      list) {
1445780fb4a2SCy Schubert 		dl_list_del(&dst->list);
14465b9c547cSRui Paulo 		os_free(dst);
1447780fb4a2SCy Schubert 	}
1448780fb4a2SCy Schubert 	dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
1449780fb4a2SCy Schubert 			      struct ctrl_iface_msg, list) {
1450780fb4a2SCy Schubert 		dl_list_del(&msg->list);
1451780fb4a2SCy Schubert 		os_free(msg);
1452780fb4a2SCy Schubert 	}
145339beb93cSSam Leffler 	os_free(priv);
145439beb93cSSam Leffler }
1455