xref: /freebsd/contrib/wpa/src/common/wpa_ctrl.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * wpa_supplicant/hostapd control interface library
339beb93cSSam Leffler  * Copyright (c) 2004-2007, 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 
1139beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE
1239beb93cSSam Leffler 
1339beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UNIX
144bc52338SCy Schubert #include <sys/stat.h>
154bc52338SCy Schubert #include <fcntl.h>
1639beb93cSSam Leffler #include <sys/un.h>
17f05cddf9SRui Paulo #include <unistd.h>
18f05cddf9SRui Paulo #include <fcntl.h>
1939beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX */
20f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
21f05cddf9SRui Paulo #include <netdb.h>
22f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
23f05cddf9SRui Paulo 
24f05cddf9SRui Paulo #ifdef ANDROID
25f05cddf9SRui Paulo #include <dirent.h>
26325151a3SRui Paulo #include <sys/stat.h>
27f05cddf9SRui Paulo #include <cutils/sockets.h>
28f05cddf9SRui Paulo #include "private/android_filesystem_config.h"
29f05cddf9SRui Paulo #endif /* ANDROID */
3039beb93cSSam Leffler 
315b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
325b9c547cSRui Paulo #include <net/if.h>
335b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
345b9c547cSRui Paulo 
3539beb93cSSam Leffler #include "wpa_ctrl.h"
3639beb93cSSam Leffler #include "common.h"
3739beb93cSSam Leffler 
3839beb93cSSam Leffler 
3939beb93cSSam Leffler #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
4039beb93cSSam Leffler #define CTRL_IFACE_SOCKET
4139beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
4239beb93cSSam Leffler 
4339beb93cSSam Leffler 
4439beb93cSSam Leffler /**
4539beb93cSSam Leffler  * struct wpa_ctrl - Internal structure for control interface library
4639beb93cSSam Leffler  *
4739beb93cSSam Leffler  * This structure is used by the wpa_supplicant/hostapd control interface
4839beb93cSSam Leffler  * library to store internal data. Programs using the library should not touch
4939beb93cSSam Leffler  * this data directly. They can only use the pointer to the data structure as
5039beb93cSSam Leffler  * an identifier for the control interface connection and use this as one of
5139beb93cSSam Leffler  * the arguments for most of the control interface library functions.
5239beb93cSSam Leffler  */
5339beb93cSSam Leffler struct wpa_ctrl {
5439beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UDP
5539beb93cSSam Leffler 	int s;
565b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
575b9c547cSRui Paulo 	struct sockaddr_in6 local;
585b9c547cSRui Paulo 	struct sockaddr_in6 dest;
595b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
6039beb93cSSam Leffler 	struct sockaddr_in local;
6139beb93cSSam Leffler 	struct sockaddr_in dest;
625b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
6339beb93cSSam Leffler 	char *cookie;
64f05cddf9SRui Paulo 	char *remote_ifname;
65f05cddf9SRui Paulo 	char *remote_ip;
6639beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UDP */
6739beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UNIX
6839beb93cSSam Leffler 	int s;
6939beb93cSSam Leffler 	struct sockaddr_un local;
7039beb93cSSam Leffler 	struct sockaddr_un dest;
7139beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX */
7239beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
7339beb93cSSam Leffler 	HANDLE pipe;
7439beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
7539beb93cSSam Leffler };
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 
7839beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UNIX
7939beb93cSSam Leffler 
80f05cddf9SRui Paulo #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
81f05cddf9SRui Paulo #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
82f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
83f05cddf9SRui Paulo #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
84f05cddf9SRui Paulo #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
85f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
86f05cddf9SRui Paulo 
87f05cddf9SRui Paulo 
wpa_ctrl_open(const char * ctrl_path)8839beb93cSSam Leffler struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
8939beb93cSSam Leffler {
90325151a3SRui Paulo 	return wpa_ctrl_open2(ctrl_path, NULL);
91325151a3SRui Paulo }
92325151a3SRui Paulo 
93325151a3SRui Paulo 
wpa_ctrl_open2(const char * ctrl_path,const char * cli_path)94325151a3SRui Paulo struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
95325151a3SRui Paulo 				 const char *cli_path)
96325151a3SRui Paulo {
9739beb93cSSam Leffler 	struct wpa_ctrl *ctrl;
9839beb93cSSam Leffler 	static int counter = 0;
9939beb93cSSam Leffler 	int ret;
10039beb93cSSam Leffler 	size_t res;
10139beb93cSSam Leffler 	int tries = 0;
102f05cddf9SRui Paulo 	int flags;
10339beb93cSSam Leffler 
1045b9c547cSRui Paulo 	if (ctrl_path == NULL)
1055b9c547cSRui Paulo 		return NULL;
1065b9c547cSRui Paulo 
1075b9c547cSRui Paulo 	ctrl = os_zalloc(sizeof(*ctrl));
10839beb93cSSam Leffler 	if (ctrl == NULL)
10939beb93cSSam Leffler 		return NULL;
11039beb93cSSam Leffler 
11139beb93cSSam Leffler 	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
11239beb93cSSam Leffler 	if (ctrl->s < 0) {
11339beb93cSSam Leffler 		os_free(ctrl);
11439beb93cSSam Leffler 		return NULL;
11539beb93cSSam Leffler 	}
11639beb93cSSam Leffler 
11739beb93cSSam Leffler 	ctrl->local.sun_family = AF_UNIX;
11839beb93cSSam Leffler 	counter++;
11939beb93cSSam Leffler try_again:
120325151a3SRui Paulo 	if (cli_path && cli_path[0] == '/') {
121325151a3SRui Paulo 		ret = os_snprintf(ctrl->local.sun_path,
122325151a3SRui Paulo 				  sizeof(ctrl->local.sun_path),
123325151a3SRui Paulo 				  "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
124325151a3SRui Paulo 				  cli_path, (int) getpid(), counter);
125325151a3SRui Paulo 	} else {
126325151a3SRui Paulo 		ret = os_snprintf(ctrl->local.sun_path,
127325151a3SRui Paulo 				  sizeof(ctrl->local.sun_path),
128f05cddf9SRui Paulo 				  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
129f05cddf9SRui Paulo 				  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
130f05cddf9SRui Paulo 				  (int) getpid(), counter);
131325151a3SRui Paulo 	}
1325b9c547cSRui Paulo 	if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
13339beb93cSSam Leffler 		close(ctrl->s);
13439beb93cSSam Leffler 		os_free(ctrl);
13539beb93cSSam Leffler 		return NULL;
13639beb93cSSam Leffler 	}
13739beb93cSSam Leffler 	tries++;
1384bc52338SCy Schubert #ifdef ANDROID
1394bc52338SCy Schubert 	/* Set client socket file permissions so that bind() creates the client
1404bc52338SCy Schubert 	 * socket with these permissions and there is no need to try to change
1414bc52338SCy Schubert 	 * them with chmod() after bind() which would have potential issues with
1424bc52338SCy Schubert 	 * race conditions. These permissions are needed to make sure the server
1434bc52338SCy Schubert 	 * side (wpa_supplicant or hostapd) can reply to the control interface
1444bc52338SCy Schubert 	 * messages.
1454bc52338SCy Schubert 	 *
1464bc52338SCy Schubert 	 * The lchown() calls below after bind() are also part of the needed
1474bc52338SCy Schubert 	 * operations to allow the response to go through. Those are using the
1484bc52338SCy Schubert 	 * no-deference-symlinks version to avoid races. */
1494bc52338SCy Schubert 	fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
1504bc52338SCy Schubert #endif /* ANDROID */
15139beb93cSSam Leffler 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
15239beb93cSSam Leffler 		    sizeof(ctrl->local)) < 0) {
15339beb93cSSam Leffler 		if (errno == EADDRINUSE && tries < 2) {
15439beb93cSSam Leffler 			/*
15539beb93cSSam Leffler 			 * getpid() returns unique identifier for this instance
15639beb93cSSam Leffler 			 * of wpa_ctrl, so the existing socket file must have
15739beb93cSSam Leffler 			 * been left by unclean termination of an earlier run.
15839beb93cSSam Leffler 			 * Remove the file and try again.
15939beb93cSSam Leffler 			 */
16039beb93cSSam Leffler 			unlink(ctrl->local.sun_path);
16139beb93cSSam Leffler 			goto try_again;
16239beb93cSSam Leffler 		}
16339beb93cSSam Leffler 		close(ctrl->s);
16439beb93cSSam Leffler 		os_free(ctrl);
16539beb93cSSam Leffler 		return NULL;
16639beb93cSSam Leffler 	}
16739beb93cSSam Leffler 
168f05cddf9SRui Paulo #ifdef ANDROID
169325151a3SRui Paulo 	/* Set group even if we do not have privileges to change owner */
1704bc52338SCy Schubert 	lchown(ctrl->local.sun_path, -1, AID_WIFI);
1714bc52338SCy Schubert 	lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
1725b9c547cSRui Paulo 
1735b9c547cSRui Paulo 	if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
1745b9c547cSRui Paulo 		if (socket_local_client_connect(
1755b9c547cSRui Paulo 			    ctrl->s, ctrl_path + 9,
1765b9c547cSRui Paulo 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
1775b9c547cSRui Paulo 			    SOCK_DGRAM) < 0) {
1785b9c547cSRui Paulo 			close(ctrl->s);
1795b9c547cSRui Paulo 			unlink(ctrl->local.sun_path);
1805b9c547cSRui Paulo 			os_free(ctrl);
1815b9c547cSRui Paulo 			return NULL;
1825b9c547cSRui Paulo 		}
1835b9c547cSRui Paulo 		return ctrl;
1845b9c547cSRui Paulo 	}
1855b9c547cSRui Paulo 
186f05cddf9SRui Paulo 	/*
187f05cddf9SRui Paulo 	 * If the ctrl_path isn't an absolute pathname, assume that
188f05cddf9SRui Paulo 	 * it's the name of a socket in the Android reserved namespace.
189f05cddf9SRui Paulo 	 * Otherwise, it's a normal UNIX domain socket appearing in the
190f05cddf9SRui Paulo 	 * filesystem.
191f05cddf9SRui Paulo 	 */
1925b9c547cSRui Paulo 	if (*ctrl_path != '/') {
193f05cddf9SRui Paulo 		char buf[21];
194f05cddf9SRui Paulo 		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
195f05cddf9SRui Paulo 		if (socket_local_client_connect(
196f05cddf9SRui Paulo 			    ctrl->s, buf,
197f05cddf9SRui Paulo 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
198f05cddf9SRui Paulo 			    SOCK_DGRAM) < 0) {
199f05cddf9SRui Paulo 			close(ctrl->s);
200f05cddf9SRui Paulo 			unlink(ctrl->local.sun_path);
201f05cddf9SRui Paulo 			os_free(ctrl);
202f05cddf9SRui Paulo 			return NULL;
203f05cddf9SRui Paulo 		}
204f05cddf9SRui Paulo 		return ctrl;
205f05cddf9SRui Paulo 	}
206f05cddf9SRui Paulo #endif /* ANDROID */
207f05cddf9SRui Paulo 
20839beb93cSSam Leffler 	ctrl->dest.sun_family = AF_UNIX;
2095b9c547cSRui Paulo 	if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
2105b9c547cSRui Paulo 		ctrl->dest.sun_path[0] = '\0';
2115b9c547cSRui Paulo 		os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
2125b9c547cSRui Paulo 			   sizeof(ctrl->dest.sun_path) - 1);
2135b9c547cSRui Paulo 	} else {
21439beb93cSSam Leffler 		res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
21539beb93cSSam Leffler 				 sizeof(ctrl->dest.sun_path));
21639beb93cSSam Leffler 		if (res >= sizeof(ctrl->dest.sun_path)) {
21739beb93cSSam Leffler 			close(ctrl->s);
21839beb93cSSam Leffler 			os_free(ctrl);
21939beb93cSSam Leffler 			return NULL;
22039beb93cSSam Leffler 		}
2215b9c547cSRui Paulo 	}
22239beb93cSSam Leffler 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
22339beb93cSSam Leffler 		    sizeof(ctrl->dest)) < 0) {
22439beb93cSSam Leffler 		close(ctrl->s);
22539beb93cSSam Leffler 		unlink(ctrl->local.sun_path);
22639beb93cSSam Leffler 		os_free(ctrl);
22739beb93cSSam Leffler 		return NULL;
22839beb93cSSam Leffler 	}
22939beb93cSSam Leffler 
230f05cddf9SRui Paulo 	/*
231f05cddf9SRui Paulo 	 * Make socket non-blocking so that we don't hang forever if
232f05cddf9SRui Paulo 	 * target dies unexpectedly.
233f05cddf9SRui Paulo 	 */
234f05cddf9SRui Paulo 	flags = fcntl(ctrl->s, F_GETFL);
235f05cddf9SRui Paulo 	if (flags >= 0) {
236f05cddf9SRui Paulo 		flags |= O_NONBLOCK;
237f05cddf9SRui Paulo 		if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
238f05cddf9SRui Paulo 			perror("fcntl(ctrl->s, O_NONBLOCK)");
239f05cddf9SRui Paulo 			/* Not fatal, continue on.*/
240f05cddf9SRui Paulo 		}
241f05cddf9SRui Paulo 	}
242f05cddf9SRui Paulo 
24339beb93cSSam Leffler 	return ctrl;
24439beb93cSSam Leffler }
24539beb93cSSam Leffler 
24639beb93cSSam Leffler 
wpa_ctrl_close(struct wpa_ctrl * ctrl)24739beb93cSSam Leffler void wpa_ctrl_close(struct wpa_ctrl *ctrl)
24839beb93cSSam Leffler {
249f05cddf9SRui Paulo 	if (ctrl == NULL)
250f05cddf9SRui Paulo 		return;
25139beb93cSSam Leffler 	unlink(ctrl->local.sun_path);
252f05cddf9SRui Paulo 	if (ctrl->s >= 0)
25339beb93cSSam Leffler 		close(ctrl->s);
25439beb93cSSam Leffler 	os_free(ctrl);
25539beb93cSSam Leffler }
25639beb93cSSam Leffler 
257f05cddf9SRui Paulo 
258f05cddf9SRui Paulo #ifdef ANDROID
259f05cddf9SRui Paulo /**
260f05cddf9SRui Paulo  * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
261f05cddf9SRui Paulo  * may be left over from clients that were previously connected to
262f05cddf9SRui Paulo  * wpa_supplicant. This keeps these files from being orphaned in the
263f05cddf9SRui Paulo  * event of crashes that prevented them from being removed as part
264f05cddf9SRui Paulo  * of the normal orderly shutdown.
265f05cddf9SRui Paulo  */
wpa_ctrl_cleanup(void)266f05cddf9SRui Paulo void wpa_ctrl_cleanup(void)
267f05cddf9SRui Paulo {
268f05cddf9SRui Paulo 	DIR *dir;
269f05cddf9SRui Paulo 	struct dirent *result;
270f05cddf9SRui Paulo 	size_t dirnamelen;
271f05cddf9SRui Paulo 	size_t maxcopy;
272f05cddf9SRui Paulo 	char pathname[PATH_MAX];
273f05cddf9SRui Paulo 	char *namep;
274f05cddf9SRui Paulo 
275f05cddf9SRui Paulo 	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
276f05cddf9SRui Paulo 		return;
277f05cddf9SRui Paulo 
278f05cddf9SRui Paulo 	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
279f05cddf9SRui Paulo 					  CONFIG_CTRL_IFACE_CLIENT_DIR);
280f05cddf9SRui Paulo 	if (dirnamelen >= sizeof(pathname)) {
281f05cddf9SRui Paulo 		closedir(dir);
282f05cddf9SRui Paulo 		return;
283f05cddf9SRui Paulo 	}
284f05cddf9SRui Paulo 	namep = pathname + dirnamelen;
285f05cddf9SRui Paulo 	maxcopy = PATH_MAX - dirnamelen;
286c1d255d3SCy Schubert 	while ((result = readdir(dir)) != NULL) {
287c1d255d3SCy Schubert 		if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
288f05cddf9SRui Paulo 			unlink(pathname);
289f05cddf9SRui Paulo 	}
290f05cddf9SRui Paulo 	closedir(dir);
291f05cddf9SRui Paulo }
292f05cddf9SRui Paulo #endif /* ANDROID */
293f05cddf9SRui Paulo 
294f05cddf9SRui Paulo #else /* CONFIG_CTRL_IFACE_UNIX */
295f05cddf9SRui Paulo 
296f05cddf9SRui Paulo #ifdef ANDROID
wpa_ctrl_cleanup(void)297f05cddf9SRui Paulo void wpa_ctrl_cleanup(void)
298f05cddf9SRui Paulo {
299f05cddf9SRui Paulo }
300f05cddf9SRui Paulo #endif /* ANDROID */
301f05cddf9SRui Paulo 
30239beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX */
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 
30539beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UDP
30639beb93cSSam Leffler 
wpa_ctrl_open(const char * ctrl_path)30739beb93cSSam Leffler struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
30839beb93cSSam Leffler {
30939beb93cSSam Leffler 	struct wpa_ctrl *ctrl;
31039beb93cSSam Leffler 	char buf[128];
31139beb93cSSam Leffler 	size_t len;
312f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
313f05cddf9SRui Paulo 	struct hostent *h;
314f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
31539beb93cSSam Leffler 
3165b9c547cSRui Paulo 	ctrl = os_zalloc(sizeof(*ctrl));
31739beb93cSSam Leffler 	if (ctrl == NULL)
31839beb93cSSam Leffler 		return NULL;
31939beb93cSSam Leffler 
3205b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3215b9c547cSRui Paulo 	ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
3225b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
32339beb93cSSam Leffler 	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
3245b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
32539beb93cSSam Leffler 	if (ctrl->s < 0) {
32639beb93cSSam Leffler 		perror("socket");
32739beb93cSSam Leffler 		os_free(ctrl);
32839beb93cSSam Leffler 		return NULL;
32939beb93cSSam Leffler 	}
33039beb93cSSam Leffler 
3315b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3325b9c547cSRui Paulo 	ctrl->local.sin6_family = AF_INET6;
3335b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3345b9c547cSRui Paulo 	ctrl->local.sin6_addr = in6addr_any;
3355b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3365b9c547cSRui Paulo 	inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
3375b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3385b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
33939beb93cSSam Leffler 	ctrl->local.sin_family = AF_INET;
340f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
341f05cddf9SRui Paulo 	ctrl->local.sin_addr.s_addr = INADDR_ANY;
342f05cddf9SRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
34339beb93cSSam Leffler 	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
344f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3455b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3465b9c547cSRui Paulo 
34739beb93cSSam Leffler 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
34839beb93cSSam Leffler 		 sizeof(ctrl->local)) < 0) {
34939beb93cSSam Leffler 		close(ctrl->s);
35039beb93cSSam Leffler 		os_free(ctrl);
35139beb93cSSam Leffler 		return NULL;
35239beb93cSSam Leffler 	}
35339beb93cSSam Leffler 
3545b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3555b9c547cSRui Paulo 	ctrl->dest.sin6_family = AF_INET6;
3565b9c547cSRui Paulo 	inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
3575b9c547cSRui Paulo 	ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
3585b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
35939beb93cSSam Leffler 	ctrl->dest.sin_family = AF_INET;
36039beb93cSSam Leffler 	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
36139beb93cSSam Leffler 	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
3625b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
363f05cddf9SRui Paulo 
364f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
365f05cddf9SRui Paulo 	if (ctrl_path) {
366f05cddf9SRui Paulo 		char *port, *name;
367f05cddf9SRui Paulo 		int port_id;
3685b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3695b9c547cSRui Paulo 		char *scope;
3705b9c547cSRui Paulo 		int scope_id = 0;
3715b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
372f05cddf9SRui Paulo 
373f05cddf9SRui Paulo 		name = os_strdup(ctrl_path);
374f05cddf9SRui Paulo 		if (name == NULL) {
375f05cddf9SRui Paulo 			close(ctrl->s);
376f05cddf9SRui Paulo 			os_free(ctrl);
377f05cddf9SRui Paulo 			return NULL;
378f05cddf9SRui Paulo 		}
3795b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3805b9c547cSRui Paulo 		port = os_strchr(name, ',');
3815b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
382f05cddf9SRui Paulo 		port = os_strchr(name, ':');
3835b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
384f05cddf9SRui Paulo 
385f05cddf9SRui Paulo 		if (port) {
386f05cddf9SRui Paulo 			port_id = atoi(&port[1]);
387f05cddf9SRui Paulo 			port[0] = '\0';
388f05cddf9SRui Paulo 		} else
389f05cddf9SRui Paulo 			port_id = WPA_CTRL_IFACE_PORT;
390f05cddf9SRui Paulo 
3915b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3925b9c547cSRui Paulo 		scope = os_strchr(name, '%');
3935b9c547cSRui Paulo 		if (scope) {
3945b9c547cSRui Paulo 			scope_id = if_nametoindex(&scope[1]);
3955b9c547cSRui Paulo 			scope[0] = '\0';
3965b9c547cSRui Paulo 		}
3975b9c547cSRui Paulo 		h = gethostbyname2(name, AF_INET6);
3985b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
399f05cddf9SRui Paulo 		h = gethostbyname(name);
4005b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
401f05cddf9SRui Paulo 		ctrl->remote_ip = os_strdup(name);
402f05cddf9SRui Paulo 		os_free(name);
403f05cddf9SRui Paulo 		if (h == NULL) {
404f05cddf9SRui Paulo 			perror("gethostbyname");
405f05cddf9SRui Paulo 			close(ctrl->s);
406f05cddf9SRui Paulo 			os_free(ctrl->remote_ip);
407f05cddf9SRui Paulo 			os_free(ctrl);
408f05cddf9SRui Paulo 			return NULL;
409f05cddf9SRui Paulo 		}
4105b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4115b9c547cSRui Paulo 		ctrl->dest.sin6_scope_id = scope_id;
4125b9c547cSRui Paulo 		ctrl->dest.sin6_port = htons(port_id);
4135b9c547cSRui Paulo 		os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
4145b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
415f05cddf9SRui Paulo 		ctrl->dest.sin_port = htons(port_id);
4165b9c547cSRui Paulo 		os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
4175b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
418f05cddf9SRui Paulo 	} else
419f05cddf9SRui Paulo 		ctrl->remote_ip = os_strdup("localhost");
420f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
421f05cddf9SRui Paulo 
42239beb93cSSam Leffler 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
42339beb93cSSam Leffler 		    sizeof(ctrl->dest)) < 0) {
4245b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4255b9c547cSRui Paulo 		char addr[INET6_ADDRSTRLEN];
4265b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
4275b9c547cSRui Paulo 			   inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
4285b9c547cSRui Paulo 				     sizeof(ctrl->dest)),
4295b9c547cSRui Paulo 			   ntohs(ctrl->dest.sin6_port),
4305b9c547cSRui Paulo 			   strerror(errno));
4315b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4325b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
4335b9c547cSRui Paulo 			   inet_ntoa(ctrl->dest.sin_addr),
4345b9c547cSRui Paulo 			   ntohs(ctrl->dest.sin_port),
4355b9c547cSRui Paulo 			   strerror(errno));
4365b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
43739beb93cSSam Leffler 		close(ctrl->s);
438f05cddf9SRui Paulo 		os_free(ctrl->remote_ip);
43939beb93cSSam Leffler 		os_free(ctrl);
44039beb93cSSam Leffler 		return NULL;
44139beb93cSSam Leffler 	}
44239beb93cSSam Leffler 
44339beb93cSSam Leffler 	len = sizeof(buf) - 1;
44439beb93cSSam Leffler 	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
44539beb93cSSam Leffler 		buf[len] = '\0';
44639beb93cSSam Leffler 		ctrl->cookie = os_strdup(buf);
44739beb93cSSam Leffler 	}
44839beb93cSSam Leffler 
449f05cddf9SRui Paulo 	if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
450f05cddf9SRui Paulo 		buf[len] = '\0';
451f05cddf9SRui Paulo 		ctrl->remote_ifname = os_strdup(buf);
452f05cddf9SRui Paulo 	}
453f05cddf9SRui Paulo 
45439beb93cSSam Leffler 	return ctrl;
45539beb93cSSam Leffler }
45639beb93cSSam Leffler 
45739beb93cSSam Leffler 
wpa_ctrl_get_remote_ifname(struct wpa_ctrl * ctrl)458f05cddf9SRui Paulo char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
459f05cddf9SRui Paulo {
460f05cddf9SRui Paulo #define WPA_CTRL_MAX_PS_NAME 100
461f05cddf9SRui Paulo 	static char ps[WPA_CTRL_MAX_PS_NAME] = {};
462f05cddf9SRui Paulo 	os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
463f05cddf9SRui Paulo 		    ctrl->remote_ip, ctrl->remote_ifname);
464f05cddf9SRui Paulo 	return ps;
465f05cddf9SRui Paulo }
466f05cddf9SRui Paulo 
467f05cddf9SRui Paulo 
wpa_ctrl_close(struct wpa_ctrl * ctrl)46839beb93cSSam Leffler void wpa_ctrl_close(struct wpa_ctrl *ctrl)
46939beb93cSSam Leffler {
47039beb93cSSam Leffler 	close(ctrl->s);
47139beb93cSSam Leffler 	os_free(ctrl->cookie);
472f05cddf9SRui Paulo 	os_free(ctrl->remote_ifname);
473f05cddf9SRui Paulo 	os_free(ctrl->remote_ip);
47439beb93cSSam Leffler 	os_free(ctrl);
47539beb93cSSam Leffler }
47639beb93cSSam Leffler 
47739beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UDP */
47839beb93cSSam Leffler 
47939beb93cSSam Leffler 
48039beb93cSSam Leffler #ifdef CTRL_IFACE_SOCKET
wpa_ctrl_request(struct wpa_ctrl * ctrl,const char * cmd,size_t cmd_len,char * reply,size_t * reply_len,void (* msg_cb)(char * msg,size_t len))48139beb93cSSam Leffler int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
48239beb93cSSam Leffler 		     char *reply, size_t *reply_len,
48339beb93cSSam Leffler 		     void (*msg_cb)(char *msg, size_t len))
48439beb93cSSam Leffler {
48539beb93cSSam Leffler 	struct timeval tv;
486*a90b9d01SCy Schubert 	struct os_reltime started_at, ending_at;
48739beb93cSSam Leffler 	int res;
48839beb93cSSam Leffler 	fd_set rfds;
48939beb93cSSam Leffler 	const char *_cmd;
49039beb93cSSam Leffler 	char *cmd_buf = NULL;
49139beb93cSSam Leffler 	size_t _cmd_len;
49239beb93cSSam Leffler 
49339beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UDP
49439beb93cSSam Leffler 	if (ctrl->cookie) {
49539beb93cSSam Leffler 		char *pos;
49639beb93cSSam Leffler 		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
49739beb93cSSam Leffler 		cmd_buf = os_malloc(_cmd_len);
49839beb93cSSam Leffler 		if (cmd_buf == NULL)
49939beb93cSSam Leffler 			return -1;
50039beb93cSSam Leffler 		_cmd = cmd_buf;
50139beb93cSSam Leffler 		pos = cmd_buf;
50239beb93cSSam Leffler 		os_strlcpy(pos, ctrl->cookie, _cmd_len);
50339beb93cSSam Leffler 		pos += os_strlen(ctrl->cookie);
50439beb93cSSam Leffler 		*pos++ = ' ';
50539beb93cSSam Leffler 		os_memcpy(pos, cmd, cmd_len);
50639beb93cSSam Leffler 	} else
50739beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UDP */
50839beb93cSSam Leffler 	{
50939beb93cSSam Leffler 		_cmd = cmd;
51039beb93cSSam Leffler 		_cmd_len = cmd_len;
51139beb93cSSam Leffler 	}
51239beb93cSSam Leffler 
513f05cddf9SRui Paulo 	errno = 0;
514f05cddf9SRui Paulo 	started_at.sec = 0;
515f05cddf9SRui Paulo 	started_at.usec = 0;
516f05cddf9SRui Paulo retry_send:
51739beb93cSSam Leffler 	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
518f05cddf9SRui Paulo 		if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
519f05cddf9SRui Paulo 		{
520f05cddf9SRui Paulo 			/*
521f05cddf9SRui Paulo 			 * Must be a non-blocking socket... Try for a bit
522f05cddf9SRui Paulo 			 * longer before giving up.
523f05cddf9SRui Paulo 			 */
524f05cddf9SRui Paulo 			if (started_at.sec == 0)
5255b9c547cSRui Paulo 				os_get_reltime(&started_at);
526f05cddf9SRui Paulo 			else {
5275b9c547cSRui Paulo 				struct os_reltime n;
5285b9c547cSRui Paulo 				os_get_reltime(&n);
529f05cddf9SRui Paulo 				/* Try for a few seconds. */
5305b9c547cSRui Paulo 				if (os_reltime_expired(&n, &started_at, 5))
531f05cddf9SRui Paulo 					goto send_err;
532f05cddf9SRui Paulo 			}
533f05cddf9SRui Paulo 			os_sleep(1, 0);
534f05cddf9SRui Paulo 			goto retry_send;
535f05cddf9SRui Paulo 		}
536f05cddf9SRui Paulo 	send_err:
53739beb93cSSam Leffler 		os_free(cmd_buf);
53839beb93cSSam Leffler 		return -1;
53939beb93cSSam Leffler 	}
54039beb93cSSam Leffler 	os_free(cmd_buf);
54139beb93cSSam Leffler 
542*a90b9d01SCy Schubert 	os_get_reltime(&ending_at);
543*a90b9d01SCy Schubert 	ending_at.sec += 10;
544*a90b9d01SCy Schubert 
54539beb93cSSam Leffler 	for (;;) {
546*a90b9d01SCy Schubert 		struct os_reltime diff;
547*a90b9d01SCy Schubert 
548*a90b9d01SCy Schubert 		os_get_reltime(&started_at);
549*a90b9d01SCy Schubert 		if (os_reltime_before(&ending_at, &started_at))
550*a90b9d01SCy Schubert 			return -2;
551*a90b9d01SCy Schubert 		os_reltime_sub(&ending_at, &started_at, &diff);
552*a90b9d01SCy Schubert 		tv.tv_sec = diff.sec;
553*a90b9d01SCy Schubert 		tv.tv_usec = diff.usec;
554*a90b9d01SCy Schubert 
55539beb93cSSam Leffler 		FD_ZERO(&rfds);
55639beb93cSSam Leffler 		FD_SET(ctrl->s, &rfds);
55739beb93cSSam Leffler 		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
558780fb4a2SCy Schubert 		if (res < 0 && errno == EINTR)
559780fb4a2SCy Schubert 			continue;
560f05cddf9SRui Paulo 		if (res < 0)
561f05cddf9SRui Paulo 			return res;
56239beb93cSSam Leffler 		if (FD_ISSET(ctrl->s, &rfds)) {
56339beb93cSSam Leffler 			res = recv(ctrl->s, reply, *reply_len, 0);
56439beb93cSSam Leffler 			if (res < 0)
56539beb93cSSam Leffler 				return res;
5664bc52338SCy Schubert 			if ((res > 0 && reply[0] == '<') ||
5674bc52338SCy Schubert 			    (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
56839beb93cSSam Leffler 				/* This is an unsolicited message from
56939beb93cSSam Leffler 				 * wpa_supplicant, not the reply to the
57039beb93cSSam Leffler 				 * request. Use msg_cb to report this to the
57139beb93cSSam Leffler 				 * caller. */
57239beb93cSSam Leffler 				if (msg_cb) {
57339beb93cSSam Leffler 					/* Make sure the message is nul
57439beb93cSSam Leffler 					 * terminated. */
57539beb93cSSam Leffler 					if ((size_t) res == *reply_len)
57639beb93cSSam Leffler 						res = (*reply_len) - 1;
57739beb93cSSam Leffler 					reply[res] = '\0';
57839beb93cSSam Leffler 					msg_cb(reply, res);
57939beb93cSSam Leffler 				}
58039beb93cSSam Leffler 				continue;
58139beb93cSSam Leffler 			}
58239beb93cSSam Leffler 			*reply_len = res;
58339beb93cSSam Leffler 			break;
58439beb93cSSam Leffler 		} else {
58539beb93cSSam Leffler 			return -2;
58639beb93cSSam Leffler 		}
58739beb93cSSam Leffler 	}
58839beb93cSSam Leffler 	return 0;
58939beb93cSSam Leffler }
59039beb93cSSam Leffler #endif /* CTRL_IFACE_SOCKET */
59139beb93cSSam Leffler 
59239beb93cSSam Leffler 
wpa_ctrl_attach_helper(struct wpa_ctrl * ctrl,int attach)59339beb93cSSam Leffler static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
59439beb93cSSam Leffler {
59539beb93cSSam Leffler 	char buf[10];
59639beb93cSSam Leffler 	int ret;
59739beb93cSSam Leffler 	size_t len = 10;
59839beb93cSSam Leffler 
59939beb93cSSam Leffler 	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
60039beb93cSSam Leffler 			       buf, &len, NULL);
60139beb93cSSam Leffler 	if (ret < 0)
60239beb93cSSam Leffler 		return ret;
60339beb93cSSam Leffler 	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
60439beb93cSSam Leffler 		return 0;
60539beb93cSSam Leffler 	return -1;
60639beb93cSSam Leffler }
60739beb93cSSam Leffler 
60839beb93cSSam Leffler 
wpa_ctrl_attach(struct wpa_ctrl * ctrl)60939beb93cSSam Leffler int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
61039beb93cSSam Leffler {
61139beb93cSSam Leffler 	return wpa_ctrl_attach_helper(ctrl, 1);
61239beb93cSSam Leffler }
61339beb93cSSam Leffler 
61439beb93cSSam Leffler 
wpa_ctrl_detach(struct wpa_ctrl * ctrl)61539beb93cSSam Leffler int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
61639beb93cSSam Leffler {
61739beb93cSSam Leffler 	return wpa_ctrl_attach_helper(ctrl, 0);
61839beb93cSSam Leffler }
61939beb93cSSam Leffler 
62039beb93cSSam Leffler 
62139beb93cSSam Leffler #ifdef CTRL_IFACE_SOCKET
62239beb93cSSam Leffler 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)62339beb93cSSam Leffler int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
62439beb93cSSam Leffler {
62539beb93cSSam Leffler 	int res;
62639beb93cSSam Leffler 
62739beb93cSSam Leffler 	res = recv(ctrl->s, reply, *reply_len, 0);
62839beb93cSSam Leffler 	if (res < 0)
62939beb93cSSam Leffler 		return res;
63039beb93cSSam Leffler 	*reply_len = res;
63139beb93cSSam Leffler 	return 0;
63239beb93cSSam Leffler }
63339beb93cSSam Leffler 
63439beb93cSSam Leffler 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)63539beb93cSSam Leffler int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
63639beb93cSSam Leffler {
63739beb93cSSam Leffler 	struct timeval tv;
63839beb93cSSam Leffler 	fd_set rfds;
63939beb93cSSam Leffler 	tv.tv_sec = 0;
64039beb93cSSam Leffler 	tv.tv_usec = 0;
64139beb93cSSam Leffler 	FD_ZERO(&rfds);
64239beb93cSSam Leffler 	FD_SET(ctrl->s, &rfds);
64339beb93cSSam Leffler 	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
64439beb93cSSam Leffler 	return FD_ISSET(ctrl->s, &rfds);
64539beb93cSSam Leffler }
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)64839beb93cSSam Leffler int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
64939beb93cSSam Leffler {
65039beb93cSSam Leffler 	return ctrl->s;
65139beb93cSSam Leffler }
65239beb93cSSam Leffler 
65339beb93cSSam Leffler #endif /* CTRL_IFACE_SOCKET */
65439beb93cSSam Leffler 
65539beb93cSSam Leffler 
65639beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
65739beb93cSSam Leffler 
65839beb93cSSam Leffler #ifndef WPA_SUPPLICANT_NAMED_PIPE
65939beb93cSSam Leffler #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
66039beb93cSSam Leffler #endif
66139beb93cSSam Leffler #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
66239beb93cSSam Leffler 
wpa_ctrl_open(const char * ctrl_path)66339beb93cSSam Leffler struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
66439beb93cSSam Leffler {
66539beb93cSSam Leffler 	struct wpa_ctrl *ctrl;
66639beb93cSSam Leffler 	DWORD mode;
66739beb93cSSam Leffler 	TCHAR name[256];
66839beb93cSSam Leffler 	int i, ret;
66939beb93cSSam Leffler 
67039beb93cSSam Leffler 	ctrl = os_malloc(sizeof(*ctrl));
67139beb93cSSam Leffler 	if (ctrl == NULL)
67239beb93cSSam Leffler 		return NULL;
67339beb93cSSam Leffler 	os_memset(ctrl, 0, sizeof(*ctrl));
67439beb93cSSam Leffler 
67539beb93cSSam Leffler #ifdef UNICODE
67639beb93cSSam Leffler 	if (ctrl_path == NULL)
67739beb93cSSam Leffler 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
67839beb93cSSam Leffler 	else
67939beb93cSSam Leffler 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
68039beb93cSSam Leffler 				 ctrl_path);
68139beb93cSSam Leffler #else /* UNICODE */
68239beb93cSSam Leffler 	if (ctrl_path == NULL)
68339beb93cSSam Leffler 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
68439beb93cSSam Leffler 	else
68539beb93cSSam Leffler 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
68639beb93cSSam Leffler 				  ctrl_path);
68739beb93cSSam Leffler #endif /* UNICODE */
6885b9c547cSRui Paulo 	if (os_snprintf_error(256, ret)) {
68939beb93cSSam Leffler 		os_free(ctrl);
69039beb93cSSam Leffler 		return NULL;
69139beb93cSSam Leffler 	}
69239beb93cSSam Leffler 
69339beb93cSSam Leffler 	for (i = 0; i < 10; i++) {
69439beb93cSSam Leffler 		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
69539beb93cSSam Leffler 					NULL, OPEN_EXISTING, 0, NULL);
69639beb93cSSam Leffler 		/*
69739beb93cSSam Leffler 		 * Current named pipe server side in wpa_supplicant is
69839beb93cSSam Leffler 		 * re-opening the pipe for new clients only after the previous
69939beb93cSSam Leffler 		 * one is taken into use. This leaves a small window for race
70039beb93cSSam Leffler 		 * conditions when two connections are being opened at almost
70139beb93cSSam Leffler 		 * the same time. Retry if that was the case.
70239beb93cSSam Leffler 		 */
70339beb93cSSam Leffler 		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
70439beb93cSSam Leffler 		    GetLastError() != ERROR_PIPE_BUSY)
70539beb93cSSam Leffler 			break;
70639beb93cSSam Leffler 		WaitNamedPipe(name, 1000);
70739beb93cSSam Leffler 	}
70839beb93cSSam Leffler 	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
70939beb93cSSam Leffler 		os_free(ctrl);
71039beb93cSSam Leffler 		return NULL;
71139beb93cSSam Leffler 	}
71239beb93cSSam Leffler 
71339beb93cSSam Leffler 	mode = PIPE_READMODE_MESSAGE;
71439beb93cSSam Leffler 	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
71539beb93cSSam Leffler 		CloseHandle(ctrl->pipe);
71639beb93cSSam Leffler 		os_free(ctrl);
71739beb93cSSam Leffler 		return NULL;
71839beb93cSSam Leffler 	}
71939beb93cSSam Leffler 
72039beb93cSSam Leffler 	return ctrl;
72139beb93cSSam Leffler }
72239beb93cSSam Leffler 
72339beb93cSSam Leffler 
wpa_ctrl_close(struct wpa_ctrl * ctrl)72439beb93cSSam Leffler void wpa_ctrl_close(struct wpa_ctrl *ctrl)
72539beb93cSSam Leffler {
72639beb93cSSam Leffler 	CloseHandle(ctrl->pipe);
72739beb93cSSam Leffler 	os_free(ctrl);
72839beb93cSSam Leffler }
72939beb93cSSam Leffler 
73039beb93cSSam Leffler 
wpa_ctrl_request(struct wpa_ctrl * ctrl,const char * cmd,size_t cmd_len,char * reply,size_t * reply_len,void (* msg_cb)(char * msg,size_t len))73139beb93cSSam Leffler int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
73239beb93cSSam Leffler 		     char *reply, size_t *reply_len,
73339beb93cSSam Leffler 		     void (*msg_cb)(char *msg, size_t len))
73439beb93cSSam Leffler {
73539beb93cSSam Leffler 	DWORD written;
73639beb93cSSam Leffler 	DWORD readlen = *reply_len;
73739beb93cSSam Leffler 
73839beb93cSSam Leffler 	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
73939beb93cSSam Leffler 		return -1;
74039beb93cSSam Leffler 
74139beb93cSSam Leffler 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
74239beb93cSSam Leffler 		return -1;
74339beb93cSSam Leffler 	*reply_len = readlen;
74439beb93cSSam Leffler 
74539beb93cSSam Leffler 	return 0;
74639beb93cSSam Leffler }
74739beb93cSSam Leffler 
74839beb93cSSam Leffler 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)74939beb93cSSam Leffler int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
75039beb93cSSam Leffler {
75139beb93cSSam Leffler 	DWORD len = *reply_len;
75239beb93cSSam Leffler 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
75339beb93cSSam Leffler 		return -1;
75439beb93cSSam Leffler 	*reply_len = len;
75539beb93cSSam Leffler 	return 0;
75639beb93cSSam Leffler }
75739beb93cSSam Leffler 
75839beb93cSSam Leffler 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)75939beb93cSSam Leffler int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
76039beb93cSSam Leffler {
76139beb93cSSam Leffler 	DWORD left;
76239beb93cSSam Leffler 
76339beb93cSSam Leffler 	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
76439beb93cSSam Leffler 		return -1;
76539beb93cSSam Leffler 	return left ? 1 : 0;
76639beb93cSSam Leffler }
76739beb93cSSam Leffler 
76839beb93cSSam Leffler 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)76939beb93cSSam Leffler int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
77039beb93cSSam Leffler {
77139beb93cSSam Leffler 	return -1;
77239beb93cSSam Leffler }
77339beb93cSSam Leffler 
77439beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
77539beb93cSSam Leffler 
77639beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE */
777