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