16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * wpa_supplicant/hostapd control interface library
36d49e1aeSJan Lentfer  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer 
116d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE
126d49e1aeSJan Lentfer 
136d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UNIX
14*a1157835SDaniel Fojt #include <sys/stat.h>
15*a1157835SDaniel Fojt #include <fcntl.h>
166d49e1aeSJan Lentfer #include <sys/un.h>
173ff40c12SJohn Marino #include <unistd.h>
183ff40c12SJohn Marino #include <fcntl.h>
196d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX */
203ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
213ff40c12SJohn Marino #include <netdb.h>
223ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
233ff40c12SJohn Marino 
243ff40c12SJohn Marino #ifdef ANDROID
253ff40c12SJohn Marino #include <dirent.h>
26*a1157835SDaniel Fojt #include <sys/stat.h>
273ff40c12SJohn Marino #include <cutils/sockets.h>
283ff40c12SJohn Marino #include "private/android_filesystem_config.h"
293ff40c12SJohn Marino #endif /* ANDROID */
306d49e1aeSJan Lentfer 
31*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
32*a1157835SDaniel Fojt #include <net/if.h>
33*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
34*a1157835SDaniel Fojt 
356d49e1aeSJan Lentfer #include "wpa_ctrl.h"
366d49e1aeSJan Lentfer #include "common.h"
376d49e1aeSJan Lentfer 
386d49e1aeSJan Lentfer 
396d49e1aeSJan Lentfer #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
406d49e1aeSJan Lentfer #define CTRL_IFACE_SOCKET
416d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
426d49e1aeSJan Lentfer 
436d49e1aeSJan Lentfer 
446d49e1aeSJan Lentfer /**
456d49e1aeSJan Lentfer  * struct wpa_ctrl - Internal structure for control interface library
466d49e1aeSJan Lentfer  *
476d49e1aeSJan Lentfer  * This structure is used by the wpa_supplicant/hostapd control interface
486d49e1aeSJan Lentfer  * library to store internal data. Programs using the library should not touch
496d49e1aeSJan Lentfer  * this data directly. They can only use the pointer to the data structure as
506d49e1aeSJan Lentfer  * an identifier for the control interface connection and use this as one of
516d49e1aeSJan Lentfer  * the arguments for most of the control interface library functions.
526d49e1aeSJan Lentfer  */
536d49e1aeSJan Lentfer struct wpa_ctrl {
546d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UDP
556d49e1aeSJan Lentfer 	int s;
56*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
57*a1157835SDaniel Fojt 	struct sockaddr_in6 local;
58*a1157835SDaniel Fojt 	struct sockaddr_in6 dest;
59*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
606d49e1aeSJan Lentfer 	struct sockaddr_in local;
616d49e1aeSJan Lentfer 	struct sockaddr_in dest;
62*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
636d49e1aeSJan Lentfer 	char *cookie;
643ff40c12SJohn Marino 	char *remote_ifname;
653ff40c12SJohn Marino 	char *remote_ip;
666d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UDP */
676d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UNIX
686d49e1aeSJan Lentfer 	int s;
696d49e1aeSJan Lentfer 	struct sockaddr_un local;
706d49e1aeSJan Lentfer 	struct sockaddr_un dest;
716d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX */
726d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
736d49e1aeSJan Lentfer 	HANDLE pipe;
746d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
756d49e1aeSJan Lentfer };
766d49e1aeSJan Lentfer 
776d49e1aeSJan Lentfer 
786d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UNIX
796d49e1aeSJan Lentfer 
803ff40c12SJohn Marino #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
813ff40c12SJohn Marino #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
823ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
833ff40c12SJohn Marino #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
843ff40c12SJohn Marino #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
853ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
863ff40c12SJohn Marino 
873ff40c12SJohn Marino 
wpa_ctrl_open(const char * ctrl_path)886d49e1aeSJan Lentfer struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
896d49e1aeSJan Lentfer {
90*a1157835SDaniel Fojt 	return wpa_ctrl_open2(ctrl_path, NULL);
91*a1157835SDaniel Fojt }
92*a1157835SDaniel Fojt 
93*a1157835SDaniel Fojt 
wpa_ctrl_open2(const char * ctrl_path,const char * cli_path)94*a1157835SDaniel Fojt struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
95*a1157835SDaniel Fojt 				 const char *cli_path)
96*a1157835SDaniel Fojt {
976d49e1aeSJan Lentfer 	struct wpa_ctrl *ctrl;
986d49e1aeSJan Lentfer 	static int counter = 0;
996d49e1aeSJan Lentfer 	int ret;
1006d49e1aeSJan Lentfer 	size_t res;
1016d49e1aeSJan Lentfer 	int tries = 0;
1023ff40c12SJohn Marino 	int flags;
1033ff40c12SJohn Marino 
1043ff40c12SJohn Marino 	if (ctrl_path == NULL)
1053ff40c12SJohn Marino 		return NULL;
1066d49e1aeSJan Lentfer 
107*a1157835SDaniel Fojt 	ctrl = os_zalloc(sizeof(*ctrl));
1086d49e1aeSJan Lentfer 	if (ctrl == NULL)
1096d49e1aeSJan Lentfer 		return NULL;
1106d49e1aeSJan Lentfer 
1116d49e1aeSJan Lentfer 	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
1126d49e1aeSJan Lentfer 	if (ctrl->s < 0) {
1136d49e1aeSJan Lentfer 		os_free(ctrl);
1146d49e1aeSJan Lentfer 		return NULL;
1156d49e1aeSJan Lentfer 	}
1166d49e1aeSJan Lentfer 
1176d49e1aeSJan Lentfer 	ctrl->local.sun_family = AF_UNIX;
1186d49e1aeSJan Lentfer 	counter++;
1196d49e1aeSJan Lentfer try_again:
120*a1157835SDaniel Fojt 	if (cli_path && cli_path[0] == '/') {
121*a1157835SDaniel Fojt 		ret = os_snprintf(ctrl->local.sun_path,
122*a1157835SDaniel Fojt 				  sizeof(ctrl->local.sun_path),
123*a1157835SDaniel Fojt 				  "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
124*a1157835SDaniel Fojt 				  cli_path, (int) getpid(), counter);
125*a1157835SDaniel Fojt 	} else {
126*a1157835SDaniel Fojt 		ret = os_snprintf(ctrl->local.sun_path,
127*a1157835SDaniel Fojt 				  sizeof(ctrl->local.sun_path),
1283ff40c12SJohn Marino 				  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
1293ff40c12SJohn Marino 				  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
1303ff40c12SJohn Marino 				  (int) getpid(), counter);
131*a1157835SDaniel Fojt 	}
132*a1157835SDaniel Fojt 	if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
1336d49e1aeSJan Lentfer 		close(ctrl->s);
1346d49e1aeSJan Lentfer 		os_free(ctrl);
1356d49e1aeSJan Lentfer 		return NULL;
1366d49e1aeSJan Lentfer 	}
1376d49e1aeSJan Lentfer 	tries++;
138*a1157835SDaniel Fojt #ifdef ANDROID
139*a1157835SDaniel Fojt 	/* Set client socket file permissions so that bind() creates the client
140*a1157835SDaniel Fojt 	 * socket with these permissions and there is no need to try to change
141*a1157835SDaniel Fojt 	 * them with chmod() after bind() which would have potential issues with
142*a1157835SDaniel Fojt 	 * race conditions. These permissions are needed to make sure the server
143*a1157835SDaniel Fojt 	 * side (wpa_supplicant or hostapd) can reply to the control interface
144*a1157835SDaniel Fojt 	 * messages.
145*a1157835SDaniel Fojt 	 *
146*a1157835SDaniel Fojt 	 * The lchown() calls below after bind() are also part of the needed
147*a1157835SDaniel Fojt 	 * operations to allow the response to go through. Those are using the
148*a1157835SDaniel Fojt 	 * no-deference-symlinks version to avoid races. */
149*a1157835SDaniel Fojt 	fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
150*a1157835SDaniel Fojt #endif /* ANDROID */
1516d49e1aeSJan Lentfer 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
1526d49e1aeSJan Lentfer 		    sizeof(ctrl->local)) < 0) {
1536d49e1aeSJan Lentfer 		if (errno == EADDRINUSE && tries < 2) {
1546d49e1aeSJan Lentfer 			/*
1556d49e1aeSJan Lentfer 			 * getpid() returns unique identifier for this instance
1566d49e1aeSJan Lentfer 			 * of wpa_ctrl, so the existing socket file must have
1576d49e1aeSJan Lentfer 			 * been left by unclean termination of an earlier run.
1586d49e1aeSJan Lentfer 			 * Remove the file and try again.
1596d49e1aeSJan Lentfer 			 */
1606d49e1aeSJan Lentfer 			unlink(ctrl->local.sun_path);
1616d49e1aeSJan Lentfer 			goto try_again;
1626d49e1aeSJan Lentfer 		}
1636d49e1aeSJan Lentfer 		close(ctrl->s);
1646d49e1aeSJan Lentfer 		os_free(ctrl);
1656d49e1aeSJan Lentfer 		return NULL;
1666d49e1aeSJan Lentfer 	}
1676d49e1aeSJan Lentfer 
1683ff40c12SJohn Marino #ifdef ANDROID
169*a1157835SDaniel Fojt 	/* Set group even if we do not have privileges to change owner */
170*a1157835SDaniel Fojt 	lchown(ctrl->local.sun_path, -1, AID_WIFI);
171*a1157835SDaniel Fojt 	lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
1723ff40c12SJohn Marino 
1733ff40c12SJohn Marino 	if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
1743ff40c12SJohn Marino 		if (socket_local_client_connect(
1753ff40c12SJohn Marino 			    ctrl->s, ctrl_path + 9,
1763ff40c12SJohn Marino 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
1773ff40c12SJohn Marino 			    SOCK_DGRAM) < 0) {
1783ff40c12SJohn Marino 			close(ctrl->s);
1793ff40c12SJohn Marino 			unlink(ctrl->local.sun_path);
1803ff40c12SJohn Marino 			os_free(ctrl);
1813ff40c12SJohn Marino 			return NULL;
1823ff40c12SJohn Marino 		}
1833ff40c12SJohn Marino 		return ctrl;
1843ff40c12SJohn Marino 	}
1853ff40c12SJohn Marino 
1863ff40c12SJohn Marino 	/*
1873ff40c12SJohn Marino 	 * If the ctrl_path isn't an absolute pathname, assume that
1883ff40c12SJohn Marino 	 * it's the name of a socket in the Android reserved namespace.
1893ff40c12SJohn Marino 	 * Otherwise, it's a normal UNIX domain socket appearing in the
1903ff40c12SJohn Marino 	 * filesystem.
1913ff40c12SJohn Marino 	 */
1923ff40c12SJohn Marino 	if (*ctrl_path != '/') {
1933ff40c12SJohn Marino 		char buf[21];
1943ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
1953ff40c12SJohn Marino 		if (socket_local_client_connect(
1963ff40c12SJohn Marino 			    ctrl->s, buf,
1973ff40c12SJohn Marino 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
1983ff40c12SJohn Marino 			    SOCK_DGRAM) < 0) {
1993ff40c12SJohn Marino 			close(ctrl->s);
2003ff40c12SJohn Marino 			unlink(ctrl->local.sun_path);
2013ff40c12SJohn Marino 			os_free(ctrl);
2023ff40c12SJohn Marino 			return NULL;
2033ff40c12SJohn Marino 		}
2043ff40c12SJohn Marino 		return ctrl;
2053ff40c12SJohn Marino 	}
2063ff40c12SJohn Marino #endif /* ANDROID */
2073ff40c12SJohn Marino 
2086d49e1aeSJan Lentfer 	ctrl->dest.sun_family = AF_UNIX;
2093ff40c12SJohn Marino 	if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
2103ff40c12SJohn Marino 		ctrl->dest.sun_path[0] = '\0';
2113ff40c12SJohn Marino 		os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
2123ff40c12SJohn Marino 			   sizeof(ctrl->dest.sun_path) - 1);
2133ff40c12SJohn Marino 	} else {
2146d49e1aeSJan Lentfer 		res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
2156d49e1aeSJan Lentfer 				 sizeof(ctrl->dest.sun_path));
2166d49e1aeSJan Lentfer 		if (res >= sizeof(ctrl->dest.sun_path)) {
2176d49e1aeSJan Lentfer 			close(ctrl->s);
2186d49e1aeSJan Lentfer 			os_free(ctrl);
2196d49e1aeSJan Lentfer 			return NULL;
2206d49e1aeSJan Lentfer 		}
2213ff40c12SJohn Marino 	}
2226d49e1aeSJan Lentfer 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
2236d49e1aeSJan Lentfer 		    sizeof(ctrl->dest)) < 0) {
2246d49e1aeSJan Lentfer 		close(ctrl->s);
2256d49e1aeSJan Lentfer 		unlink(ctrl->local.sun_path);
2266d49e1aeSJan Lentfer 		os_free(ctrl);
2276d49e1aeSJan Lentfer 		return NULL;
2286d49e1aeSJan Lentfer 	}
2296d49e1aeSJan Lentfer 
2303ff40c12SJohn Marino 	/*
2313ff40c12SJohn Marino 	 * Make socket non-blocking so that we don't hang forever if
2323ff40c12SJohn Marino 	 * target dies unexpectedly.
2333ff40c12SJohn Marino 	 */
2343ff40c12SJohn Marino 	flags = fcntl(ctrl->s, F_GETFL);
2353ff40c12SJohn Marino 	if (flags >= 0) {
2363ff40c12SJohn Marino 		flags |= O_NONBLOCK;
2373ff40c12SJohn Marino 		if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
2383ff40c12SJohn Marino 			perror("fcntl(ctrl->s, O_NONBLOCK)");
2393ff40c12SJohn Marino 			/* Not fatal, continue on.*/
2403ff40c12SJohn Marino 		}
2413ff40c12SJohn Marino 	}
2423ff40c12SJohn Marino 
2436d49e1aeSJan Lentfer 	return ctrl;
2446d49e1aeSJan Lentfer }
2456d49e1aeSJan Lentfer 
2466d49e1aeSJan Lentfer 
wpa_ctrl_close(struct wpa_ctrl * ctrl)2476d49e1aeSJan Lentfer void wpa_ctrl_close(struct wpa_ctrl *ctrl)
2486d49e1aeSJan Lentfer {
2493ff40c12SJohn Marino 	if (ctrl == NULL)
2503ff40c12SJohn Marino 		return;
2516d49e1aeSJan Lentfer 	unlink(ctrl->local.sun_path);
2523ff40c12SJohn Marino 	if (ctrl->s >= 0)
2536d49e1aeSJan Lentfer 		close(ctrl->s);
2546d49e1aeSJan Lentfer 	os_free(ctrl);
2556d49e1aeSJan Lentfer }
2566d49e1aeSJan Lentfer 
2573ff40c12SJohn Marino 
2583ff40c12SJohn Marino #ifdef ANDROID
2593ff40c12SJohn Marino /**
2603ff40c12SJohn Marino  * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
2613ff40c12SJohn Marino  * may be left over from clients that were previously connected to
2623ff40c12SJohn Marino  * wpa_supplicant. This keeps these files from being orphaned in the
2633ff40c12SJohn Marino  * event of crashes that prevented them from being removed as part
2643ff40c12SJohn Marino  * of the normal orderly shutdown.
2653ff40c12SJohn Marino  */
wpa_ctrl_cleanup(void)2663ff40c12SJohn Marino void wpa_ctrl_cleanup(void)
2673ff40c12SJohn Marino {
2683ff40c12SJohn Marino 	DIR *dir;
2693ff40c12SJohn Marino 	struct dirent entry;
2703ff40c12SJohn Marino 	struct dirent *result;
2713ff40c12SJohn Marino 	size_t dirnamelen;
2723ff40c12SJohn Marino 	size_t maxcopy;
2733ff40c12SJohn Marino 	char pathname[PATH_MAX];
2743ff40c12SJohn Marino 	char *namep;
2753ff40c12SJohn Marino 
2763ff40c12SJohn Marino 	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
2773ff40c12SJohn Marino 		return;
2783ff40c12SJohn Marino 
2793ff40c12SJohn Marino 	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
2803ff40c12SJohn Marino 					  CONFIG_CTRL_IFACE_CLIENT_DIR);
2813ff40c12SJohn Marino 	if (dirnamelen >= sizeof(pathname)) {
2823ff40c12SJohn Marino 		closedir(dir);
2833ff40c12SJohn Marino 		return;
2843ff40c12SJohn Marino 	}
2853ff40c12SJohn Marino 	namep = pathname + dirnamelen;
2863ff40c12SJohn Marino 	maxcopy = PATH_MAX - dirnamelen;
2873ff40c12SJohn Marino 	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
2883ff40c12SJohn Marino 		if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
2893ff40c12SJohn Marino 			unlink(pathname);
2903ff40c12SJohn Marino 	}
2913ff40c12SJohn Marino 	closedir(dir);
2923ff40c12SJohn Marino }
2933ff40c12SJohn Marino #endif /* ANDROID */
2943ff40c12SJohn Marino 
2953ff40c12SJohn Marino #else /* CONFIG_CTRL_IFACE_UNIX */
2963ff40c12SJohn Marino 
2973ff40c12SJohn Marino #ifdef ANDROID
wpa_ctrl_cleanup(void)2983ff40c12SJohn Marino void wpa_ctrl_cleanup(void)
2993ff40c12SJohn Marino {
3003ff40c12SJohn Marino }
3013ff40c12SJohn Marino #endif /* ANDROID */
3023ff40c12SJohn Marino 
3036d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX */
3046d49e1aeSJan Lentfer 
3056d49e1aeSJan Lentfer 
3066d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UDP
3076d49e1aeSJan Lentfer 
wpa_ctrl_open(const char * ctrl_path)3086d49e1aeSJan Lentfer struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
3096d49e1aeSJan Lentfer {
3106d49e1aeSJan Lentfer 	struct wpa_ctrl *ctrl;
3116d49e1aeSJan Lentfer 	char buf[128];
3126d49e1aeSJan Lentfer 	size_t len;
3133ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3143ff40c12SJohn Marino 	struct hostent *h;
3153ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3166d49e1aeSJan Lentfer 
317*a1157835SDaniel Fojt 	ctrl = os_zalloc(sizeof(*ctrl));
3186d49e1aeSJan Lentfer 	if (ctrl == NULL)
3196d49e1aeSJan Lentfer 		return NULL;
3206d49e1aeSJan Lentfer 
321*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
322*a1157835SDaniel Fojt 	ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
323*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3246d49e1aeSJan Lentfer 	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
325*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3266d49e1aeSJan Lentfer 	if (ctrl->s < 0) {
3276d49e1aeSJan Lentfer 		perror("socket");
3286d49e1aeSJan Lentfer 		os_free(ctrl);
3296d49e1aeSJan Lentfer 		return NULL;
3306d49e1aeSJan Lentfer 	}
3316d49e1aeSJan Lentfer 
332*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
333*a1157835SDaniel Fojt 	ctrl->local.sin6_family = AF_INET6;
334*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
335*a1157835SDaniel Fojt 	ctrl->local.sin6_addr = in6addr_any;
336*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
337*a1157835SDaniel Fojt 	inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
338*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
339*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3406d49e1aeSJan Lentfer 	ctrl->local.sin_family = AF_INET;
3413ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3423ff40c12SJohn Marino 	ctrl->local.sin_addr.s_addr = INADDR_ANY;
3433ff40c12SJohn Marino #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3446d49e1aeSJan Lentfer 	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
3453ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
346*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
347*a1157835SDaniel Fojt 
3486d49e1aeSJan Lentfer 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
3496d49e1aeSJan Lentfer 		 sizeof(ctrl->local)) < 0) {
3506d49e1aeSJan Lentfer 		close(ctrl->s);
3516d49e1aeSJan Lentfer 		os_free(ctrl);
3526d49e1aeSJan Lentfer 		return NULL;
3536d49e1aeSJan Lentfer 	}
3546d49e1aeSJan Lentfer 
355*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
356*a1157835SDaniel Fojt 	ctrl->dest.sin6_family = AF_INET6;
357*a1157835SDaniel Fojt 	inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
358*a1157835SDaniel Fojt 	ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
359*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3606d49e1aeSJan Lentfer 	ctrl->dest.sin_family = AF_INET;
3616d49e1aeSJan Lentfer 	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
3626d49e1aeSJan Lentfer 	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
363*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3643ff40c12SJohn Marino 
3653ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3663ff40c12SJohn Marino 	if (ctrl_path) {
3673ff40c12SJohn Marino 		char *port, *name;
3683ff40c12SJohn Marino 		int port_id;
369*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
370*a1157835SDaniel Fojt 		char *scope;
371*a1157835SDaniel Fojt 		int scope_id = 0;
372*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3733ff40c12SJohn Marino 
3743ff40c12SJohn Marino 		name = os_strdup(ctrl_path);
3753ff40c12SJohn Marino 		if (name == NULL) {
3763ff40c12SJohn Marino 			close(ctrl->s);
3773ff40c12SJohn Marino 			os_free(ctrl);
3783ff40c12SJohn Marino 			return NULL;
3793ff40c12SJohn Marino 		}
380*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
381*a1157835SDaniel Fojt 		port = os_strchr(name, ',');
382*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3833ff40c12SJohn Marino 		port = os_strchr(name, ':');
384*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3853ff40c12SJohn Marino 
3863ff40c12SJohn Marino 		if (port) {
3873ff40c12SJohn Marino 			port_id = atoi(&port[1]);
3883ff40c12SJohn Marino 			port[0] = '\0';
3893ff40c12SJohn Marino 		} else
3903ff40c12SJohn Marino 			port_id = WPA_CTRL_IFACE_PORT;
3913ff40c12SJohn Marino 
392*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
393*a1157835SDaniel Fojt 		scope = os_strchr(name, '%');
394*a1157835SDaniel Fojt 		if (scope) {
395*a1157835SDaniel Fojt 			scope_id = if_nametoindex(&scope[1]);
396*a1157835SDaniel Fojt 			scope[0] = '\0';
397*a1157835SDaniel Fojt 		}
398*a1157835SDaniel Fojt 		h = gethostbyname2(name, AF_INET6);
399*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4003ff40c12SJohn Marino 		h = gethostbyname(name);
401*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4023ff40c12SJohn Marino 		ctrl->remote_ip = os_strdup(name);
4033ff40c12SJohn Marino 		os_free(name);
4043ff40c12SJohn Marino 		if (h == NULL) {
4053ff40c12SJohn Marino 			perror("gethostbyname");
4063ff40c12SJohn Marino 			close(ctrl->s);
4073ff40c12SJohn Marino 			os_free(ctrl->remote_ip);
4083ff40c12SJohn Marino 			os_free(ctrl);
4093ff40c12SJohn Marino 			return NULL;
4103ff40c12SJohn Marino 		}
411*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
412*a1157835SDaniel Fojt 		ctrl->dest.sin6_scope_id = scope_id;
413*a1157835SDaniel Fojt 		ctrl->dest.sin6_port = htons(port_id);
414*a1157835SDaniel Fojt 		os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
415*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4163ff40c12SJohn Marino 		ctrl->dest.sin_port = htons(port_id);
417*a1157835SDaniel Fojt 		os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
418*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4193ff40c12SJohn Marino 	} else
4203ff40c12SJohn Marino 		ctrl->remote_ip = os_strdup("localhost");
4213ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
4223ff40c12SJohn Marino 
4236d49e1aeSJan Lentfer 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
4246d49e1aeSJan Lentfer 		    sizeof(ctrl->dest)) < 0) {
425*a1157835SDaniel Fojt #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
426*a1157835SDaniel Fojt 		char addr[INET6_ADDRSTRLEN];
427*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
428*a1157835SDaniel Fojt 			   inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
429*a1157835SDaniel Fojt 				     sizeof(ctrl->dest)),
430*a1157835SDaniel Fojt 			   ntohs(ctrl->dest.sin6_port),
431*a1157835SDaniel Fojt 			   strerror(errno));
432*a1157835SDaniel Fojt #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
433*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
434*a1157835SDaniel Fojt 			   inet_ntoa(ctrl->dest.sin_addr),
435*a1157835SDaniel Fojt 			   ntohs(ctrl->dest.sin_port),
436*a1157835SDaniel Fojt 			   strerror(errno));
437*a1157835SDaniel Fojt #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4386d49e1aeSJan Lentfer 		close(ctrl->s);
4393ff40c12SJohn Marino 		os_free(ctrl->remote_ip);
4406d49e1aeSJan Lentfer 		os_free(ctrl);
4416d49e1aeSJan Lentfer 		return NULL;
4426d49e1aeSJan Lentfer 	}
4436d49e1aeSJan Lentfer 
4446d49e1aeSJan Lentfer 	len = sizeof(buf) - 1;
4456d49e1aeSJan Lentfer 	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
4466d49e1aeSJan Lentfer 		buf[len] = '\0';
4476d49e1aeSJan Lentfer 		ctrl->cookie = os_strdup(buf);
4486d49e1aeSJan Lentfer 	}
4496d49e1aeSJan Lentfer 
4503ff40c12SJohn Marino 	if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
4513ff40c12SJohn Marino 		buf[len] = '\0';
4523ff40c12SJohn Marino 		ctrl->remote_ifname = os_strdup(buf);
4533ff40c12SJohn Marino 	}
4543ff40c12SJohn Marino 
4556d49e1aeSJan Lentfer 	return ctrl;
4566d49e1aeSJan Lentfer }
4576d49e1aeSJan Lentfer 
4586d49e1aeSJan Lentfer 
wpa_ctrl_get_remote_ifname(struct wpa_ctrl * ctrl)4593ff40c12SJohn Marino char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
4603ff40c12SJohn Marino {
4613ff40c12SJohn Marino #define WPA_CTRL_MAX_PS_NAME 100
4623ff40c12SJohn Marino 	static char ps[WPA_CTRL_MAX_PS_NAME] = {};
4633ff40c12SJohn Marino 	os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
4643ff40c12SJohn Marino 		    ctrl->remote_ip, ctrl->remote_ifname);
4653ff40c12SJohn Marino 	return ps;
4663ff40c12SJohn Marino }
4673ff40c12SJohn Marino 
4683ff40c12SJohn Marino 
wpa_ctrl_close(struct wpa_ctrl * ctrl)4696d49e1aeSJan Lentfer void wpa_ctrl_close(struct wpa_ctrl *ctrl)
4706d49e1aeSJan Lentfer {
4716d49e1aeSJan Lentfer 	close(ctrl->s);
4726d49e1aeSJan Lentfer 	os_free(ctrl->cookie);
4733ff40c12SJohn Marino 	os_free(ctrl->remote_ifname);
4743ff40c12SJohn Marino 	os_free(ctrl->remote_ip);
4756d49e1aeSJan Lentfer 	os_free(ctrl);
4766d49e1aeSJan Lentfer }
4776d49e1aeSJan Lentfer 
4786d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UDP */
4796d49e1aeSJan Lentfer 
4806d49e1aeSJan Lentfer 
4816d49e1aeSJan Lentfer #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))4826d49e1aeSJan Lentfer int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
4836d49e1aeSJan Lentfer 		     char *reply, size_t *reply_len,
4846d49e1aeSJan Lentfer 		     void (*msg_cb)(char *msg, size_t len))
4856d49e1aeSJan Lentfer {
4866d49e1aeSJan Lentfer 	struct timeval tv;
4873ff40c12SJohn Marino 	struct os_reltime started_at;
4886d49e1aeSJan Lentfer 	int res;
4896d49e1aeSJan Lentfer 	fd_set rfds;
4906d49e1aeSJan Lentfer 	const char *_cmd;
4916d49e1aeSJan Lentfer 	char *cmd_buf = NULL;
4926d49e1aeSJan Lentfer 	size_t _cmd_len;
4936d49e1aeSJan Lentfer 
4946d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UDP
4956d49e1aeSJan Lentfer 	if (ctrl->cookie) {
4966d49e1aeSJan Lentfer 		char *pos;
4976d49e1aeSJan Lentfer 		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
4986d49e1aeSJan Lentfer 		cmd_buf = os_malloc(_cmd_len);
4996d49e1aeSJan Lentfer 		if (cmd_buf == NULL)
5006d49e1aeSJan Lentfer 			return -1;
5016d49e1aeSJan Lentfer 		_cmd = cmd_buf;
5026d49e1aeSJan Lentfer 		pos = cmd_buf;
5036d49e1aeSJan Lentfer 		os_strlcpy(pos, ctrl->cookie, _cmd_len);
5046d49e1aeSJan Lentfer 		pos += os_strlen(ctrl->cookie);
5056d49e1aeSJan Lentfer 		*pos++ = ' ';
5066d49e1aeSJan Lentfer 		os_memcpy(pos, cmd, cmd_len);
5076d49e1aeSJan Lentfer 	} else
5086d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UDP */
5096d49e1aeSJan Lentfer 	{
5106d49e1aeSJan Lentfer 		_cmd = cmd;
5116d49e1aeSJan Lentfer 		_cmd_len = cmd_len;
5126d49e1aeSJan Lentfer 	}
5136d49e1aeSJan Lentfer 
5143ff40c12SJohn Marino 	errno = 0;
5153ff40c12SJohn Marino 	started_at.sec = 0;
5163ff40c12SJohn Marino 	started_at.usec = 0;
5173ff40c12SJohn Marino retry_send:
5186d49e1aeSJan Lentfer 	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
5193ff40c12SJohn Marino 		if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
5203ff40c12SJohn Marino 		{
5213ff40c12SJohn Marino 			/*
5223ff40c12SJohn Marino 			 * Must be a non-blocking socket... Try for a bit
5233ff40c12SJohn Marino 			 * longer before giving up.
5243ff40c12SJohn Marino 			 */
5253ff40c12SJohn Marino 			if (started_at.sec == 0)
5263ff40c12SJohn Marino 				os_get_reltime(&started_at);
5273ff40c12SJohn Marino 			else {
5283ff40c12SJohn Marino 				struct os_reltime n;
5293ff40c12SJohn Marino 				os_get_reltime(&n);
5303ff40c12SJohn Marino 				/* Try for a few seconds. */
5313ff40c12SJohn Marino 				if (os_reltime_expired(&n, &started_at, 5))
5323ff40c12SJohn Marino 					goto send_err;
5333ff40c12SJohn Marino 			}
5343ff40c12SJohn Marino 			os_sleep(1, 0);
5353ff40c12SJohn Marino 			goto retry_send;
5363ff40c12SJohn Marino 		}
5373ff40c12SJohn Marino 	send_err:
5386d49e1aeSJan Lentfer 		os_free(cmd_buf);
5396d49e1aeSJan Lentfer 		return -1;
5406d49e1aeSJan Lentfer 	}
5416d49e1aeSJan Lentfer 	os_free(cmd_buf);
5426d49e1aeSJan Lentfer 
5436d49e1aeSJan Lentfer 	for (;;) {
5443ff40c12SJohn Marino 		tv.tv_sec = 10;
5456d49e1aeSJan Lentfer 		tv.tv_usec = 0;
5466d49e1aeSJan Lentfer 		FD_ZERO(&rfds);
5476d49e1aeSJan Lentfer 		FD_SET(ctrl->s, &rfds);
5486d49e1aeSJan Lentfer 		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
549*a1157835SDaniel Fojt 		if (res < 0 && errno == EINTR)
550*a1157835SDaniel Fojt 			continue;
5513ff40c12SJohn Marino 		if (res < 0)
5523ff40c12SJohn Marino 			return res;
5536d49e1aeSJan Lentfer 		if (FD_ISSET(ctrl->s, &rfds)) {
5546d49e1aeSJan Lentfer 			res = recv(ctrl->s, reply, *reply_len, 0);
5556d49e1aeSJan Lentfer 			if (res < 0)
5566d49e1aeSJan Lentfer 				return res;
557*a1157835SDaniel Fojt 			if ((res > 0 && reply[0] == '<') ||
558*a1157835SDaniel Fojt 			    (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
5596d49e1aeSJan Lentfer 				/* This is an unsolicited message from
5606d49e1aeSJan Lentfer 				 * wpa_supplicant, not the reply to the
5616d49e1aeSJan Lentfer 				 * request. Use msg_cb to report this to the
5626d49e1aeSJan Lentfer 				 * caller. */
5636d49e1aeSJan Lentfer 				if (msg_cb) {
5646d49e1aeSJan Lentfer 					/* Make sure the message is nul
5656d49e1aeSJan Lentfer 					 * terminated. */
5666d49e1aeSJan Lentfer 					if ((size_t) res == *reply_len)
5676d49e1aeSJan Lentfer 						res = (*reply_len) - 1;
5686d49e1aeSJan Lentfer 					reply[res] = '\0';
5696d49e1aeSJan Lentfer 					msg_cb(reply, res);
5706d49e1aeSJan Lentfer 				}
5716d49e1aeSJan Lentfer 				continue;
5726d49e1aeSJan Lentfer 			}
5736d49e1aeSJan Lentfer 			*reply_len = res;
5746d49e1aeSJan Lentfer 			break;
5756d49e1aeSJan Lentfer 		} else {
5766d49e1aeSJan Lentfer 			return -2;
5776d49e1aeSJan Lentfer 		}
5786d49e1aeSJan Lentfer 	}
5796d49e1aeSJan Lentfer 	return 0;
5806d49e1aeSJan Lentfer }
5816d49e1aeSJan Lentfer #endif /* CTRL_IFACE_SOCKET */
5826d49e1aeSJan Lentfer 
5836d49e1aeSJan Lentfer 
wpa_ctrl_attach_helper(struct wpa_ctrl * ctrl,int attach)5846d49e1aeSJan Lentfer static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
5856d49e1aeSJan Lentfer {
5866d49e1aeSJan Lentfer 	char buf[10];
5876d49e1aeSJan Lentfer 	int ret;
5886d49e1aeSJan Lentfer 	size_t len = 10;
5896d49e1aeSJan Lentfer 
5906d49e1aeSJan Lentfer 	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
5916d49e1aeSJan Lentfer 			       buf, &len, NULL);
5926d49e1aeSJan Lentfer 	if (ret < 0)
5936d49e1aeSJan Lentfer 		return ret;
5946d49e1aeSJan Lentfer 	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
5956d49e1aeSJan Lentfer 		return 0;
5966d49e1aeSJan Lentfer 	return -1;
5976d49e1aeSJan Lentfer }
5986d49e1aeSJan Lentfer 
5996d49e1aeSJan Lentfer 
wpa_ctrl_attach(struct wpa_ctrl * ctrl)6006d49e1aeSJan Lentfer int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
6016d49e1aeSJan Lentfer {
6026d49e1aeSJan Lentfer 	return wpa_ctrl_attach_helper(ctrl, 1);
6036d49e1aeSJan Lentfer }
6046d49e1aeSJan Lentfer 
6056d49e1aeSJan Lentfer 
wpa_ctrl_detach(struct wpa_ctrl * ctrl)6066d49e1aeSJan Lentfer int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
6076d49e1aeSJan Lentfer {
6086d49e1aeSJan Lentfer 	return wpa_ctrl_attach_helper(ctrl, 0);
6096d49e1aeSJan Lentfer }
6106d49e1aeSJan Lentfer 
6116d49e1aeSJan Lentfer 
6126d49e1aeSJan Lentfer #ifdef CTRL_IFACE_SOCKET
6136d49e1aeSJan Lentfer 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)6146d49e1aeSJan Lentfer int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
6156d49e1aeSJan Lentfer {
6166d49e1aeSJan Lentfer 	int res;
6176d49e1aeSJan Lentfer 
6186d49e1aeSJan Lentfer 	res = recv(ctrl->s, reply, *reply_len, 0);
6196d49e1aeSJan Lentfer 	if (res < 0)
6206d49e1aeSJan Lentfer 		return res;
6216d49e1aeSJan Lentfer 	*reply_len = res;
6226d49e1aeSJan Lentfer 	return 0;
6236d49e1aeSJan Lentfer }
6246d49e1aeSJan Lentfer 
6256d49e1aeSJan Lentfer 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)6266d49e1aeSJan Lentfer int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
6276d49e1aeSJan Lentfer {
6286d49e1aeSJan Lentfer 	struct timeval tv;
6296d49e1aeSJan Lentfer 	fd_set rfds;
6306d49e1aeSJan Lentfer 	tv.tv_sec = 0;
6316d49e1aeSJan Lentfer 	tv.tv_usec = 0;
6326d49e1aeSJan Lentfer 	FD_ZERO(&rfds);
6336d49e1aeSJan Lentfer 	FD_SET(ctrl->s, &rfds);
6346d49e1aeSJan Lentfer 	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
6356d49e1aeSJan Lentfer 	return FD_ISSET(ctrl->s, &rfds);
6366d49e1aeSJan Lentfer }
6376d49e1aeSJan Lentfer 
6386d49e1aeSJan Lentfer 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)6396d49e1aeSJan Lentfer int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
6406d49e1aeSJan Lentfer {
6416d49e1aeSJan Lentfer 	return ctrl->s;
6426d49e1aeSJan Lentfer }
6436d49e1aeSJan Lentfer 
6446d49e1aeSJan Lentfer #endif /* CTRL_IFACE_SOCKET */
6456d49e1aeSJan Lentfer 
6466d49e1aeSJan Lentfer 
6476d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
6486d49e1aeSJan Lentfer 
6496d49e1aeSJan Lentfer #ifndef WPA_SUPPLICANT_NAMED_PIPE
6506d49e1aeSJan Lentfer #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
6516d49e1aeSJan Lentfer #endif
6526d49e1aeSJan Lentfer #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
6536d49e1aeSJan Lentfer 
wpa_ctrl_open(const char * ctrl_path)6546d49e1aeSJan Lentfer struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
6556d49e1aeSJan Lentfer {
6566d49e1aeSJan Lentfer 	struct wpa_ctrl *ctrl;
6576d49e1aeSJan Lentfer 	DWORD mode;
6586d49e1aeSJan Lentfer 	TCHAR name[256];
6596d49e1aeSJan Lentfer 	int i, ret;
6606d49e1aeSJan Lentfer 
6616d49e1aeSJan Lentfer 	ctrl = os_malloc(sizeof(*ctrl));
6626d49e1aeSJan Lentfer 	if (ctrl == NULL)
6636d49e1aeSJan Lentfer 		return NULL;
6646d49e1aeSJan Lentfer 	os_memset(ctrl, 0, sizeof(*ctrl));
6656d49e1aeSJan Lentfer 
6666d49e1aeSJan Lentfer #ifdef UNICODE
6676d49e1aeSJan Lentfer 	if (ctrl_path == NULL)
6686d49e1aeSJan Lentfer 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
6696d49e1aeSJan Lentfer 	else
6706d49e1aeSJan Lentfer 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
6716d49e1aeSJan Lentfer 				 ctrl_path);
6726d49e1aeSJan Lentfer #else /* UNICODE */
6736d49e1aeSJan Lentfer 	if (ctrl_path == NULL)
6746d49e1aeSJan Lentfer 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
6756d49e1aeSJan Lentfer 	else
6766d49e1aeSJan Lentfer 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
6776d49e1aeSJan Lentfer 				  ctrl_path);
6786d49e1aeSJan Lentfer #endif /* UNICODE */
679*a1157835SDaniel Fojt 	if (os_snprintf_error(256, ret)) {
6806d49e1aeSJan Lentfer 		os_free(ctrl);
6816d49e1aeSJan Lentfer 		return NULL;
6826d49e1aeSJan Lentfer 	}
6836d49e1aeSJan Lentfer 
6846d49e1aeSJan Lentfer 	for (i = 0; i < 10; i++) {
6856d49e1aeSJan Lentfer 		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
6866d49e1aeSJan Lentfer 					NULL, OPEN_EXISTING, 0, NULL);
6876d49e1aeSJan Lentfer 		/*
6886d49e1aeSJan Lentfer 		 * Current named pipe server side in wpa_supplicant is
6896d49e1aeSJan Lentfer 		 * re-opening the pipe for new clients only after the previous
6906d49e1aeSJan Lentfer 		 * one is taken into use. This leaves a small window for race
6916d49e1aeSJan Lentfer 		 * conditions when two connections are being opened at almost
6926d49e1aeSJan Lentfer 		 * the same time. Retry if that was the case.
6936d49e1aeSJan Lentfer 		 */
6946d49e1aeSJan Lentfer 		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
6956d49e1aeSJan Lentfer 		    GetLastError() != ERROR_PIPE_BUSY)
6966d49e1aeSJan Lentfer 			break;
6976d49e1aeSJan Lentfer 		WaitNamedPipe(name, 1000);
6986d49e1aeSJan Lentfer 	}
6996d49e1aeSJan Lentfer 	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
7006d49e1aeSJan Lentfer 		os_free(ctrl);
7016d49e1aeSJan Lentfer 		return NULL;
7026d49e1aeSJan Lentfer 	}
7036d49e1aeSJan Lentfer 
7046d49e1aeSJan Lentfer 	mode = PIPE_READMODE_MESSAGE;
7056d49e1aeSJan Lentfer 	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
7066d49e1aeSJan Lentfer 		CloseHandle(ctrl->pipe);
7076d49e1aeSJan Lentfer 		os_free(ctrl);
7086d49e1aeSJan Lentfer 		return NULL;
7096d49e1aeSJan Lentfer 	}
7106d49e1aeSJan Lentfer 
7116d49e1aeSJan Lentfer 	return ctrl;
7126d49e1aeSJan Lentfer }
7136d49e1aeSJan Lentfer 
7146d49e1aeSJan Lentfer 
wpa_ctrl_close(struct wpa_ctrl * ctrl)7156d49e1aeSJan Lentfer void wpa_ctrl_close(struct wpa_ctrl *ctrl)
7166d49e1aeSJan Lentfer {
7176d49e1aeSJan Lentfer 	CloseHandle(ctrl->pipe);
7186d49e1aeSJan Lentfer 	os_free(ctrl);
7196d49e1aeSJan Lentfer }
7206d49e1aeSJan Lentfer 
7216d49e1aeSJan Lentfer 
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))7226d49e1aeSJan Lentfer int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
7236d49e1aeSJan Lentfer 		     char *reply, size_t *reply_len,
7246d49e1aeSJan Lentfer 		     void (*msg_cb)(char *msg, size_t len))
7256d49e1aeSJan Lentfer {
7266d49e1aeSJan Lentfer 	DWORD written;
7276d49e1aeSJan Lentfer 	DWORD readlen = *reply_len;
7286d49e1aeSJan Lentfer 
7296d49e1aeSJan Lentfer 	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
7306d49e1aeSJan Lentfer 		return -1;
7316d49e1aeSJan Lentfer 
7326d49e1aeSJan Lentfer 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
7336d49e1aeSJan Lentfer 		return -1;
7346d49e1aeSJan Lentfer 	*reply_len = readlen;
7356d49e1aeSJan Lentfer 
7366d49e1aeSJan Lentfer 	return 0;
7376d49e1aeSJan Lentfer }
7386d49e1aeSJan Lentfer 
7396d49e1aeSJan Lentfer 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)7406d49e1aeSJan Lentfer int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
7416d49e1aeSJan Lentfer {
7426d49e1aeSJan Lentfer 	DWORD len = *reply_len;
7436d49e1aeSJan Lentfer 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
7446d49e1aeSJan Lentfer 		return -1;
7456d49e1aeSJan Lentfer 	*reply_len = len;
7466d49e1aeSJan Lentfer 	return 0;
7476d49e1aeSJan Lentfer }
7486d49e1aeSJan Lentfer 
7496d49e1aeSJan Lentfer 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)7506d49e1aeSJan Lentfer int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
7516d49e1aeSJan Lentfer {
7526d49e1aeSJan Lentfer 	DWORD left;
7536d49e1aeSJan Lentfer 
7546d49e1aeSJan Lentfer 	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
7556d49e1aeSJan Lentfer 		return -1;
7566d49e1aeSJan Lentfer 	return left ? 1 : 0;
7576d49e1aeSJan Lentfer }
7586d49e1aeSJan Lentfer 
7596d49e1aeSJan Lentfer 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)7606d49e1aeSJan Lentfer int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
7616d49e1aeSJan Lentfer {
7626d49e1aeSJan Lentfer 	return -1;
7636d49e1aeSJan Lentfer }
7646d49e1aeSJan Lentfer 
7656d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
7666d49e1aeSJan Lentfer 
7676d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE */
768