xref: /wlan-dirver/utils/sigma-dut/wpa_ctrl.c (revision a1deeaa4e8d7cf571d402d4e8800768689643ca3)
1cd4e3c3eSJouni Malinen /*
2cd4e3c3eSJouni Malinen  * wpa_supplicant/hostapd control interface library
3cd4e3c3eSJouni Malinen  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4cd4e3c3eSJouni Malinen  *
5cd4e3c3eSJouni Malinen  * This software may be distributed under the terms of the BSD license.
6cd4e3c3eSJouni Malinen  * See README for more details.
7cd4e3c3eSJouni Malinen  */
8cd4e3c3eSJouni Malinen 
9cd4e3c3eSJouni Malinen #include <stdlib.h>
10cd4e3c3eSJouni Malinen #include <stdio.h>
11cd4e3c3eSJouni Malinen #include <string.h>
12cd4e3c3eSJouni Malinen #include <unistd.h>
13cd4e3c3eSJouni Malinen #include <errno.h>
14cd4e3c3eSJouni Malinen #include <sys/types.h>
15cd4e3c3eSJouni Malinen #include <sys/socket.h>
16cd4e3c3eSJouni Malinen #ifdef __QNXNTO__
17cd4e3c3eSJouni Malinen #include <sys/select.h>
18cd4e3c3eSJouni Malinen #endif /* __QNXNTO__ */
19cd4e3c3eSJouni Malinen #include <sys/stat.h>
20cd4e3c3eSJouni Malinen 
21cd4e3c3eSJouni Malinen #define CONFIG_CTRL_IFACE
22cd4e3c3eSJouni Malinen #define CONFIG_CTRL_IFACE_UNIX
23cd4e3c3eSJouni Malinen #define os_malloc malloc
24cd4e3c3eSJouni Malinen #define os_free free
25cd4e3c3eSJouni Malinen #define os_memset memset
26cd4e3c3eSJouni Malinen #define os_memcmp memcmp
27cd4e3c3eSJouni Malinen #define os_snprintf snprintf
28cd4e3c3eSJouni Malinen #define os_strlen strlen
29cd4e3c3eSJouni Malinen #define os_strncmp strncmp
30769731a2SPeng Xu #define os_strlcpy strlcpy
31769731a2SPeng Xu #include "sigma_dut.h"
32cd4e3c3eSJouni Malinen 
33cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE
34cd4e3c3eSJouni Malinen 
35cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_UNIX
36cd4e3c3eSJouni Malinen #include <sys/un.h>
37cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_UNIX */
38cd4e3c3eSJouni Malinen 
39cd4e3c3eSJouni Malinen #ifdef ANDROID
40cd4e3c3eSJouni Malinen #include <dirent.h>
41cd4e3c3eSJouni Malinen #include <cutils/sockets.h>
42d7e00081SVeerendranath Jakkam #include <grp.h>
43d7e00081SVeerendranath Jakkam #include <pwd.h>
44cd4e3c3eSJouni Malinen #endif /* ANDROID */
45cd4e3c3eSJouni Malinen 
46cd4e3c3eSJouni Malinen #include "wpa_ctrl.h"
47cd4e3c3eSJouni Malinen 
48cd4e3c3eSJouni Malinen 
49cd4e3c3eSJouni Malinen #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
50cd4e3c3eSJouni Malinen #define CTRL_IFACE_SOCKET
51cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
52cd4e3c3eSJouni Malinen 
53cd4e3c3eSJouni Malinen 
54cd4e3c3eSJouni Malinen /**
55cd4e3c3eSJouni Malinen  * struct wpa_ctrl - Internal structure for control interface library
56cd4e3c3eSJouni Malinen  *
57cd4e3c3eSJouni Malinen  * This structure is used by the wpa_supplicant/hostapd control interface
58cd4e3c3eSJouni Malinen  * library to store internal data. Programs using the library should not touch
59cd4e3c3eSJouni Malinen  * this data directly. They can only use the pointer to the data structure as
60cd4e3c3eSJouni Malinen  * an identifier for the control interface connection and use this as one of
61cd4e3c3eSJouni Malinen  * the arguments for most of the control interface library functions.
62cd4e3c3eSJouni Malinen  */
63cd4e3c3eSJouni Malinen struct wpa_ctrl {
64cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_UDP
65cd4e3c3eSJouni Malinen 	int s;
66cd4e3c3eSJouni Malinen 	struct sockaddr_in local;
67cd4e3c3eSJouni Malinen 	struct sockaddr_in dest;
68cd4e3c3eSJouni Malinen 	char *cookie;
69cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_UDP */
70cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_UNIX
71cd4e3c3eSJouni Malinen 	int s;
72cd4e3c3eSJouni Malinen 	struct sockaddr_un local;
73cd4e3c3eSJouni Malinen 	struct sockaddr_un dest;
74cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_UNIX */
75cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
76cd4e3c3eSJouni Malinen 	HANDLE pipe;
77cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
78cd4e3c3eSJouni Malinen };
79cd4e3c3eSJouni Malinen 
80cd4e3c3eSJouni Malinen 
81cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_UNIX
82cd4e3c3eSJouni Malinen 
83cd4e3c3eSJouni Malinen #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
84cd4e3c3eSJouni Malinen #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
85cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
86cd4e3c3eSJouni Malinen #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
87cd4e3c3eSJouni Malinen #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
88cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
89cd4e3c3eSJouni Malinen 
90cd4e3c3eSJouni Malinen 
wpa_ctrl_open(const char * ctrl_path)91cd4e3c3eSJouni Malinen struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
92cd4e3c3eSJouni Malinen {
93831b5497SRajiv Ranjan 	return wpa_ctrl_open2(ctrl_path, NULL);
94831b5497SRajiv Ranjan }
95831b5497SRajiv Ranjan 
96831b5497SRajiv Ranjan 
wpa_ctrl_open2(const char * ctrl_path,const char * cli_path)97831b5497SRajiv Ranjan struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
98831b5497SRajiv Ranjan 				 const char *cli_path)
99831b5497SRajiv Ranjan {
100cd4e3c3eSJouni Malinen 	struct wpa_ctrl *ctrl;
101cd4e3c3eSJouni Malinen 	static int counter = 0;
102cd4e3c3eSJouni Malinen 	int ret;
103cd4e3c3eSJouni Malinen 	size_t res;
104cd4e3c3eSJouni Malinen 	int tries = 0;
105*a1deeaa4SSrinivas Dasari #ifdef ANDROID
106*a1deeaa4SSrinivas Dasari 	struct passwd *pw;
107*a1deeaa4SSrinivas Dasari 	struct group *gr;
108*a1deeaa4SSrinivas Dasari #endif /* ANDROID */
109cd4e3c3eSJouni Malinen 
1105df800e1SPradeep Reddy POTTETI 	if (ctrl_path == NULL)
1115df800e1SPradeep Reddy POTTETI 		return NULL;
1125df800e1SPradeep Reddy POTTETI 
113cd4e3c3eSJouni Malinen 	ctrl = os_malloc(sizeof(*ctrl));
114cd4e3c3eSJouni Malinen 	if (ctrl == NULL)
115cd4e3c3eSJouni Malinen 		return NULL;
116cd4e3c3eSJouni Malinen 	os_memset(ctrl, 0, sizeof(*ctrl));
117cd4e3c3eSJouni Malinen 
118cd4e3c3eSJouni Malinen 	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
119cd4e3c3eSJouni Malinen 	if (ctrl->s < 0) {
120cd4e3c3eSJouni Malinen 		os_free(ctrl);
121cd4e3c3eSJouni Malinen 		return NULL;
122cd4e3c3eSJouni Malinen 	}
123cd4e3c3eSJouni Malinen 
124cd4e3c3eSJouni Malinen 	ctrl->local.sun_family = AF_UNIX;
125cd4e3c3eSJouni Malinen 	counter++;
126cd4e3c3eSJouni Malinen try_again:
127831b5497SRajiv Ranjan 	if (cli_path && cli_path[0] == '/') {
128831b5497SRajiv Ranjan 		ret = os_snprintf(ctrl->local.sun_path,
129831b5497SRajiv Ranjan 				  sizeof(ctrl->local.sun_path),
130831b5497SRajiv Ranjan 				  "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
131831b5497SRajiv Ranjan 				  cli_path, (int) getpid(), counter);
132831b5497SRajiv Ranjan 	} else {
133831b5497SRajiv Ranjan 		ret = os_snprintf(ctrl->local.sun_path,
134831b5497SRajiv Ranjan 				  sizeof(ctrl->local.sun_path),
135cd4e3c3eSJouni Malinen 				  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
136cd4e3c3eSJouni Malinen 				  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
137cd4e3c3eSJouni Malinen 				  (int) getpid(), counter);
138831b5497SRajiv Ranjan 	}
139831b5497SRajiv Ranjan 
140cd4e3c3eSJouni Malinen 	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
141cd4e3c3eSJouni Malinen 		close(ctrl->s);
142cd4e3c3eSJouni Malinen 		os_free(ctrl);
143cd4e3c3eSJouni Malinen 		return NULL;
144cd4e3c3eSJouni Malinen 	}
145cd4e3c3eSJouni Malinen 	tries++;
146cd4e3c3eSJouni Malinen 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
147cd4e3c3eSJouni Malinen 		    sizeof(ctrl->local)) < 0) {
148cd4e3c3eSJouni Malinen 		if (errno == EADDRINUSE && tries < 2) {
149cd4e3c3eSJouni Malinen 			/*
150cd4e3c3eSJouni Malinen 			 * getpid() returns unique identifier for this instance
151cd4e3c3eSJouni Malinen 			 * of wpa_ctrl, so the existing socket file must have
152cd4e3c3eSJouni Malinen 			 * been left by unclean termination of an earlier run.
153cd4e3c3eSJouni Malinen 			 * Remove the file and try again.
154cd4e3c3eSJouni Malinen 			 */
155cd4e3c3eSJouni Malinen 			unlink(ctrl->local.sun_path);
156cd4e3c3eSJouni Malinen 			goto try_again;
157cd4e3c3eSJouni Malinen 		}
158cd4e3c3eSJouni Malinen 		close(ctrl->s);
159cd4e3c3eSJouni Malinen 		os_free(ctrl);
160cd4e3c3eSJouni Malinen 		return NULL;
161cd4e3c3eSJouni Malinen 	}
162cd4e3c3eSJouni Malinen 
163cd4e3c3eSJouni Malinen #ifdef ANDROID
164cd4e3c3eSJouni Malinen 	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
165*a1deeaa4SSrinivas Dasari 	pw = getpwnam("system");
166*a1deeaa4SSrinivas Dasari 	gr = getgrnam("wifi");
167*a1deeaa4SSrinivas Dasari 	if (pw && gr)
168*a1deeaa4SSrinivas Dasari 		chown(ctrl->local.sun_path, pw->pw_uid, gr->gr_gid);
169*a1deeaa4SSrinivas Dasari 
170cd4e3c3eSJouni Malinen 	/*
171cd4e3c3eSJouni Malinen 	 * If the ctrl_path isn't an absolute pathname, assume that
172cd4e3c3eSJouni Malinen 	 * it's the name of a socket in the Android reserved namespace.
173cd4e3c3eSJouni Malinen 	 * Otherwise, it's a normal UNIX domain socket appearing in the
174cd4e3c3eSJouni Malinen 	 * filesystem.
175cd4e3c3eSJouni Malinen 	 */
1765df800e1SPradeep Reddy POTTETI 	if (*ctrl_path != '/') {
177cd4e3c3eSJouni Malinen 		char buf[21];
178cd4e3c3eSJouni Malinen 		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
179cd4e3c3eSJouni Malinen 		if (socket_local_client_connect(
180cd4e3c3eSJouni Malinen 			    ctrl->s, buf,
181cd4e3c3eSJouni Malinen 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
182cd4e3c3eSJouni Malinen 			    SOCK_DGRAM) < 0) {
183cd4e3c3eSJouni Malinen 			close(ctrl->s);
184cd4e3c3eSJouni Malinen 			unlink(ctrl->local.sun_path);
185cd4e3c3eSJouni Malinen 			os_free(ctrl);
186cd4e3c3eSJouni Malinen 			return NULL;
187cd4e3c3eSJouni Malinen 		}
188cd4e3c3eSJouni Malinen 		return ctrl;
189cd4e3c3eSJouni Malinen 	}
190cd4e3c3eSJouni Malinen #endif /* ANDROID */
191cd4e3c3eSJouni Malinen 
192cd4e3c3eSJouni Malinen 	ctrl->dest.sun_family = AF_UNIX;
193cd4e3c3eSJouni Malinen 	res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
194cd4e3c3eSJouni Malinen 			 sizeof(ctrl->dest.sun_path));
195cd4e3c3eSJouni Malinen 	if (res >= sizeof(ctrl->dest.sun_path)) {
196cd4e3c3eSJouni Malinen 		close(ctrl->s);
197cd4e3c3eSJouni Malinen 		os_free(ctrl);
198cd4e3c3eSJouni Malinen 		return NULL;
199cd4e3c3eSJouni Malinen 	}
200cd4e3c3eSJouni Malinen 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
201cd4e3c3eSJouni Malinen 		    sizeof(ctrl->dest)) < 0) {
202cd4e3c3eSJouni Malinen 		close(ctrl->s);
203cd4e3c3eSJouni Malinen 		unlink(ctrl->local.sun_path);
204cd4e3c3eSJouni Malinen 		os_free(ctrl);
205cd4e3c3eSJouni Malinen 		return NULL;
206cd4e3c3eSJouni Malinen 	}
207cd4e3c3eSJouni Malinen 
208cd4e3c3eSJouni Malinen 	return ctrl;
209cd4e3c3eSJouni Malinen }
210cd4e3c3eSJouni Malinen 
211cd4e3c3eSJouni Malinen 
wpa_ctrl_close(struct wpa_ctrl * ctrl)212cd4e3c3eSJouni Malinen void wpa_ctrl_close(struct wpa_ctrl *ctrl)
213cd4e3c3eSJouni Malinen {
214cd4e3c3eSJouni Malinen 	if (ctrl == NULL)
215cd4e3c3eSJouni Malinen 		return;
216cd4e3c3eSJouni Malinen 	unlink(ctrl->local.sun_path);
217cd4e3c3eSJouni Malinen 	if (ctrl->s >= 0)
218cd4e3c3eSJouni Malinen 		close(ctrl->s);
219cd4e3c3eSJouni Malinen 	os_free(ctrl);
220cd4e3c3eSJouni Malinen }
221cd4e3c3eSJouni Malinen 
222cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_UNIX */
223cd4e3c3eSJouni Malinen 
224cd4e3c3eSJouni Malinen 
225cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_UDP
226cd4e3c3eSJouni Malinen 
wpa_ctrl_open(const char * ctrl_path)227cd4e3c3eSJouni Malinen struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
228cd4e3c3eSJouni Malinen {
229cd4e3c3eSJouni Malinen 	struct wpa_ctrl *ctrl;
230cd4e3c3eSJouni Malinen 	char buf[128];
231cd4e3c3eSJouni Malinen 	size_t len;
232cd4e3c3eSJouni Malinen 
233cd4e3c3eSJouni Malinen 	ctrl = os_malloc(sizeof(*ctrl));
234cd4e3c3eSJouni Malinen 	if (ctrl == NULL)
235cd4e3c3eSJouni Malinen 		return NULL;
236cd4e3c3eSJouni Malinen 	os_memset(ctrl, 0, sizeof(*ctrl));
237cd4e3c3eSJouni Malinen 
238cd4e3c3eSJouni Malinen 	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
239cd4e3c3eSJouni Malinen 	if (ctrl->s < 0) {
240cd4e3c3eSJouni Malinen 		perror("socket");
241cd4e3c3eSJouni Malinen 		os_free(ctrl);
242cd4e3c3eSJouni Malinen 		return NULL;
243cd4e3c3eSJouni Malinen 	}
244cd4e3c3eSJouni Malinen 
245cd4e3c3eSJouni Malinen 	ctrl->local.sin_family = AF_INET;
246cd4e3c3eSJouni Malinen 	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
247cd4e3c3eSJouni Malinen 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
248cd4e3c3eSJouni Malinen 		 sizeof(ctrl->local)) < 0) {
249cd4e3c3eSJouni Malinen 		close(ctrl->s);
250cd4e3c3eSJouni Malinen 		os_free(ctrl);
251cd4e3c3eSJouni Malinen 		return NULL;
252cd4e3c3eSJouni Malinen 	}
253cd4e3c3eSJouni Malinen 
254cd4e3c3eSJouni Malinen 	ctrl->dest.sin_family = AF_INET;
255cd4e3c3eSJouni Malinen 	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
256cd4e3c3eSJouni Malinen 	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
257cd4e3c3eSJouni Malinen 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
258cd4e3c3eSJouni Malinen 		    sizeof(ctrl->dest)) < 0) {
259cd4e3c3eSJouni Malinen 		perror("connect");
260cd4e3c3eSJouni Malinen 		close(ctrl->s);
261cd4e3c3eSJouni Malinen 		os_free(ctrl);
262cd4e3c3eSJouni Malinen 		return NULL;
263cd4e3c3eSJouni Malinen 	}
264cd4e3c3eSJouni Malinen 
265cd4e3c3eSJouni Malinen 	len = sizeof(buf) - 1;
266cd4e3c3eSJouni Malinen 	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
267cd4e3c3eSJouni Malinen 		buf[len] = '\0';
268cd4e3c3eSJouni Malinen 		ctrl->cookie = os_strdup(buf);
269cd4e3c3eSJouni Malinen 	}
270cd4e3c3eSJouni Malinen 
271cd4e3c3eSJouni Malinen 	return ctrl;
272cd4e3c3eSJouni Malinen }
273cd4e3c3eSJouni Malinen 
274cd4e3c3eSJouni Malinen 
wpa_ctrl_close(struct wpa_ctrl * ctrl)275cd4e3c3eSJouni Malinen void wpa_ctrl_close(struct wpa_ctrl *ctrl)
276cd4e3c3eSJouni Malinen {
277cd4e3c3eSJouni Malinen 	close(ctrl->s);
278cd4e3c3eSJouni Malinen 	os_free(ctrl->cookie);
279cd4e3c3eSJouni Malinen 	os_free(ctrl);
280cd4e3c3eSJouni Malinen }
281cd4e3c3eSJouni Malinen 
282cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_UDP */
283cd4e3c3eSJouni Malinen 
284cd4e3c3eSJouni Malinen 
285cd4e3c3eSJouni Malinen #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))286cd4e3c3eSJouni Malinen int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
287cd4e3c3eSJouni Malinen 		     char *reply, size_t *reply_len,
288cd4e3c3eSJouni Malinen 		     void (*msg_cb)(char *msg, size_t len))
289cd4e3c3eSJouni Malinen {
290cd4e3c3eSJouni Malinen 	struct timeval tv;
291cd4e3c3eSJouni Malinen 	int res;
292cd4e3c3eSJouni Malinen 	fd_set rfds;
293cd4e3c3eSJouni Malinen 	const char *_cmd;
294cd4e3c3eSJouni Malinen 	char *cmd_buf = NULL;
295cd4e3c3eSJouni Malinen 	size_t _cmd_len;
296cd4e3c3eSJouni Malinen 
297cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_UDP
298cd4e3c3eSJouni Malinen 	if (ctrl->cookie) {
299cd4e3c3eSJouni Malinen 		char *pos;
300cd4e3c3eSJouni Malinen 		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
301cd4e3c3eSJouni Malinen 		cmd_buf = os_malloc(_cmd_len);
302cd4e3c3eSJouni Malinen 		if (cmd_buf == NULL)
303cd4e3c3eSJouni Malinen 			return -1;
304cd4e3c3eSJouni Malinen 		_cmd = cmd_buf;
305cd4e3c3eSJouni Malinen 		pos = cmd_buf;
306cd4e3c3eSJouni Malinen 		os_strlcpy(pos, ctrl->cookie, _cmd_len);
307cd4e3c3eSJouni Malinen 		pos += os_strlen(ctrl->cookie);
308cd4e3c3eSJouni Malinen 		*pos++ = ' ';
309cd4e3c3eSJouni Malinen 		os_memcpy(pos, cmd, cmd_len);
310cd4e3c3eSJouni Malinen 	} else
311cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_UDP */
312cd4e3c3eSJouni Malinen 	{
313cd4e3c3eSJouni Malinen 		_cmd = cmd;
314cd4e3c3eSJouni Malinen 		_cmd_len = cmd_len;
315cd4e3c3eSJouni Malinen 	}
316cd4e3c3eSJouni Malinen 
317cd4e3c3eSJouni Malinen 	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
318cd4e3c3eSJouni Malinen 		os_free(cmd_buf);
319cd4e3c3eSJouni Malinen 		return -1;
320cd4e3c3eSJouni Malinen 	}
321cd4e3c3eSJouni Malinen 	os_free(cmd_buf);
322cd4e3c3eSJouni Malinen 
323cd4e3c3eSJouni Malinen 	for (;;) {
324cd4e3c3eSJouni Malinen 		tv.tv_sec = 10;
325cd4e3c3eSJouni Malinen 		tv.tv_usec = 0;
326cd4e3c3eSJouni Malinen 		FD_ZERO(&rfds);
327cd4e3c3eSJouni Malinen 		FD_SET(ctrl->s, &rfds);
328cd4e3c3eSJouni Malinen 		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
329cd4e3c3eSJouni Malinen 		if (res < 0)
330cd4e3c3eSJouni Malinen 			return res;
331cd4e3c3eSJouni Malinen 		if (FD_ISSET(ctrl->s, &rfds)) {
332cd4e3c3eSJouni Malinen 			res = recv(ctrl->s, reply, *reply_len, 0);
333cd4e3c3eSJouni Malinen 			if (res < 0)
334cd4e3c3eSJouni Malinen 				return res;
335cd4e3c3eSJouni Malinen 			if (res > 0 && reply[0] == '<') {
336cd4e3c3eSJouni Malinen 				/* This is an unsolicited message from
337cd4e3c3eSJouni Malinen 				 * wpa_supplicant, not the reply to the
338cd4e3c3eSJouni Malinen 				 * request. Use msg_cb to report this to the
339cd4e3c3eSJouni Malinen 				 * caller. */
340cd4e3c3eSJouni Malinen 				if (msg_cb) {
341cd4e3c3eSJouni Malinen 					/* Make sure the message is nul
342cd4e3c3eSJouni Malinen 					 * terminated. */
343cd4e3c3eSJouni Malinen 					if ((size_t) res == *reply_len)
344cd4e3c3eSJouni Malinen 						res = (*reply_len) - 1;
345cd4e3c3eSJouni Malinen 					reply[res] = '\0';
346cd4e3c3eSJouni Malinen 					msg_cb(reply, res);
347cd4e3c3eSJouni Malinen 				}
348cd4e3c3eSJouni Malinen 				continue;
349cd4e3c3eSJouni Malinen 			}
350cd4e3c3eSJouni Malinen 			*reply_len = res;
351cd4e3c3eSJouni Malinen 			break;
352cd4e3c3eSJouni Malinen 		} else {
353cd4e3c3eSJouni Malinen 			return -2;
354cd4e3c3eSJouni Malinen 		}
355cd4e3c3eSJouni Malinen 	}
356cd4e3c3eSJouni Malinen 	return 0;
357cd4e3c3eSJouni Malinen }
358cd4e3c3eSJouni Malinen #endif /* CTRL_IFACE_SOCKET */
359cd4e3c3eSJouni Malinen 
360cd4e3c3eSJouni Malinen 
wpa_ctrl_attach_helper(struct wpa_ctrl * ctrl,int attach)361cd4e3c3eSJouni Malinen static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
362cd4e3c3eSJouni Malinen {
363cd4e3c3eSJouni Malinen 	char buf[10];
364cd4e3c3eSJouni Malinen 	int ret;
365cd4e3c3eSJouni Malinen 	size_t len = 10;
366cd4e3c3eSJouni Malinen 
367cd4e3c3eSJouni Malinen 	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
368cd4e3c3eSJouni Malinen 			       buf, &len, NULL);
369cd4e3c3eSJouni Malinen 	if (ret < 0)
370cd4e3c3eSJouni Malinen 		return ret;
371cd4e3c3eSJouni Malinen 	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
372cd4e3c3eSJouni Malinen 		return 0;
373cd4e3c3eSJouni Malinen 	return -1;
374cd4e3c3eSJouni Malinen }
375cd4e3c3eSJouni Malinen 
376cd4e3c3eSJouni Malinen 
wpa_ctrl_attach(struct wpa_ctrl * ctrl)377cd4e3c3eSJouni Malinen int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
378cd4e3c3eSJouni Malinen {
379cd4e3c3eSJouni Malinen 	return wpa_ctrl_attach_helper(ctrl, 1);
380cd4e3c3eSJouni Malinen }
381cd4e3c3eSJouni Malinen 
382cd4e3c3eSJouni Malinen 
wpa_ctrl_detach(struct wpa_ctrl * ctrl)383cd4e3c3eSJouni Malinen int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
384cd4e3c3eSJouni Malinen {
385cd4e3c3eSJouni Malinen 	return wpa_ctrl_attach_helper(ctrl, 0);
386cd4e3c3eSJouni Malinen }
387cd4e3c3eSJouni Malinen 
388cd4e3c3eSJouni Malinen 
389cd4e3c3eSJouni Malinen #ifdef CTRL_IFACE_SOCKET
390cd4e3c3eSJouni Malinen 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)391cd4e3c3eSJouni Malinen int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
392cd4e3c3eSJouni Malinen {
393cd4e3c3eSJouni Malinen 	int res;
394cd4e3c3eSJouni Malinen 
395cd4e3c3eSJouni Malinen 	res = recv(ctrl->s, reply, *reply_len, 0);
396cd4e3c3eSJouni Malinen 	if (res < 0)
397cd4e3c3eSJouni Malinen 		return res;
398cd4e3c3eSJouni Malinen 	*reply_len = res;
399cd4e3c3eSJouni Malinen 	return 0;
400cd4e3c3eSJouni Malinen }
401cd4e3c3eSJouni Malinen 
402cd4e3c3eSJouni Malinen 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)403cd4e3c3eSJouni Malinen int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
404cd4e3c3eSJouni Malinen {
405cd4e3c3eSJouni Malinen 	struct timeval tv;
406cd4e3c3eSJouni Malinen 	fd_set rfds;
407cd4e3c3eSJouni Malinen 	tv.tv_sec = 0;
408cd4e3c3eSJouni Malinen 	tv.tv_usec = 0;
409cd4e3c3eSJouni Malinen 	FD_ZERO(&rfds);
410cd4e3c3eSJouni Malinen 	FD_SET(ctrl->s, &rfds);
411cd4e3c3eSJouni Malinen 	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
412cd4e3c3eSJouni Malinen 	return FD_ISSET(ctrl->s, &rfds);
413cd4e3c3eSJouni Malinen }
414cd4e3c3eSJouni Malinen 
415cd4e3c3eSJouni Malinen 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)416cd4e3c3eSJouni Malinen int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
417cd4e3c3eSJouni Malinen {
418cd4e3c3eSJouni Malinen 	return ctrl->s;
419cd4e3c3eSJouni Malinen }
420cd4e3c3eSJouni Malinen 
421cd4e3c3eSJouni Malinen #endif /* CTRL_IFACE_SOCKET */
422cd4e3c3eSJouni Malinen 
423cd4e3c3eSJouni Malinen 
424cd4e3c3eSJouni Malinen #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
425cd4e3c3eSJouni Malinen 
426cd4e3c3eSJouni Malinen #ifndef WPA_SUPPLICANT_NAMED_PIPE
427cd4e3c3eSJouni Malinen #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
428cd4e3c3eSJouni Malinen #endif
429cd4e3c3eSJouni Malinen #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
430cd4e3c3eSJouni Malinen 
wpa_ctrl_open(const char * ctrl_path)431cd4e3c3eSJouni Malinen struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
432cd4e3c3eSJouni Malinen {
433cd4e3c3eSJouni Malinen 	struct wpa_ctrl *ctrl;
434cd4e3c3eSJouni Malinen 	DWORD mode;
435cd4e3c3eSJouni Malinen 	TCHAR name[256];
436cd4e3c3eSJouni Malinen 	int i, ret;
437cd4e3c3eSJouni Malinen 
438cd4e3c3eSJouni Malinen 	ctrl = os_malloc(sizeof(*ctrl));
439cd4e3c3eSJouni Malinen 	if (ctrl == NULL)
440cd4e3c3eSJouni Malinen 		return NULL;
441cd4e3c3eSJouni Malinen 	os_memset(ctrl, 0, sizeof(*ctrl));
442cd4e3c3eSJouni Malinen 
443cd4e3c3eSJouni Malinen #ifdef UNICODE
444cd4e3c3eSJouni Malinen 	if (ctrl_path == NULL)
445cd4e3c3eSJouni Malinen 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
446cd4e3c3eSJouni Malinen 	else
447cd4e3c3eSJouni Malinen 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
448cd4e3c3eSJouni Malinen 				 ctrl_path);
449cd4e3c3eSJouni Malinen #else /* UNICODE */
450cd4e3c3eSJouni Malinen 	if (ctrl_path == NULL)
451cd4e3c3eSJouni Malinen 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
452cd4e3c3eSJouni Malinen 	else
453cd4e3c3eSJouni Malinen 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
454cd4e3c3eSJouni Malinen 				  ctrl_path);
455cd4e3c3eSJouni Malinen #endif /* UNICODE */
456cd4e3c3eSJouni Malinen 	if (ret < 0 || ret >= 256) {
457cd4e3c3eSJouni Malinen 		os_free(ctrl);
458cd4e3c3eSJouni Malinen 		return NULL;
459cd4e3c3eSJouni Malinen 	}
460cd4e3c3eSJouni Malinen 
461cd4e3c3eSJouni Malinen 	for (i = 0; i < 10; i++) {
462cd4e3c3eSJouni Malinen 		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
463cd4e3c3eSJouni Malinen 					NULL, OPEN_EXISTING, 0, NULL);
464cd4e3c3eSJouni Malinen 		/*
465cd4e3c3eSJouni Malinen 		 * Current named pipe server side in wpa_supplicant is
466cd4e3c3eSJouni Malinen 		 * re-opening the pipe for new clients only after the previous
467cd4e3c3eSJouni Malinen 		 * one is taken into use. This leaves a small window for race
468cd4e3c3eSJouni Malinen 		 * conditions when two connections are being opened at almost
469cd4e3c3eSJouni Malinen 		 * the same time. Retry if that was the case.
470cd4e3c3eSJouni Malinen 		 */
471cd4e3c3eSJouni Malinen 		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
472cd4e3c3eSJouni Malinen 		    GetLastError() != ERROR_PIPE_BUSY)
473cd4e3c3eSJouni Malinen 			break;
474cd4e3c3eSJouni Malinen 		WaitNamedPipe(name, 1000);
475cd4e3c3eSJouni Malinen 	}
476cd4e3c3eSJouni Malinen 	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
477cd4e3c3eSJouni Malinen 		os_free(ctrl);
478cd4e3c3eSJouni Malinen 		return NULL;
479cd4e3c3eSJouni Malinen 	}
480cd4e3c3eSJouni Malinen 
481cd4e3c3eSJouni Malinen 	mode = PIPE_READMODE_MESSAGE;
482cd4e3c3eSJouni Malinen 	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
483cd4e3c3eSJouni Malinen 		CloseHandle(ctrl->pipe);
484cd4e3c3eSJouni Malinen 		os_free(ctrl);
485cd4e3c3eSJouni Malinen 		return NULL;
486cd4e3c3eSJouni Malinen 	}
487cd4e3c3eSJouni Malinen 
488cd4e3c3eSJouni Malinen 	return ctrl;
489cd4e3c3eSJouni Malinen }
490cd4e3c3eSJouni Malinen 
491cd4e3c3eSJouni Malinen 
wpa_ctrl_close(struct wpa_ctrl * ctrl)492cd4e3c3eSJouni Malinen void wpa_ctrl_close(struct wpa_ctrl *ctrl)
493cd4e3c3eSJouni Malinen {
494cd4e3c3eSJouni Malinen 	CloseHandle(ctrl->pipe);
495cd4e3c3eSJouni Malinen 	os_free(ctrl);
496cd4e3c3eSJouni Malinen }
497cd4e3c3eSJouni Malinen 
498cd4e3c3eSJouni Malinen 
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))499cd4e3c3eSJouni Malinen int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
500cd4e3c3eSJouni Malinen 		     char *reply, size_t *reply_len,
501cd4e3c3eSJouni Malinen 		     void (*msg_cb)(char *msg, size_t len))
502cd4e3c3eSJouni Malinen {
503cd4e3c3eSJouni Malinen 	DWORD written;
504cd4e3c3eSJouni Malinen 	DWORD readlen = *reply_len;
505cd4e3c3eSJouni Malinen 
506cd4e3c3eSJouni Malinen 	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
507cd4e3c3eSJouni Malinen 		return -1;
508cd4e3c3eSJouni Malinen 
509cd4e3c3eSJouni Malinen 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
510cd4e3c3eSJouni Malinen 		return -1;
511cd4e3c3eSJouni Malinen 	*reply_len = readlen;
512cd4e3c3eSJouni Malinen 
513cd4e3c3eSJouni Malinen 	return 0;
514cd4e3c3eSJouni Malinen }
515cd4e3c3eSJouni Malinen 
516cd4e3c3eSJouni Malinen 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)517cd4e3c3eSJouni Malinen int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
518cd4e3c3eSJouni Malinen {
519cd4e3c3eSJouni Malinen 	DWORD len = *reply_len;
520cd4e3c3eSJouni Malinen 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
521cd4e3c3eSJouni Malinen 		return -1;
522cd4e3c3eSJouni Malinen 	*reply_len = len;
523cd4e3c3eSJouni Malinen 	return 0;
524cd4e3c3eSJouni Malinen }
525cd4e3c3eSJouni Malinen 
526cd4e3c3eSJouni Malinen 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)527cd4e3c3eSJouni Malinen int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
528cd4e3c3eSJouni Malinen {
529cd4e3c3eSJouni Malinen 	DWORD left;
530cd4e3c3eSJouni Malinen 
531cd4e3c3eSJouni Malinen 	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
532cd4e3c3eSJouni Malinen 		return -1;
533cd4e3c3eSJouni Malinen 	return left ? 1 : 0;
534cd4e3c3eSJouni Malinen }
535cd4e3c3eSJouni Malinen 
536cd4e3c3eSJouni Malinen 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)537cd4e3c3eSJouni Malinen int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
538cd4e3c3eSJouni Malinen {
539cd4e3c3eSJouni Malinen 	return -1;
540cd4e3c3eSJouni Malinen }
541cd4e3c3eSJouni Malinen 
542cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
543cd4e3c3eSJouni Malinen 
544cd4e3c3eSJouni Malinen #endif /* CONFIG_CTRL_IFACE */
545