• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "includes.h"
10 
11 #ifdef CONFIG_CTRL_IFACE
12 
13 #ifdef CONFIG_CTRL_IFACE_UNIX
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <sys/un.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #endif /* CONFIG_CTRL_IFACE_UNIX */
20 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
21 #include <netdb.h>
22 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
23 
24 #ifdef ANDROID
25 #include <dirent.h>
26 #include <sys/stat.h>
27 #include <cutils/sockets.h>
28 #include "private/android_filesystem_config.h"
29 #endif /* ANDROID */
30 
31 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
32 #include <net/if.h>
33 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
34 
35 #include "wpa_ctrl.h"
36 #include "common.h"
37 
38 #ifdef CONFIG_OPEN_HARMONY_PATCH
39 #include <grp.h>
40 #include <pwd.h>
41 #include <sys/types.h>
42 #endif /* CONFIG_OPEN_HARMONY_PATCH */
43 
44 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
45 #define CTRL_IFACE_SOCKET
46 #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
47 
48 
49 /**
50  * struct wpa_ctrl - Internal structure for control interface library
51  *
52  * This structure is used by the wpa_supplicant/hostapd control interface
53  * library to store internal data. Programs using the library should not touch
54  * this data directly. They can only use the pointer to the data structure as
55  * an identifier for the control interface connection and use this as one of
56  * the arguments for most of the control interface library functions.
57  */
58 struct wpa_ctrl {
59 #ifdef CONFIG_CTRL_IFACE_UDP
60 	int s;
61 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
62 	struct sockaddr_in6 local;
63 	struct sockaddr_in6 dest;
64 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
65 	struct sockaddr_in local;
66 	struct sockaddr_in dest;
67 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
68 	char *cookie;
69 	char *remote_ifname;
70 	char *remote_ip;
71 #endif /* CONFIG_CTRL_IFACE_UDP */
72 #ifdef CONFIG_CTRL_IFACE_UNIX
73 	int s;
74 	struct sockaddr_un local;
75 	struct sockaddr_un dest;
76 #endif /* CONFIG_CTRL_IFACE_UNIX */
77 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
78 	HANDLE pipe;
79 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
80 };
81 
82 
83 #ifdef CONFIG_CTRL_IFACE_UNIX
84 
85 #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
86 
87 #ifdef OHOS_EUPDATER
88 #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp/service/el1/public/wifi"
89 #else
90 #define CONFIG_CTRL_IFACE_CLIENT_DIR "/data/service/el1/public/wifi"
91 #endif // OHOS_EUPDATER
92 
93 #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
94 #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
95 #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
96 #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
97 
98 
wpa_ctrl_open(const char * ctrl_path)99 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
100 {
101 	return wpa_ctrl_open2(ctrl_path, NULL);
102 }
103 
104 
wpa_ctrl_open2(const char * ctrl_path,const char * cli_path)105 struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
106 				 const char *cli_path)
107 {
108 	struct wpa_ctrl *ctrl;
109 	static int counter = 0;
110 	int ret;
111 	size_t res;
112 	int tries = 0;
113 	int flags;
114 #ifdef CONFIG_OPEN_HARMONY_PATCH
115 	struct group *grp_wifi;
116 	gid_t gid_wifi;
117 	struct passwd *pwd_wifi;
118 	uid_t uid_wifi;
119 #endif /* CONFIG_OPEN_HARMONY_PATCH */
120 
121 
122 	if (ctrl_path == NULL)
123 		return NULL;
124 
125 	ctrl = os_zalloc(sizeof(*ctrl));
126 	if (ctrl == NULL)
127 		return NULL;
128 
129 	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
130 	if (ctrl->s < 0) {
131 		os_free(ctrl);
132 		return NULL;
133 	}
134 
135 	ctrl->local.sun_family = AF_UNIX;
136 	counter++;
137 try_again:
138 	if (cli_path && cli_path[0] == '/') {
139 		ret = os_snprintf(ctrl->local.sun_path,
140 				  sizeof(ctrl->local.sun_path),
141 				  "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
142 				  cli_path, (int) getpid(), counter);
143 	} else {
144 		ret = os_snprintf(ctrl->local.sun_path,
145 				  sizeof(ctrl->local.sun_path),
146 				  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
147 				  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
148 				  (int) getpid(), counter);
149 	}
150 	if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
151 		close(ctrl->s);
152 		os_free(ctrl);
153 		return NULL;
154 	}
155 	tries++;
156 #ifdef ANDROID
157 	/* Set client socket file permissions so that bind() creates the client
158 	 * socket with these permissions and there is no need to try to change
159 	 * them with chmod() after bind() which would have potential issues with
160 	 * race conditions. These permissions are needed to make sure the server
161 	 * side (wpa_supplicant or hostapd) can reply to the control interface
162 	 * messages.
163 	 *
164 	 * The lchown() calls below after bind() are also part of the needed
165 	 * operations to allow the response to go through. Those are using the
166 	 * no-deference-symlinks version to avoid races. */
167 	fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
168 #endif /* ANDROID */
169 	fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
170 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
171 		    sizeof(ctrl->local)) < 0) {
172 		if (errno == EADDRINUSE && tries < 2) {
173 			/*
174 			 * getpid() returns unique identifier for this instance
175 			 * of wpa_ctrl, so the existing socket file must have
176 			 * been left by unclean termination of an earlier run.
177 			 * Remove the file and try again.
178 			 */
179 			unlink(ctrl->local.sun_path);
180 			goto try_again;
181 		}
182 		close(ctrl->s);
183 		os_free(ctrl);
184 		return NULL;
185 	}
186 #ifdef CONFIG_OPEN_HARMONY_PATCH
187 	ret = chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
188 	if (ret != 0) {
189 		wpa_printf(MSG_ERROR, "chmod %s error:%s", ctrl->local.sun_path, strerror(errno));
190 	}
191 	grp_wifi = getgrnam("wifi");
192 	gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0;
193 	pwd_wifi = getpwnam("wifi");
194 	uid_wifi = pwd_wifi ? pwd_wifi->pw_uid : 0;
195 	if (!gid_wifi || !pwd_wifi) {
196 		wpa_printf(MSG_ERROR, "wpa ctrl get gid(wifi) or uid(wifi) fail");
197 		close(ctrl->s);
198 		unlink(ctrl->local.sun_path);
199 		os_free(ctrl);
200 		return NULL;
201 	}
202 	wpa_printf(MSG_DEBUG, "uid_wifi is %u, gid_wifi is %u", uid_wifi, gid_wifi);
203 	chown(ctrl->local.sun_path, -1, gid_wifi);
204 	chown(ctrl->local.sun_path, uid_wifi, gid_wifi);
205 #endif /* CONFIG_OPEN_HARMONY_PATCH */
206 #ifdef ANDROID
207 	/* Set group even if we do not have privileges to change owner */
208 	lchown(ctrl->local.sun_path, -1, AID_WIFI);
209 	lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
210 
211 	if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
212 		if (socket_local_client_connect(
213 			    ctrl->s, ctrl_path + 9,
214 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
215 			    SOCK_DGRAM) < 0) {
216 			close(ctrl->s);
217 			unlink(ctrl->local.sun_path);
218 			os_free(ctrl);
219 			return NULL;
220 		}
221 		return ctrl;
222 	}
223 
224 	/*
225 	 * If the ctrl_path isn't an absolute pathname, assume that
226 	 * it's the name of a socket in the Android reserved namespace.
227 	 * Otherwise, it's a normal UNIX domain socket appearing in the
228 	 * filesystem.
229 	 */
230 	if (*ctrl_path != '/') {
231 		char buf[21];
232 		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
233 		if (socket_local_client_connect(
234 			    ctrl->s, buf,
235 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
236 			    SOCK_DGRAM) < 0) {
237 			close(ctrl->s);
238 			unlink(ctrl->local.sun_path);
239 			os_free(ctrl);
240 			return NULL;
241 		}
242 		return ctrl;
243 	}
244 #endif /* ANDROID */
245 
246 	ctrl->dest.sun_family = AF_UNIX;
247 	if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
248 		ctrl->dest.sun_path[0] = '\0';
249 		os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
250 			   sizeof(ctrl->dest.sun_path) - 1);
251 	} else {
252 		res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
253 				 sizeof(ctrl->dest.sun_path));
254 		if (res >= sizeof(ctrl->dest.sun_path)) {
255 			close(ctrl->s);
256 			os_free(ctrl);
257 			return NULL;
258 		}
259 	}
260 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
261 		    sizeof(ctrl->dest)) < 0) {
262 		close(ctrl->s);
263 		unlink(ctrl->local.sun_path);
264 		os_free(ctrl);
265 		return NULL;
266 	}
267 
268 	/*
269 	 * Make socket non-blocking so that we don't hang forever if
270 	 * target dies unexpectedly.
271 	 */
272 	flags = fcntl(ctrl->s, F_GETFL);
273 	if (flags >= 0) {
274 		flags |= O_NONBLOCK;
275 		if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
276 			perror("fcntl(ctrl->s, O_NONBLOCK)");
277 			/* Not fatal, continue on.*/
278 		}
279 	}
280 
281 	return ctrl;
282 }
283 
284 
wpa_ctrl_close(struct wpa_ctrl * ctrl)285 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
286 {
287 	if (ctrl == NULL)
288 		return;
289 	unlink(ctrl->local.sun_path);
290 	if (ctrl->s >= 0)
291 		close(ctrl->s);
292 	os_free(ctrl);
293 }
294 
295 
296 #ifdef ANDROID
297 /**
298  * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
299  * may be left over from clients that were previously connected to
300  * wpa_supplicant. This keeps these files from being orphaned in the
301  * event of crashes that prevented them from being removed as part
302  * of the normal orderly shutdown.
303  */
wpa_ctrl_cleanup(void)304 void wpa_ctrl_cleanup(void)
305 {
306 	DIR *dir;
307 	struct dirent *result;
308 	size_t dirnamelen;
309 	size_t maxcopy;
310 	char pathname[PATH_MAX];
311 	char *namep;
312 
313 	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
314 		return;
315 
316 	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
317 					  CONFIG_CTRL_IFACE_CLIENT_DIR);
318 	if (dirnamelen >= sizeof(pathname)) {
319 		closedir(dir);
320 		return;
321 	}
322 	namep = pathname + dirnamelen;
323 	maxcopy = PATH_MAX - dirnamelen;
324 	while ((result = readdir(dir)) != NULL) {
325 		if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
326 			unlink(pathname);
327 	}
328 	closedir(dir);
329 }
330 #endif /* ANDROID */
331 
332 #else /* CONFIG_CTRL_IFACE_UNIX */
333 
334 #ifdef ANDROID
wpa_ctrl_cleanup(void)335 void wpa_ctrl_cleanup(void)
336 {
337 }
338 #endif /* ANDROID */
339 
340 #endif /* CONFIG_CTRL_IFACE_UNIX */
341 
342 #ifdef CONFIG_CTRL_IFACE_UDP
343 #if defined(CONFIG_OPEN_HARMONY_PATCH) || defined(CONFIG_OPEN_HARMONY_PATCH_LITE)
wpa_ctrl_port(const char * ctrl_path,struct wpa_ctrl * ctrl)344 int wpa_ctrl_port(const char *ctrl_path, struct wpa_ctrl *ctrl)
345 {
346 	if (ctrl_path == NULL || ctrl == NULL) {
347 		return -1;
348 	}
349 
350 	if (os_strcmp(ctrl_path, "global") == 0) {
351 		ctrl->dest.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
352 		return 0;
353 	}
354 
355 	char *port, *name;
356 	int port_id;
357 	name = os_strdup(ctrl_path);
358 	if (name == NULL) {
359 		return -1;
360 	}
361 
362 	port = os_strchr(name, ':');
363 	if (port) {
364 		port_id = atoi(&port[1]);
365 		port[0] = '\0';
366 		ctrl->dest.sin_port = htons(port_id);
367 	}
368 	os_free(name);
369 	return 0;
370 }
371 #endif /* CONFIG_OPEN_HARMONY_PATCH */
372 
wpa_ctrl_open(const char * ctrl_path)373 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
374 {
375 	struct wpa_ctrl *ctrl;
376 	char buf[128];
377 	size_t len;
378 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
379 	struct hostent *h;
380 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
381 
382 	ctrl = os_zalloc(sizeof(*ctrl));
383 	if (ctrl == NULL)
384 		return NULL;
385 
386 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
387 	ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
388 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
389 	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
390 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
391 	if (ctrl->s < 0) {
392 		perror("socket");
393 		os_free(ctrl);
394 		return NULL;
395 	}
396 
397 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
398 	ctrl->local.sin6_family = AF_INET6;
399 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
400 	ctrl->local.sin6_addr = in6addr_any;
401 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
402 	inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
403 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
404 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
405 	ctrl->local.sin_family = AF_INET;
406 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
407 	ctrl->local.sin_addr.s_addr = INADDR_ANY;
408 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
409 	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
410 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
411 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
412 
413 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
414 		 sizeof(ctrl->local)) < 0) {
415 		close(ctrl->s);
416 		os_free(ctrl);
417 		return NULL;
418 	}
419 
420 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
421 	ctrl->dest.sin6_family = AF_INET6;
422 	inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
423 	ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
424 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
425 	ctrl->dest.sin_family = AF_INET;
426 	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
427 	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
428 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
429 
430 #if defined(CONFIG_OPEN_HARMONY_PATCH) || defined(CONFIG_OPEN_HARMONY_PATCH_LITE)
431 	if (wpa_ctrl_port(ctrl_path, ctrl) < 0) {
432 		wpa_printf(MSG_ERROR, "get port fail");
433 	}
434 #endif /* CONFIG_OPEN_HARMONY_PATCH | CONFIG_OPEN_HARMONY_PATCH_LITE */
435 
436 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
437 	if (ctrl_path) {
438 		char *port, *name;
439 		int port_id;
440 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
441 		char *scope;
442 		int scope_id = 0;
443 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
444 
445 		name = os_strdup(ctrl_path);
446 		if (name == NULL) {
447 			close(ctrl->s);
448 			os_free(ctrl);
449 			return NULL;
450 		}
451 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
452 		port = os_strchr(name, ',');
453 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
454 		port = os_strchr(name, ':');
455 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
456 
457 		if (port) {
458 			port_id = atoi(&port[1]);
459 			port[0] = '\0';
460 		} else
461 			port_id = WPA_CTRL_IFACE_PORT;
462 
463 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
464 		scope = os_strchr(name, '%');
465 		if (scope) {
466 			scope_id = if_nametoindex(&scope[1]);
467 			scope[0] = '\0';
468 		}
469 		h = gethostbyname2(name, AF_INET6);
470 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
471 		h = gethostbyname(name);
472 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
473 		ctrl->remote_ip = os_strdup(name);
474 		os_free(name);
475 		if (h == NULL) {
476 			perror("gethostbyname");
477 			close(ctrl->s);
478 			os_free(ctrl->remote_ip);
479 			os_free(ctrl);
480 			return NULL;
481 		}
482 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
483 		ctrl->dest.sin6_scope_id = scope_id;
484 		ctrl->dest.sin6_port = htons(port_id);
485 		os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
486 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
487 		ctrl->dest.sin_port = htons(port_id);
488 		os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
489 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
490 	} else
491 		ctrl->remote_ip = os_strdup("localhost");
492 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
493 
494 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
495 		    sizeof(ctrl->dest)) < 0) {
496 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
497 		char addr[INET6_ADDRSTRLEN];
498 		wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
499 			   inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
500 				     sizeof(ctrl->dest)),
501 			   ntohs(ctrl->dest.sin6_port),
502 			   strerror(errno));
503 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
504 		wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
505 			   inet_ntoa(ctrl->dest.sin_addr),
506 			   ntohs(ctrl->dest.sin_port),
507 			   strerror(errno));
508 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
509 		close(ctrl->s);
510 		os_free(ctrl->remote_ip);
511 		os_free(ctrl);
512 		return NULL;
513 	}
514 
515 	len = sizeof(buf) - 1;
516 	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
517 		buf[len] = '\0';
518 		ctrl->cookie = os_strdup(buf);
519 	}
520 
521 	if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
522 		buf[len] = '\0';
523 		ctrl->remote_ifname = os_strdup(buf);
524 	}
525 
526 	return ctrl;
527 }
528 
529 
wpa_ctrl_get_remote_ifname(struct wpa_ctrl * ctrl)530 char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
531 {
532 #define WPA_CTRL_MAX_PS_NAME 100
533 	static char ps[WPA_CTRL_MAX_PS_NAME] = {};
534 	os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
535 		    ctrl->remote_ip, ctrl->remote_ifname);
536 	return ps;
537 }
538 
539 
wpa_ctrl_close(struct wpa_ctrl * ctrl)540 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
541 {
542 	close(ctrl->s);
543 	os_free(ctrl->cookie);
544 	os_free(ctrl->remote_ifname);
545 	os_free(ctrl->remote_ip);
546 	os_free(ctrl);
547 }
548 
549 #endif /* CONFIG_CTRL_IFACE_UDP */
550 
551 
552 #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))553 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
554 		     char *reply, size_t *reply_len,
555 		     void (*msg_cb)(char *msg, size_t len))
556 {
557 	struct timeval tv;
558 	struct os_reltime started_at, ending_at;
559 	int res;
560 	fd_set rfds;
561 	const char *_cmd;
562 	char *cmd_buf = NULL;
563 	size_t _cmd_len;
564 #ifdef CONFIG_OPEN_HARMONY_PATCH
565 	if (disable_anonymized_print()) {
566 		wpa_printf(MSG_INFO, "wpa_ctrl_request cmd: %s", cmd);
567 	}
568 #endif // CONFIG_OPEN_HARMONY_PATCH
569 
570 #ifdef CONFIG_CTRL_IFACE_UDP
571 	if (ctrl->cookie) {
572 		char *pos;
573 		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
574 		cmd_buf = os_malloc(_cmd_len);
575 		if (cmd_buf == NULL)
576 			return -1;
577 		_cmd = cmd_buf;
578 		pos = cmd_buf;
579 		os_strlcpy(pos, ctrl->cookie, _cmd_len);
580 		pos += os_strlen(ctrl->cookie);
581 		*pos++ = ' ';
582 		os_memcpy(pos, cmd, cmd_len);
583 	} else
584 #endif /* CONFIG_CTRL_IFACE_UDP */
585 	{
586 		_cmd = cmd;
587 		_cmd_len = cmd_len;
588 	}
589 
590 	errno = 0;
591 	started_at.sec = 0;
592 	started_at.usec = 0;
593 retry_send:
594 	wpa_printf(MSG_DEBUG, "wpa_ctrl_request send success!");
595 	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
596 		if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
597 		{
598 			/*
599 			 * Must be a non-blocking socket... Try for a bit
600 			 * longer before giving up.
601 			 */
602 			if (started_at.sec == 0)
603 				os_get_reltime(&started_at);
604 			else {
605 				struct os_reltime n;
606 				os_get_reltime(&n);
607 				/* Try for a few seconds. */
608 				if (os_reltime_expired(&n, &started_at, 5))
609 					goto send_err;
610 			}
611 			os_sleep(1, 0);
612 			goto retry_send;
613 		}
614 	send_err:
615 		wpa_printf(MSG_ERROR, "wpa_ctrl_request send fail!");
616 		os_free(cmd_buf);
617 		return -1;
618 	}
619 	os_free(cmd_buf);
620 
621 	os_get_reltime(&ending_at);
622 	ending_at.sec += 10;
623 
624 	for (;;) {
625 		struct os_reltime diff;
626 
627 		os_get_reltime(&started_at);
628 		if (os_reltime_before(&ending_at, &started_at))
629 			return -2;
630 		os_reltime_sub(&ending_at, &started_at, &diff);
631 		tv.tv_sec = diff.sec;
632 		tv.tv_usec = diff.usec;
633 
634 		FD_ZERO(&rfds);
635 		FD_SET(ctrl->s, &rfds);
636 		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
637 		if (res < 0 && errno == EINTR)
638 			continue;
639 		if (res < 0)
640 			return res;
641 		if (FD_ISSET(ctrl->s, &rfds)) {
642 			res = recv(ctrl->s, reply, *reply_len, 0);
643 			wpa_printf(MSG_DEBUG, "wpa_ctrl_request recv success!");
644 			if (res < 0)
645 				return res;
646 			if ((res > 0 && reply[0] == '<') ||
647 			    (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
648 				/* This is an unsolicited message from
649 				 * wpa_supplicant, not the reply to the
650 				 * request. Use msg_cb to report this to the
651 				 * caller. */
652 				if (msg_cb) {
653 					/* Make sure the message is nul
654 					 * terminated. */
655 					if ((size_t) res == *reply_len)
656 						res = (*reply_len) - 1;
657 					reply[res] = '\0';
658 					msg_cb(reply, res);
659 				}
660 				continue;
661 			}
662 			*reply_len = res;
663 			break;
664 		} else {
665 			return -2;
666 		}
667 	}
668 	return 0;
669 }
670 #endif /* CTRL_IFACE_SOCKET */
671 
672 
wpa_ctrl_attach_helper(struct wpa_ctrl * ctrl,int attach)673 static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
674 {
675 	char buf[10];
676 	int ret;
677 	size_t len = 10;
678 
679 	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
680 			       buf, &len, NULL);
681 	if (ret < 0)
682 		return ret;
683 	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
684 		return 0;
685 	return -1;
686 }
687 
688 
wpa_ctrl_attach(struct wpa_ctrl * ctrl)689 int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
690 {
691 	return wpa_ctrl_attach_helper(ctrl, 1);
692 }
693 
694 
wpa_ctrl_detach(struct wpa_ctrl * ctrl)695 int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
696 {
697 	return wpa_ctrl_attach_helper(ctrl, 0);
698 }
699 
700 
701 #ifdef CTRL_IFACE_SOCKET
702 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)703 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
704 {
705 	int res;
706 
707 	res = recv(ctrl->s, reply, *reply_len, 0);
708 	if (res < 0)
709 		return res;
710 	*reply_len = res;
711 	return 0;
712 }
713 
714 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)715 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
716 {
717 	struct timeval tv;
718 	fd_set rfds;
719 	tv.tv_sec = 0;
720 	tv.tv_usec = 0;
721 	FD_ZERO(&rfds);
722 	FD_SET(ctrl->s, &rfds);
723 	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
724 	return FD_ISSET(ctrl->s, &rfds);
725 }
726 
727 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)728 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
729 {
730 	return ctrl->s;
731 }
732 
733 #endif /* CTRL_IFACE_SOCKET */
734 
735 
736 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
737 
738 #ifndef WPA_SUPPLICANT_NAMED_PIPE
739 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
740 #endif
741 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
742 
wpa_ctrl_open(const char * ctrl_path)743 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
744 {
745 	struct wpa_ctrl *ctrl;
746 	DWORD mode;
747 	TCHAR name[256];
748 	int i, ret;
749 
750 	ctrl = os_malloc(sizeof(*ctrl));
751 	if (ctrl == NULL)
752 		return NULL;
753 	os_memset(ctrl, 0, sizeof(*ctrl));
754 
755 #ifdef UNICODE
756 	if (ctrl_path == NULL)
757 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
758 	else
759 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
760 				 ctrl_path);
761 #else /* UNICODE */
762 	if (ctrl_path == NULL)
763 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
764 	else
765 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
766 				  ctrl_path);
767 #endif /* UNICODE */
768 	if (os_snprintf_error(256, ret)) {
769 		os_free(ctrl);
770 		return NULL;
771 	}
772 
773 	for (i = 0; i < 10; i++) {
774 		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
775 					NULL, OPEN_EXISTING, 0, NULL);
776 		/*
777 		 * Current named pipe server side in wpa_supplicant is
778 		 * re-opening the pipe for new clients only after the previous
779 		 * one is taken into use. This leaves a small window for race
780 		 * conditions when two connections are being opened at almost
781 		 * the same time. Retry if that was the case.
782 		 */
783 		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
784 		    GetLastError() != ERROR_PIPE_BUSY)
785 			break;
786 		WaitNamedPipe(name, 1000);
787 	}
788 	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
789 		os_free(ctrl);
790 		return NULL;
791 	}
792 
793 	mode = PIPE_READMODE_MESSAGE;
794 	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
795 		CloseHandle(ctrl->pipe);
796 		os_free(ctrl);
797 		return NULL;
798 	}
799 
800 	return ctrl;
801 }
802 
803 
wpa_ctrl_close(struct wpa_ctrl * ctrl)804 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
805 {
806 	CloseHandle(ctrl->pipe);
807 	os_free(ctrl);
808 }
809 
810 
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))811 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
812 		     char *reply, size_t *reply_len,
813 		     void (*msg_cb)(char *msg, size_t len))
814 {
815 	DWORD written;
816 	DWORD readlen = *reply_len;
817 
818 	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
819 		return -1;
820 
821 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
822 		return -1;
823 	*reply_len = readlen;
824 
825 	return 0;
826 }
827 
828 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)829 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
830 {
831 	DWORD len = *reply_len;
832 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
833 		return -1;
834 	*reply_len = len;
835 	return 0;
836 }
837 
838 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)839 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
840 {
841 	DWORD left;
842 
843 	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
844 		return -1;
845 	return left ? 1 : 0;
846 }
847 
848 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)849 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
850 {
851 	return -1;
852 }
853 
854 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
855 
856 #endif /* CONFIG_CTRL_IFACE */
857