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