• 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;
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 	for (;;) {
622 		tv.tv_sec = 10;
623 		tv.tv_usec = 0;
624 		FD_ZERO(&rfds);
625 		FD_SET(ctrl->s, &rfds);
626 		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
627 		if (res < 0 && errno == EINTR)
628 			continue;
629 		if (res < 0)
630 			return res;
631 		if (FD_ISSET(ctrl->s, &rfds)) {
632 			res = recv(ctrl->s, reply, *reply_len, 0);
633 			wpa_printf(MSG_DEBUG, "wpa_ctrl_request recv success!");
634 			if (res < 0)
635 				return res;
636 			if ((res > 0 && reply[0] == '<') ||
637 			    (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
638 				/* This is an unsolicited message from
639 				 * wpa_supplicant, not the reply to the
640 				 * request. Use msg_cb to report this to the
641 				 * caller. */
642 				if (msg_cb) {
643 					/* Make sure the message is nul
644 					 * terminated. */
645 					if ((size_t) res == *reply_len)
646 						res = (*reply_len) - 1;
647 					reply[res] = '\0';
648 					msg_cb(reply, res);
649 				}
650 				continue;
651 			}
652 			*reply_len = res;
653 			break;
654 		} else {
655 			return -2;
656 		}
657 	}
658 	return 0;
659 }
660 #endif /* CTRL_IFACE_SOCKET */
661 
662 
wpa_ctrl_attach_helper(struct wpa_ctrl * ctrl,int attach)663 static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
664 {
665 	char buf[10];
666 	int ret;
667 	size_t len = 10;
668 
669 	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
670 			       buf, &len, NULL);
671 	if (ret < 0)
672 		return ret;
673 	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
674 		return 0;
675 	return -1;
676 }
677 
678 
wpa_ctrl_attach(struct wpa_ctrl * ctrl)679 int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
680 {
681 	return wpa_ctrl_attach_helper(ctrl, 1);
682 }
683 
684 
wpa_ctrl_detach(struct wpa_ctrl * ctrl)685 int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
686 {
687 	return wpa_ctrl_attach_helper(ctrl, 0);
688 }
689 
690 
691 #ifdef CTRL_IFACE_SOCKET
692 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)693 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
694 {
695 	int res;
696 
697 	res = recv(ctrl->s, reply, *reply_len, 0);
698 	if (res < 0)
699 		return res;
700 	*reply_len = res;
701 	return 0;
702 }
703 
704 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)705 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
706 {
707 	struct timeval tv;
708 	fd_set rfds;
709 	tv.tv_sec = 0;
710 	tv.tv_usec = 0;
711 	FD_ZERO(&rfds);
712 	FD_SET(ctrl->s, &rfds);
713 	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
714 	return FD_ISSET(ctrl->s, &rfds);
715 }
716 
717 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)718 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
719 {
720 	return ctrl->s;
721 }
722 
723 #endif /* CTRL_IFACE_SOCKET */
724 
725 
726 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
727 
728 #ifndef WPA_SUPPLICANT_NAMED_PIPE
729 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
730 #endif
731 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
732 
wpa_ctrl_open(const char * ctrl_path)733 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
734 {
735 	struct wpa_ctrl *ctrl;
736 	DWORD mode;
737 	TCHAR name[256];
738 	int i, ret;
739 
740 	ctrl = os_malloc(sizeof(*ctrl));
741 	if (ctrl == NULL)
742 		return NULL;
743 	os_memset(ctrl, 0, sizeof(*ctrl));
744 
745 #ifdef UNICODE
746 	if (ctrl_path == NULL)
747 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
748 	else
749 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
750 				 ctrl_path);
751 #else /* UNICODE */
752 	if (ctrl_path == NULL)
753 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
754 	else
755 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
756 				  ctrl_path);
757 #endif /* UNICODE */
758 	if (os_snprintf_error(256, ret)) {
759 		os_free(ctrl);
760 		return NULL;
761 	}
762 
763 	for (i = 0; i < 10; i++) {
764 		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
765 					NULL, OPEN_EXISTING, 0, NULL);
766 		/*
767 		 * Current named pipe server side in wpa_supplicant is
768 		 * re-opening the pipe for new clients only after the previous
769 		 * one is taken into use. This leaves a small window for race
770 		 * conditions when two connections are being opened at almost
771 		 * the same time. Retry if that was the case.
772 		 */
773 		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
774 		    GetLastError() != ERROR_PIPE_BUSY)
775 			break;
776 		WaitNamedPipe(name, 1000);
777 	}
778 	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
779 		os_free(ctrl);
780 		return NULL;
781 	}
782 
783 	mode = PIPE_READMODE_MESSAGE;
784 	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
785 		CloseHandle(ctrl->pipe);
786 		os_free(ctrl);
787 		return NULL;
788 	}
789 
790 	return ctrl;
791 }
792 
793 
wpa_ctrl_close(struct wpa_ctrl * ctrl)794 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
795 {
796 	CloseHandle(ctrl->pipe);
797 	os_free(ctrl);
798 }
799 
800 
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))801 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
802 		     char *reply, size_t *reply_len,
803 		     void (*msg_cb)(char *msg, size_t len))
804 {
805 	DWORD written;
806 	DWORD readlen = *reply_len;
807 
808 	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
809 		return -1;
810 
811 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
812 		return -1;
813 	*reply_len = readlen;
814 
815 	return 0;
816 }
817 
818 
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)819 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
820 {
821 	DWORD len = *reply_len;
822 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
823 		return -1;
824 	*reply_len = len;
825 	return 0;
826 }
827 
828 
wpa_ctrl_pending(struct wpa_ctrl * ctrl)829 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
830 {
831 	DWORD left;
832 
833 	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
834 		return -1;
835 	return left ? 1 : 0;
836 }
837 
838 
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)839 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
840 {
841 	return -1;
842 }
843 
844 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
845 
846 #endif /* CONFIG_CTRL_IFACE */
847