blob: 8722b1998102eaf438d47a848c1ec1c4806145a7 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * wpa_supplicant/hostapd control interface library
3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#ifdef CONFIG_CTRL_IFACE
12
13#ifdef CONFIG_CTRL_IFACE_UNIX
Hai Shalom74f70d42019-02-11 14:42:39 -080014#include <sys/stat.h>
15#include <fcntl.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include <sys/un.h>
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070017#include <unistd.h>
18#include <fcntl.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#endif /* CONFIG_CTRL_IFACE_UNIX */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070020#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
21#include <netdb.h>
22#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023
24#ifdef ANDROID
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080025#include <dirent.h>
Yifan Hong96362de2017-07-20 14:15:22 -070026#include <grp.h>
27#include <pwd.h>
Mark Salyzyndb238192015-03-31 17:58:11 -070028#include <sys/stat.h>
Yifan Hong96362de2017-07-20 14:15:22 -070029#include <sys/types.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include <cutils/sockets.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070031#endif /* ANDROID */
32
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080033#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
34#include <net/if.h>
35#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
36
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070037#include "wpa_ctrl.h"
38#include "common.h"
39
40
41#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
42#define CTRL_IFACE_SOCKET
43#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
44
45
46/**
47 * struct wpa_ctrl - Internal structure for control interface library
48 *
49 * This structure is used by the wpa_supplicant/hostapd control interface
50 * library to store internal data. Programs using the library should not touch
51 * this data directly. They can only use the pointer to the data structure as
52 * an identifier for the control interface connection and use this as one of
53 * the arguments for most of the control interface library functions.
54 */
55struct wpa_ctrl {
56#ifdef CONFIG_CTRL_IFACE_UDP
57 int s;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080058#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
59 struct sockaddr_in6 local;
60 struct sockaddr_in6 dest;
61#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070062 struct sockaddr_in local;
63 struct sockaddr_in dest;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080064#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070065 char *cookie;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070066 char *remote_ifname;
67 char *remote_ip;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070068#endif /* CONFIG_CTRL_IFACE_UDP */
69#ifdef CONFIG_CTRL_IFACE_UNIX
70 int s;
71 struct sockaddr_un local;
72 struct sockaddr_un dest;
73#endif /* CONFIG_CTRL_IFACE_UNIX */
74#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
75 HANDLE pipe;
76#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
77};
78
79
80#ifdef CONFIG_CTRL_IFACE_UNIX
81
82#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
83#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
84#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
85#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
86#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
87#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
88
89
90struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
91{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080092 return wpa_ctrl_open2(ctrl_path, NULL);
93}
94
95
96struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
97 const char *cli_path)
98{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070099 struct wpa_ctrl *ctrl;
100 static int counter = 0;
101 int ret;
102 size_t res;
103 int tries = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700104 int flags;
Yifan Hong96362de2017-07-20 14:15:22 -0700105#ifdef ANDROID
106 struct group *grp_wifi;
107 gid_t gid_wifi;
108 struct passwd *pwd_system;
109 uid_t uid_system;
110#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700111
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700112 if (ctrl_path == NULL)
113 return NULL;
114
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800115 ctrl = os_zalloc(sizeof(*ctrl));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700116 if (ctrl == NULL)
117 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700118
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++;
127try_again:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800128 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 }
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800140 if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700141 close(ctrl->s);
142 os_free(ctrl);
143 return NULL;
144 }
145 tries++;
Hai Shalom74f70d42019-02-11 14:42:39 -0800146#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 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700159 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
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800177 /* Set group even if we do not have privileges to change owner */
Yifan Hong96362de2017-07-20 14:15:22 -0700178 grp_wifi = getgrnam("wifi");
179 gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0;
180 pwd_system = getpwnam("system");
181 uid_system = pwd_system ? pwd_system->pw_uid : 0;
182 if (!gid_wifi || !uid_system) {
183 close(ctrl->s);
184 unlink(ctrl->local.sun_path);
185 os_free(ctrl);
186 return NULL;
187 }
Hai Shalom74f70d42019-02-11 14:42:39 -0800188 lchown(ctrl->local.sun_path, -1, gid_wifi);
189 lchown(ctrl->local.sun_path, uid_system, gid_wifi);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700190
191 if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
192 if (socket_local_client_connect(
193 ctrl->s, ctrl_path + 9,
194 ANDROID_SOCKET_NAMESPACE_RESERVED,
195 SOCK_DGRAM) < 0) {
196 close(ctrl->s);
197 unlink(ctrl->local.sun_path);
198 os_free(ctrl);
199 return NULL;
200 }
201 return ctrl;
202 }
203
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700204 /*
205 * If the ctrl_path isn't an absolute pathname, assume that
206 * it's the name of a socket in the Android reserved namespace.
207 * Otherwise, it's a normal UNIX domain socket appearing in the
208 * filesystem.
209 */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700210 if (*ctrl_path != '/') {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700211 char buf[21];
212 os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
213 if (socket_local_client_connect(
214 ctrl->s, buf,
215 ANDROID_SOCKET_NAMESPACE_RESERVED,
216 SOCK_DGRAM) < 0) {
217 close(ctrl->s);
218 unlink(ctrl->local.sun_path);
219 os_free(ctrl);
220 return NULL;
221 }
222 return ctrl;
223 }
224#endif /* ANDROID */
225
226 ctrl->dest.sun_family = AF_UNIX;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700227 if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
228 ctrl->dest.sun_path[0] = '\0';
229 os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
230 sizeof(ctrl->dest.sun_path) - 1);
231 } else {
232 res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
233 sizeof(ctrl->dest.sun_path));
234 if (res >= sizeof(ctrl->dest.sun_path)) {
235 close(ctrl->s);
236 os_free(ctrl);
237 return NULL;
238 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700239 }
240 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
241 sizeof(ctrl->dest)) < 0) {
242 close(ctrl->s);
243 unlink(ctrl->local.sun_path);
244 os_free(ctrl);
245 return NULL;
246 }
247
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700248 /*
249 * Make socket non-blocking so that we don't hang forever if
250 * target dies unexpectedly.
251 */
252 flags = fcntl(ctrl->s, F_GETFL);
253 if (flags >= 0) {
254 flags |= O_NONBLOCK;
255 if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
256 perror("fcntl(ctrl->s, O_NONBLOCK)");
257 /* Not fatal, continue on.*/
258 }
259 }
260
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700261 return ctrl;
262}
263
264
265void wpa_ctrl_close(struct wpa_ctrl *ctrl)
266{
267 if (ctrl == NULL)
268 return;
269 unlink(ctrl->local.sun_path);
270 if (ctrl->s >= 0)
271 close(ctrl->s);
272 os_free(ctrl);
273}
274
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800275
276#ifdef ANDROID
277/**
278 * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
279 * may be left over from clients that were previously connected to
280 * wpa_supplicant. This keeps these files from being orphaned in the
281 * event of crashes that prevented them from being removed as part
282 * of the normal orderly shutdown.
283 */
284void wpa_ctrl_cleanup(void)
285{
286 DIR *dir;
287 struct dirent entry;
288 struct dirent *result;
289 size_t dirnamelen;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800290 size_t maxcopy;
291 char pathname[PATH_MAX];
292 char *namep;
293
294 if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
295 return;
296
297 dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
298 CONFIG_CTRL_IFACE_CLIENT_DIR);
299 if (dirnamelen >= sizeof(pathname)) {
300 closedir(dir);
301 return;
302 }
303 namep = pathname + dirnamelen;
304 maxcopy = PATH_MAX - dirnamelen;
305 while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
Dmitry Shmidt3733ef32013-09-09 10:26:32 -0700306 if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
307 unlink(pathname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800308 }
309 closedir(dir);
310}
311#endif /* ANDROID */
312
313#else /* CONFIG_CTRL_IFACE_UNIX */
314
315#ifdef ANDROID
316void wpa_ctrl_cleanup(void)
317{
318}
319#endif /* ANDROID */
320
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700321#endif /* CONFIG_CTRL_IFACE_UNIX */
322
323
324#ifdef CONFIG_CTRL_IFACE_UDP
325
326struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
327{
328 struct wpa_ctrl *ctrl;
329 char buf[128];
330 size_t len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700331#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
332 struct hostent *h;
333#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700334
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800335 ctrl = os_zalloc(sizeof(*ctrl));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336 if (ctrl == NULL)
337 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700338
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800339#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
340 ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
341#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342 ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800343#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700344 if (ctrl->s < 0) {
345 perror("socket");
346 os_free(ctrl);
347 return NULL;
348 }
349
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800350#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
351 ctrl->local.sin6_family = AF_INET6;
352#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
353 ctrl->local.sin6_addr = in6addr_any;
354#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
355 inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
356#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
357#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700358 ctrl->local.sin_family = AF_INET;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700359#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
360 ctrl->local.sin_addr.s_addr = INADDR_ANY;
361#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700362 ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700363#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800364#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
365
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700366 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
367 sizeof(ctrl->local)) < 0) {
368 close(ctrl->s);
369 os_free(ctrl);
370 return NULL;
371 }
372
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800373#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
374 ctrl->dest.sin6_family = AF_INET6;
375 inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
376 ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
377#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700378 ctrl->dest.sin_family = AF_INET;
379 ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
380 ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800381#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700382
383#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
384 if (ctrl_path) {
385 char *port, *name;
386 int port_id;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800387#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
388 char *scope;
389 int scope_id = 0;
390#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700391
392 name = os_strdup(ctrl_path);
393 if (name == NULL) {
394 close(ctrl->s);
395 os_free(ctrl);
396 return NULL;
397 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800398#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
399 port = os_strchr(name, ',');
400#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700401 port = os_strchr(name, ':');
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800402#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700403
404 if (port) {
405 port_id = atoi(&port[1]);
406 port[0] = '\0';
407 } else
408 port_id = WPA_CTRL_IFACE_PORT;
409
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800410#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
411 scope = os_strchr(name, '%');
412 if (scope) {
413 scope_id = if_nametoindex(&scope[1]);
414 scope[0] = '\0';
415 }
416 h = gethostbyname2(name, AF_INET6);
417#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700418 h = gethostbyname(name);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800419#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700420 ctrl->remote_ip = os_strdup(name);
421 os_free(name);
422 if (h == NULL) {
423 perror("gethostbyname");
424 close(ctrl->s);
425 os_free(ctrl->remote_ip);
426 os_free(ctrl);
427 return NULL;
428 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800429#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
430 ctrl->dest.sin6_scope_id = scope_id;
431 ctrl->dest.sin6_port = htons(port_id);
432 os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
433#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700434 ctrl->dest.sin_port = htons(port_id);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800435 os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
436#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700437 } else
438 ctrl->remote_ip = os_strdup("localhost");
439#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
440
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700441 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
442 sizeof(ctrl->dest)) < 0) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800443#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
444 char addr[INET6_ADDRSTRLEN];
445 wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
446 inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
447 sizeof(ctrl->dest)),
448 ntohs(ctrl->dest.sin6_port),
449 strerror(errno));
450#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
451 wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
452 inet_ntoa(ctrl->dest.sin_addr),
453 ntohs(ctrl->dest.sin_port),
454 strerror(errno));
455#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700456 close(ctrl->s);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700457 os_free(ctrl->remote_ip);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700458 os_free(ctrl);
459 return NULL;
460 }
461
462 len = sizeof(buf) - 1;
463 if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
464 buf[len] = '\0';
465 ctrl->cookie = os_strdup(buf);
466 }
467
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700468 if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
469 buf[len] = '\0';
470 ctrl->remote_ifname = os_strdup(buf);
471 }
472
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700473 return ctrl;
474}
475
476
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700477char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
478{
479#define WPA_CTRL_MAX_PS_NAME 100
480 static char ps[WPA_CTRL_MAX_PS_NAME] = {};
481 os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
482 ctrl->remote_ip, ctrl->remote_ifname);
483 return ps;
484}
485
486
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700487void wpa_ctrl_close(struct wpa_ctrl *ctrl)
488{
489 close(ctrl->s);
490 os_free(ctrl->cookie);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700491 os_free(ctrl->remote_ifname);
492 os_free(ctrl->remote_ip);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700493 os_free(ctrl);
494}
495
496#endif /* CONFIG_CTRL_IFACE_UDP */
497
498
499#ifdef CTRL_IFACE_SOCKET
500int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
501 char *reply, size_t *reply_len,
502 void (*msg_cb)(char *msg, size_t len))
503{
504 struct timeval tv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800505 struct os_reltime started_at;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700506 int res;
507 fd_set rfds;
508 const char *_cmd;
509 char *cmd_buf = NULL;
510 size_t _cmd_len;
511
512#ifdef CONFIG_CTRL_IFACE_UDP
513 if (ctrl->cookie) {
514 char *pos;
515 _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
516 cmd_buf = os_malloc(_cmd_len);
517 if (cmd_buf == NULL)
518 return -1;
519 _cmd = cmd_buf;
520 pos = cmd_buf;
521 os_strlcpy(pos, ctrl->cookie, _cmd_len);
522 pos += os_strlen(ctrl->cookie);
523 *pos++ = ' ';
524 os_memcpy(pos, cmd, cmd_len);
525 } else
526#endif /* CONFIG_CTRL_IFACE_UDP */
527 {
528 _cmd = cmd;
529 _cmd_len = cmd_len;
530 }
531
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700532 errno = 0;
533 started_at.sec = 0;
534 started_at.usec = 0;
535retry_send:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700536 if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700537 if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
538 {
539 /*
540 * Must be a non-blocking socket... Try for a bit
541 * longer before giving up.
542 */
543 if (started_at.sec == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800544 os_get_reltime(&started_at);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700545 else {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800546 struct os_reltime n;
547 os_get_reltime(&n);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700548 /* Try for a few seconds. */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800549 if (os_reltime_expired(&n, &started_at, 5))
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700550 goto send_err;
551 }
552 os_sleep(1, 0);
553 goto retry_send;
554 }
555 send_err:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700556 os_free(cmd_buf);
557 return -1;
558 }
559 os_free(cmd_buf);
560
561 for (;;) {
562 tv.tv_sec = 10;
563 tv.tv_usec = 0;
564 FD_ZERO(&rfds);
565 FD_SET(ctrl->s, &rfds);
566 res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800567 if (res < 0 && errno == EINTR)
568 continue;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700569 if (res < 0)
570 return res;
571 if (FD_ISSET(ctrl->s, &rfds)) {
572 res = recv(ctrl->s, reply, *reply_len, 0);
573 if (res < 0)
574 return res;
Hai Shalom74f70d42019-02-11 14:42:39 -0800575 if ((res > 0 && reply[0] == '<') ||
576 (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700577 /* This is an unsolicited message from
578 * wpa_supplicant, not the reply to the
579 * request. Use msg_cb to report this to the
580 * caller. */
581 if (msg_cb) {
582 /* Make sure the message is nul
583 * terminated. */
584 if ((size_t) res == *reply_len)
585 res = (*reply_len) - 1;
586 reply[res] = '\0';
587 msg_cb(reply, res);
588 }
589 continue;
590 }
591 *reply_len = res;
592 break;
593 } else {
594 return -2;
595 }
596 }
597 return 0;
598}
599#endif /* CTRL_IFACE_SOCKET */
600
601
602static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
603{
604 char buf[10];
605 int ret;
606 size_t len = 10;
607
608 ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
609 buf, &len, NULL);
610 if (ret < 0)
611 return ret;
612 if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
613 return 0;
614 return -1;
615}
616
617
618int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
619{
620 return wpa_ctrl_attach_helper(ctrl, 1);
621}
622
623
624int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
625{
626 return wpa_ctrl_attach_helper(ctrl, 0);
627}
628
629
630#ifdef CTRL_IFACE_SOCKET
631
632int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
633{
634 int res;
635
636 res = recv(ctrl->s, reply, *reply_len, 0);
637 if (res < 0)
638 return res;
639 *reply_len = res;
640 return 0;
641}
642
643
644int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
645{
646 struct timeval tv;
647 fd_set rfds;
648 tv.tv_sec = 0;
649 tv.tv_usec = 0;
650 FD_ZERO(&rfds);
651 FD_SET(ctrl->s, &rfds);
652 select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
653 return FD_ISSET(ctrl->s, &rfds);
654}
655
656
657int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
658{
659 return ctrl->s;
660}
661
662#endif /* CTRL_IFACE_SOCKET */
663
664
665#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
666
667#ifndef WPA_SUPPLICANT_NAMED_PIPE
668#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
669#endif
670#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
671
672struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
673{
674 struct wpa_ctrl *ctrl;
675 DWORD mode;
676 TCHAR name[256];
677 int i, ret;
678
679 ctrl = os_malloc(sizeof(*ctrl));
680 if (ctrl == NULL)
681 return NULL;
682 os_memset(ctrl, 0, sizeof(*ctrl));
683
684#ifdef UNICODE
685 if (ctrl_path == NULL)
686 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
687 else
688 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
689 ctrl_path);
690#else /* UNICODE */
691 if (ctrl_path == NULL)
692 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
693 else
694 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
695 ctrl_path);
696#endif /* UNICODE */
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800697 if (os_snprintf_error(256, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700698 os_free(ctrl);
699 return NULL;
700 }
701
702 for (i = 0; i < 10; i++) {
703 ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
704 NULL, OPEN_EXISTING, 0, NULL);
705 /*
706 * Current named pipe server side in wpa_supplicant is
707 * re-opening the pipe for new clients only after the previous
708 * one is taken into use. This leaves a small window for race
709 * conditions when two connections are being opened at almost
710 * the same time. Retry if that was the case.
711 */
712 if (ctrl->pipe != INVALID_HANDLE_VALUE ||
713 GetLastError() != ERROR_PIPE_BUSY)
714 break;
715 WaitNamedPipe(name, 1000);
716 }
717 if (ctrl->pipe == INVALID_HANDLE_VALUE) {
718 os_free(ctrl);
719 return NULL;
720 }
721
722 mode = PIPE_READMODE_MESSAGE;
723 if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
724 CloseHandle(ctrl->pipe);
725 os_free(ctrl);
726 return NULL;
727 }
728
729 return ctrl;
730}
731
732
733void wpa_ctrl_close(struct wpa_ctrl *ctrl)
734{
735 CloseHandle(ctrl->pipe);
736 os_free(ctrl);
737}
738
739
740int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
741 char *reply, size_t *reply_len,
742 void (*msg_cb)(char *msg, size_t len))
743{
744 DWORD written;
745 DWORD readlen = *reply_len;
746
747 if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
748 return -1;
749
750 if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
751 return -1;
752 *reply_len = readlen;
753
754 return 0;
755}
756
757
758int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
759{
760 DWORD len = *reply_len;
761 if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
762 return -1;
763 *reply_len = len;
764 return 0;
765}
766
767
768int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
769{
770 DWORD left;
771
772 if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
773 return -1;
774 return left ? 1 : 0;
775}
776
777
778int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
779{
780 return -1;
781}
782
783#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
784
785#endif /* CONFIG_CTRL_IFACE */