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