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