Line data Source code
1 : /*
2 : * WPA Supplicant / UNIX domain socket -based control interface
3 : * Copyright (c) 2004-2014, 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 : #include <sys/un.h>
11 : #include <sys/stat.h>
12 : #include <grp.h>
13 : #include <stddef.h>
14 : #include <unistd.h>
15 : #include <fcntl.h>
16 : #ifdef __linux__
17 : #include <sys/ioctl.h>
18 : #include <linux/sockios.h>
19 : #endif /* __linux__ */
20 : #ifdef ANDROID
21 : #include <cutils/sockets.h>
22 : #endif /* ANDROID */
23 :
24 : #include "utils/common.h"
25 : #include "utils/eloop.h"
26 : #include "utils/list.h"
27 : #include "eapol_supp/eapol_supp_sm.h"
28 : #include "config.h"
29 : #include "wpa_supplicant_i.h"
30 : #include "ctrl_iface.h"
31 :
32 : /* Per-interface ctrl_iface */
33 :
34 : /**
35 : * struct wpa_ctrl_dst - Internal data structure of control interface monitors
36 : *
37 : * This structure is used to store information about registered control
38 : * interface monitors into struct wpa_supplicant. This data is private to
39 : * ctrl_iface_unix.c and should not be touched directly from other files.
40 : */
41 : struct wpa_ctrl_dst {
42 : struct dl_list list;
43 : struct sockaddr_un addr;
44 : socklen_t addrlen;
45 : int debug_level;
46 : int errors;
47 : };
48 :
49 :
50 : struct ctrl_iface_priv {
51 : struct wpa_supplicant *wpa_s;
52 : int sock;
53 : struct dl_list ctrl_dst;
54 : int android_control_socket;
55 : };
56 :
57 :
58 : struct ctrl_iface_global_priv {
59 : struct wpa_global *global;
60 : int sock;
61 : struct dl_list ctrl_dst;
62 : int android_control_socket;
63 : };
64 :
65 :
66 : static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
67 : const char *ifname, int sock,
68 : struct dl_list *ctrl_dst,
69 : int level, const char *buf,
70 : size_t len,
71 : struct ctrl_iface_priv *priv,
72 : struct ctrl_iface_global_priv *gp);
73 : static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
74 : struct ctrl_iface_priv *priv);
75 : static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
76 : struct ctrl_iface_global_priv *priv);
77 :
78 :
79 292735 : static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
80 : size_t len)
81 : {
82 : #ifdef __linux__
83 : socklen_t optlen;
84 : int sndbuf, outq;
85 292735 : int level = MSG_MSGDUMP;
86 :
87 292735 : if (len >= 5 && os_strncmp(buf, "PONG\n", 5) == 0)
88 14829 : level = MSG_EXCESSIVE;
89 :
90 292735 : optlen = sizeof(sndbuf);
91 292735 : sndbuf = 0;
92 292735 : if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
93 0 : sndbuf = -1;
94 :
95 292735 : if (ioctl(sock, SIOCOUTQ, &outq) < 0)
96 0 : outq = -1;
97 :
98 292735 : wpa_printf(level,
99 : "CTRL-DEBUG: %s: sock=%d sndbuf=%d outq=%d send_len=%d",
100 : title, sock, sndbuf, outq, (int) len);
101 : #endif /* __linux__ */
102 292735 : }
103 :
104 :
105 4523 : static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
106 : struct sockaddr_un *from,
107 : socklen_t fromlen, int global)
108 : {
109 : struct wpa_ctrl_dst *dst;
110 : char addr_txt[200];
111 :
112 4523 : dst = os_zalloc(sizeof(*dst));
113 4523 : if (dst == NULL)
114 0 : return -1;
115 4523 : os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
116 4523 : dst->addrlen = fromlen;
117 4523 : dst->debug_level = MSG_INFO;
118 4523 : dl_list_add(ctrl_dst, &dst->list);
119 9046 : printf_encode(addr_txt, sizeof(addr_txt),
120 4523 : (u8 *) from->sun_path,
121 : fromlen - offsetof(struct sockaddr_un, sun_path));
122 4523 : wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s",
123 : global ? "global " : "", addr_txt);
124 4523 : return 0;
125 : }
126 :
127 :
128 4519 : static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
129 : struct sockaddr_un *from,
130 : socklen_t fromlen)
131 : {
132 : struct wpa_ctrl_dst *dst;
133 :
134 4652 : dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
135 9271 : if (fromlen == dst->addrlen &&
136 4632 : os_memcmp(from->sun_path, dst->addr.sun_path,
137 : fromlen - offsetof(struct sockaddr_un, sun_path))
138 : == 0) {
139 : char addr_txt[200];
140 9012 : printf_encode(addr_txt, sizeof(addr_txt),
141 4506 : (u8 *) from->sun_path,
142 : fromlen -
143 : offsetof(struct sockaddr_un, sun_path));
144 4506 : wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s",
145 : addr_txt);
146 4506 : dl_list_del(&dst->list);
147 4506 : os_free(dst);
148 4506 : return 0;
149 : }
150 : }
151 13 : return -1;
152 : }
153 :
154 :
155 3 : static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
156 : struct sockaddr_un *from,
157 : socklen_t fromlen,
158 : char *level)
159 : {
160 : struct wpa_ctrl_dst *dst;
161 :
162 3 : wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
163 :
164 4 : dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
165 6 : if (fromlen == dst->addrlen &&
166 3 : os_memcmp(from->sun_path, dst->addr.sun_path,
167 : fromlen - offsetof(struct sockaddr_un, sun_path))
168 : == 0) {
169 : char addr_txt[200];
170 2 : dst->debug_level = atoi(level);
171 4 : printf_encode(addr_txt, sizeof(addr_txt),
172 2 : (u8 *) from->sun_path, fromlen -
173 : offsetof(struct sockaddr_un, sun_path));
174 2 : wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s",
175 : dst->debug_level, addr_txt);
176 2 : return 0;
177 : }
178 : }
179 :
180 1 : return -1;
181 : }
182 :
183 :
184 74157 : static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
185 : void *sock_ctx)
186 : {
187 74157 : struct wpa_supplicant *wpa_s = eloop_ctx;
188 74157 : struct ctrl_iface_priv *priv = sock_ctx;
189 : char buf[4096];
190 : int res;
191 : struct sockaddr_un from;
192 74157 : socklen_t fromlen = sizeof(from);
193 74157 : char *reply = NULL, *reply_buf = NULL;
194 74157 : size_t reply_len = 0;
195 74157 : int new_attached = 0;
196 :
197 74157 : res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
198 : (struct sockaddr *) &from, &fromlen);
199 74157 : if (res < 0) {
200 0 : wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
201 0 : strerror(errno));
202 74157 : return;
203 : }
204 74157 : buf[res] = '\0';
205 :
206 74157 : if (os_strcmp(buf, "ATTACH") == 0) {
207 888 : if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
208 : fromlen, 0))
209 0 : reply_len = 1;
210 : else {
211 888 : new_attached = 1;
212 888 : reply_len = 2;
213 : }
214 73269 : } else if (os_strcmp(buf, "DETACH") == 0) {
215 854 : if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
216 : fromlen))
217 5 : reply_len = 1;
218 : else
219 849 : reply_len = 2;
220 72415 : } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
221 3 : if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
222 : buf + 6))
223 1 : reply_len = 1;
224 : else
225 2 : reply_len = 2;
226 : } else {
227 72412 : reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
228 : &reply_len);
229 72412 : reply = reply_buf;
230 :
231 : /*
232 : * There could be some password/key material in the command, so
233 : * clear the buffer explicitly now that it is not needed
234 : * anymore.
235 : */
236 72412 : os_memset(buf, 0, res);
237 : }
238 :
239 74157 : if (!reply && reply_len == 1) {
240 6 : reply = "FAIL\n";
241 6 : reply_len = 5;
242 74151 : } else if (!reply && reply_len == 2) {
243 1739 : reply = "OK\n";
244 1739 : reply_len = 3;
245 : }
246 :
247 74157 : if (reply) {
248 74157 : wpas_ctrl_sock_debug("ctrl_sock-sendto", sock, reply,
249 : reply_len);
250 74157 : if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
251 : fromlen) < 0) {
252 42 : int _errno = errno;
253 42 : wpa_dbg(wpa_s, MSG_DEBUG,
254 : "ctrl_iface sendto failed: %d - %s",
255 : _errno, strerror(_errno));
256 42 : if (_errno == ENOBUFS || _errno == EAGAIN) {
257 : /*
258 : * The socket send buffer could be full. This
259 : * may happen if client programs are not
260 : * receiving their pending messages. Close and
261 : * reopen the socket as a workaround to avoid
262 : * getting stuck being unable to send any new
263 : * responses.
264 : */
265 0 : sock = wpas_ctrl_iface_reinit(wpa_s, priv);
266 0 : if (sock < 0) {
267 0 : wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
268 : }
269 : }
270 42 : if (new_attached) {
271 0 : wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
272 0 : new_attached = 0;
273 0 : wpa_supplicant_ctrl_iface_detach(
274 : &priv->ctrl_dst, &from, fromlen);
275 : }
276 : }
277 : }
278 74157 : os_free(reply_buf);
279 :
280 74157 : if (new_attached)
281 888 : eapol_sm_notify_ctrl_attached(wpa_s->eapol);
282 : }
283 :
284 :
285 1080 : static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
286 : {
287 : char *buf;
288 : size_t len;
289 1080 : char *pbuf, *dir = NULL;
290 : int res;
291 :
292 1080 : if (wpa_s->conf->ctrl_interface == NULL)
293 0 : return NULL;
294 :
295 1080 : pbuf = os_strdup(wpa_s->conf->ctrl_interface);
296 1080 : if (pbuf == NULL)
297 0 : return NULL;
298 1080 : if (os_strncmp(pbuf, "DIR=", 4) == 0) {
299 : char *gid_str;
300 1080 : dir = pbuf + 4;
301 1080 : gid_str = os_strstr(dir, " GROUP=");
302 1080 : if (gid_str)
303 1052 : *gid_str = '\0';
304 : } else
305 0 : dir = pbuf;
306 :
307 1080 : len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
308 1080 : buf = os_malloc(len);
309 1080 : if (buf == NULL) {
310 0 : os_free(pbuf);
311 0 : return NULL;
312 : }
313 :
314 1080 : res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
315 1080 : if (os_snprintf_error(len, res)) {
316 0 : os_free(pbuf);
317 0 : os_free(buf);
318 0 : return NULL;
319 : }
320 : #ifdef __CYGWIN__
321 : {
322 : /* Windows/WinPcap uses interface names that are not suitable
323 : * as a file name - convert invalid chars to underscores */
324 : char *pos = buf;
325 : while (*pos) {
326 : if (*pos == '\\')
327 : *pos = '_';
328 : pos++;
329 : }
330 : }
331 : #endif /* __CYGWIN__ */
332 1080 : os_free(pbuf);
333 1080 : return buf;
334 : }
335 :
336 :
337 1115563 : static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
338 : enum wpa_msg_type type,
339 : const char *txt, size_t len)
340 : {
341 1115563 : struct wpa_supplicant *wpa_s = ctx;
342 :
343 1115563 : if (wpa_s == NULL)
344 243 : return;
345 :
346 1115320 : if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
347 1115274 : struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
348 1115274 : if (!dl_list_empty(&priv->ctrl_dst)) {
349 1113759 : wpa_supplicant_ctrl_iface_send(
350 : wpa_s,
351 : type != WPA_MSG_PER_INTERFACE ?
352 : NULL : wpa_s->ifname,
353 : priv->sock, &priv->ctrl_dst, level, txt, len,
354 : NULL, priv);
355 : }
356 : }
357 :
358 1115320 : if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL)
359 5214 : return;
360 2220212 : wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
361 1110106 : &wpa_s->ctrl_iface->ctrl_dst,
362 : level, txt, len, wpa_s->ctrl_iface,
363 : NULL);
364 : }
365 :
366 :
367 540 : static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
368 : struct ctrl_iface_priv *priv)
369 : {
370 : struct sockaddr_un addr;
371 540 : char *fname = NULL;
372 540 : gid_t gid = 0;
373 540 : int gid_set = 0;
374 540 : char *buf, *dir = NULL, *gid_str = NULL;
375 : struct group *grp;
376 : char *endp;
377 : int flags;
378 :
379 540 : buf = os_strdup(wpa_s->conf->ctrl_interface);
380 540 : if (buf == NULL)
381 0 : goto fail;
382 : #ifdef ANDROID
383 : os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
384 : wpa_s->conf->ctrl_interface);
385 : priv->sock = android_get_control_socket(addr.sun_path);
386 : if (priv->sock >= 0) {
387 : priv->android_control_socket = 1;
388 : goto havesock;
389 : }
390 : #endif /* ANDROID */
391 540 : if (os_strncmp(buf, "DIR=", 4) == 0) {
392 540 : dir = buf + 4;
393 540 : gid_str = os_strstr(dir, " GROUP=");
394 540 : if (gid_str) {
395 526 : *gid_str = '\0';
396 526 : gid_str += 7;
397 : }
398 : } else {
399 0 : dir = buf;
400 0 : gid_str = wpa_s->conf->ctrl_interface_group;
401 : }
402 :
403 540 : if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
404 534 : if (errno == EEXIST) {
405 534 : wpa_printf(MSG_DEBUG, "Using existing control "
406 : "interface directory.");
407 : } else {
408 0 : wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s",
409 0 : dir, strerror(errno));
410 0 : goto fail;
411 : }
412 : }
413 :
414 : #ifdef ANDROID
415 : /*
416 : * wpa_supplicant is started from /init.*.rc on Android and that seems
417 : * to be using umask 0077 which would leave the control interface
418 : * directory without group access. This breaks things since Wi-Fi
419 : * framework assumes that this directory can be accessed by other
420 : * applications in the wifi group. Fix this by adding group access even
421 : * if umask value would prevent this.
422 : */
423 : if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
424 : wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
425 : strerror(errno));
426 : /* Try to continue anyway */
427 : }
428 : #endif /* ANDROID */
429 :
430 540 : if (gid_str) {
431 526 : grp = getgrnam(gid_str);
432 526 : if (grp) {
433 526 : gid = grp->gr_gid;
434 526 : gid_set = 1;
435 526 : wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
436 : " (from group name '%s')",
437 : (int) gid, gid_str);
438 : } else {
439 : /* Group name not found - try to parse this as gid */
440 0 : gid = strtol(gid_str, &endp, 10);
441 0 : if (*gid_str == '\0' || *endp != '\0') {
442 0 : wpa_printf(MSG_ERROR, "CTRL: Invalid group "
443 : "'%s'", gid_str);
444 0 : goto fail;
445 : }
446 0 : gid_set = 1;
447 0 : wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
448 : (int) gid);
449 : }
450 : }
451 :
452 540 : if (gid_set && chown(dir, -1, gid) < 0) {
453 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
454 0 : dir, (int) gid, strerror(errno));
455 0 : goto fail;
456 : }
457 :
458 : /* Make sure the group can enter and read the directory */
459 1066 : if (gid_set &&
460 526 : chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) {
461 0 : wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s",
462 0 : strerror(errno));
463 0 : goto fail;
464 : }
465 :
466 540 : if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
467 : sizeof(addr.sun_path)) {
468 0 : wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded");
469 0 : goto fail;
470 : }
471 :
472 540 : priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
473 540 : if (priv->sock < 0) {
474 0 : wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
475 0 : goto fail;
476 : }
477 :
478 540 : os_memset(&addr, 0, sizeof(addr));
479 : #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
480 : addr.sun_len = sizeof(addr);
481 : #endif /* __FreeBSD__ */
482 540 : addr.sun_family = AF_UNIX;
483 540 : fname = wpa_supplicant_ctrl_iface_path(wpa_s);
484 540 : if (fname == NULL)
485 0 : goto fail;
486 540 : os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
487 540 : if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
488 0 : wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
489 0 : strerror(errno));
490 0 : if (connect(priv->sock, (struct sockaddr *) &addr,
491 : sizeof(addr)) < 0) {
492 0 : wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
493 : " allow connections - assuming it was left"
494 : "over from forced program termination");
495 0 : if (unlink(fname) < 0) {
496 0 : wpa_printf(MSG_ERROR,
497 : "Could not unlink existing ctrl_iface socket '%s': %s",
498 0 : fname, strerror(errno));
499 0 : goto fail;
500 : }
501 0 : if (bind(priv->sock, (struct sockaddr *) &addr,
502 : sizeof(addr)) < 0) {
503 0 : wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s",
504 0 : strerror(errno));
505 0 : goto fail;
506 : }
507 0 : wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
508 : "ctrl_iface socket '%s'", fname);
509 : } else {
510 0 : wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
511 : "be in use - cannot override it");
512 0 : wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
513 : "not used anymore", fname);
514 0 : os_free(fname);
515 0 : fname = NULL;
516 0 : goto fail;
517 : }
518 : }
519 :
520 540 : if (gid_set && chown(fname, -1, gid) < 0) {
521 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
522 0 : fname, (int) gid, strerror(errno));
523 0 : goto fail;
524 : }
525 :
526 540 : if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
527 0 : wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s",
528 0 : fname, strerror(errno));
529 0 : goto fail;
530 : }
531 540 : os_free(fname);
532 :
533 : #ifdef ANDROID
534 : havesock:
535 : #endif /* ANDROID */
536 :
537 : /*
538 : * Make socket non-blocking so that we don't hang forever if
539 : * target dies unexpectedly.
540 : */
541 540 : flags = fcntl(priv->sock, F_GETFL);
542 540 : if (flags >= 0) {
543 540 : flags |= O_NONBLOCK;
544 540 : if (fcntl(priv->sock, F_SETFL, flags) < 0) {
545 0 : wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
546 0 : strerror(errno));
547 : /* Not fatal, continue on.*/
548 : }
549 : }
550 :
551 540 : eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
552 : wpa_s, priv);
553 540 : wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
554 :
555 540 : os_free(buf);
556 540 : return 0;
557 :
558 : fail:
559 0 : if (priv->sock >= 0) {
560 0 : close(priv->sock);
561 0 : priv->sock = -1;
562 : }
563 0 : if (fname) {
564 0 : unlink(fname);
565 0 : os_free(fname);
566 : }
567 0 : os_free(buf);
568 0 : return -1;
569 : }
570 :
571 :
572 : struct ctrl_iface_priv *
573 577 : wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
574 : {
575 : struct ctrl_iface_priv *priv;
576 :
577 577 : priv = os_zalloc(sizeof(*priv));
578 577 : if (priv == NULL)
579 1 : return NULL;
580 576 : dl_list_init(&priv->ctrl_dst);
581 576 : priv->wpa_s = wpa_s;
582 576 : priv->sock = -1;
583 :
584 576 : if (wpa_s->conf->ctrl_interface == NULL)
585 36 : return priv;
586 :
587 : #ifdef ANDROID
588 : if (wpa_s->global->params.ctrl_interface) {
589 : int same = 0;
590 :
591 : if (wpa_s->global->params.ctrl_interface[0] == '/') {
592 : if (os_strcmp(wpa_s->global->params.ctrl_interface,
593 : wpa_s->conf->ctrl_interface) == 0)
594 : same = 1;
595 : } else if (os_strncmp(wpa_s->global->params.ctrl_interface,
596 : "@android:", 9) == 0 ||
597 : os_strncmp(wpa_s->global->params.ctrl_interface,
598 : "@abstract:", 10) == 0) {
599 : char *pos;
600 :
601 : /*
602 : * Currently, Android uses @android:wpa_* as the naming
603 : * convention for the global ctrl interface. This logic
604 : * needs to be revisited if the above naming convention
605 : * is modified.
606 : */
607 : pos = os_strchr(wpa_s->global->params.ctrl_interface,
608 : '_');
609 : if (pos &&
610 : os_strcmp(pos + 1,
611 : wpa_s->conf->ctrl_interface) == 0)
612 : same = 1;
613 : }
614 :
615 : if (same) {
616 : /*
617 : * The invalid configuration combination might be
618 : * possible to hit in an Android OTA upgrade case, so
619 : * instead of refusing to start the wpa_supplicant
620 : * process, do not open the per-interface ctrl_iface
621 : * and continue with the global control interface that
622 : * was set from the command line since the Wi-Fi
623 : * framework will use it for operations.
624 : */
625 : wpa_printf(MSG_ERROR,
626 : "global ctrl interface %s matches ctrl interface %s - do not open per-interface ctrl interface",
627 : wpa_s->global->params.ctrl_interface,
628 : wpa_s->conf->ctrl_interface);
629 : return priv;
630 : }
631 : }
632 : #endif /* ANDROID */
633 :
634 540 : if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
635 0 : os_free(priv);
636 0 : return NULL;
637 : }
638 :
639 540 : return priv;
640 : }
641 :
642 :
643 0 : static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
644 : struct ctrl_iface_priv *priv)
645 : {
646 : int res;
647 :
648 0 : if (priv->sock <= 0)
649 0 : return -1;
650 :
651 : /*
652 : * On Android, the control socket being used may be the socket
653 : * that is created when wpa_supplicant is started as a /init.*.rc
654 : * service. Such a socket is maintained as a key-value pair in
655 : * Android's environment. Closing this control socket would leave us
656 : * in a bad state with an invalid socket descriptor.
657 : */
658 0 : if (priv->android_control_socket)
659 0 : return priv->sock;
660 :
661 0 : eloop_unregister_read_sock(priv->sock);
662 0 : close(priv->sock);
663 0 : priv->sock = -1;
664 0 : res = wpas_ctrl_iface_open_sock(wpa_s, priv);
665 0 : if (res < 0)
666 0 : return -1;
667 0 : return priv->sock;
668 : }
669 :
670 :
671 576 : void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
672 : {
673 : struct wpa_ctrl_dst *dst, *prev;
674 :
675 576 : if (priv->sock > -1) {
676 : char *fname;
677 540 : char *buf, *dir = NULL;
678 540 : eloop_unregister_read_sock(priv->sock);
679 540 : if (!dl_list_empty(&priv->ctrl_dst)) {
680 : /*
681 : * Wait before closing the control socket if
682 : * there are any attached monitors in order to allow
683 : * them to receive any pending messages.
684 : */
685 16 : wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
686 : "monitors to receive messages");
687 16 : os_sleep(0, 100000);
688 : }
689 540 : close(priv->sock);
690 540 : priv->sock = -1;
691 540 : fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
692 540 : if (fname) {
693 540 : unlink(fname);
694 540 : os_free(fname);
695 : }
696 :
697 540 : if (priv->wpa_s->conf->ctrl_interface == NULL)
698 0 : goto free_dst;
699 540 : buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
700 540 : if (buf == NULL)
701 0 : goto free_dst;
702 540 : if (os_strncmp(buf, "DIR=", 4) == 0) {
703 : char *gid_str;
704 540 : dir = buf + 4;
705 540 : gid_str = os_strstr(dir, " GROUP=");
706 540 : if (gid_str)
707 526 : *gid_str = '\0';
708 : } else
709 0 : dir = buf;
710 :
711 540 : if (rmdir(dir) < 0) {
712 534 : if (errno == ENOTEMPTY) {
713 532 : wpa_printf(MSG_DEBUG, "Control interface "
714 : "directory not empty - leaving it "
715 : "behind");
716 : } else {
717 2 : wpa_printf(MSG_ERROR,
718 : "rmdir[ctrl_interface=%s]: %s",
719 2 : dir, strerror(errno));
720 : }
721 : }
722 540 : os_free(buf);
723 : }
724 :
725 : free_dst:
726 593 : dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
727 : list)
728 17 : os_free(dst);
729 576 : os_free(priv);
730 576 : }
731 :
732 :
733 : /**
734 : * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
735 : * @ifname: Interface name for global control socket or %NULL
736 : * @sock: Local socket fd
737 : * @ctrl_dst: List of attached listeners
738 : * @level: Priority level of the message
739 : * @buf: Message data
740 : * @len: Message length
741 : *
742 : * Send a packet to all monitor programs attached to the control interface.
743 : */
744 2223865 : static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
745 : const char *ifname, int sock,
746 : struct dl_list *ctrl_dst,
747 : int level, const char *buf,
748 : size_t len,
749 : struct ctrl_iface_priv *priv,
750 : struct ctrl_iface_global_priv *gp)
751 : {
752 : struct wpa_ctrl_dst *dst, *next;
753 : char levelstr[10];
754 : int idx, res;
755 : struct msghdr msg;
756 : struct iovec io[5];
757 :
758 2223865 : if (sock < 0 || dl_list_empty(ctrl_dst))
759 465280 : return;
760 :
761 1991225 : res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
762 1991225 : if (os_snprintf_error(sizeof(levelstr), res))
763 0 : return;
764 1991225 : idx = 0;
765 1991225 : if (ifname) {
766 865291 : io[idx].iov_base = "IFNAME=";
767 865291 : io[idx].iov_len = 7;
768 865291 : idx++;
769 865291 : io[idx].iov_base = (char *) ifname;
770 865291 : io[idx].iov_len = os_strlen(ifname);
771 865291 : idx++;
772 865291 : io[idx].iov_base = " ";
773 865291 : io[idx].iov_len = 1;
774 865291 : idx++;
775 : }
776 1991225 : io[idx].iov_base = levelstr;
777 1991225 : io[idx].iov_len = os_strlen(levelstr);
778 1991225 : idx++;
779 1991225 : io[idx].iov_base = (char *) buf;
780 1991225 : io[idx].iov_len = len;
781 1991225 : idx++;
782 1991225 : os_memset(&msg, 0, sizeof(msg));
783 1991225 : msg.msg_iov = io;
784 1991225 : msg.msg_iovlen = idx;
785 :
786 4043818 : dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
787 : int _errno;
788 : char addr_txt[200];
789 :
790 2052593 : if (level < dst->debug_level)
791 3952794 : continue;
792 :
793 304722 : printf_encode(addr_txt, sizeof(addr_txt),
794 304722 : (u8 *) dst->addr.sun_path, dst->addrlen -
795 : offsetof(struct sockaddr_un, sun_path));
796 152361 : msg.msg_name = (void *) &dst->addr;
797 152361 : msg.msg_namelen = dst->addrlen;
798 152361 : wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len);
799 152361 : if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
800 152330 : wpa_printf(MSG_MSGDUMP,
801 : "CTRL_IFACE monitor sent successfully to %s",
802 : addr_txt);
803 152330 : dst->errors = 0;
804 152330 : continue;
805 : }
806 :
807 31 : _errno = errno;
808 62 : wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s",
809 62 : addr_txt, errno, strerror(errno));
810 31 : dst->errors++;
811 :
812 31 : if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
813 31 : wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages",
814 : addr_txt);
815 31 : wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
816 : dst->addrlen);
817 : }
818 :
819 31 : if (_errno == ENOBUFS || _errno == EAGAIN) {
820 : /*
821 : * The socket send buffer could be full. This may happen
822 : * if client programs are not receiving their pending
823 : * messages. Close and reopen the socket as a workaround
824 : * to avoid getting stuck being unable to send any new
825 : * responses.
826 : */
827 0 : if (priv)
828 0 : sock = wpas_ctrl_iface_reinit(wpa_s, priv);
829 0 : else if (gp)
830 0 : sock = wpas_ctrl_iface_global_reinit(
831 : wpa_s->global, gp);
832 : else
833 0 : break;
834 0 : if (sock < 0) {
835 0 : wpa_dbg(wpa_s, MSG_DEBUG,
836 : "Failed to reinitialize ctrl_iface socket");
837 0 : break;
838 : }
839 : }
840 : }
841 : }
842 :
843 :
844 1 : void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
845 : {
846 : char buf[256];
847 : int res;
848 : struct sockaddr_un from;
849 1 : socklen_t fromlen = sizeof(from);
850 :
851 : for (;;) {
852 1 : wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
853 1 : "attach", priv->wpa_s->ifname);
854 1 : eloop_wait_for_read_sock(priv->sock);
855 :
856 1 : res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
857 : (struct sockaddr *) &from, &fromlen);
858 1 : if (res < 0) {
859 0 : wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
860 0 : strerror(errno));
861 0 : continue;
862 : }
863 1 : buf[res] = '\0';
864 :
865 1 : if (os_strcmp(buf, "ATTACH") == 0) {
866 : /* handle ATTACH signal of first monitor interface */
867 1 : if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
868 : &from, fromlen,
869 : 0)) {
870 1 : if (sendto(priv->sock, "OK\n", 3, 0,
871 : (struct sockaddr *) &from, fromlen) <
872 : 0) {
873 0 : wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
874 0 : strerror(errno));
875 : }
876 : /* OK to continue */
877 2 : return;
878 : } else {
879 0 : if (sendto(priv->sock, "FAIL\n", 5, 0,
880 : (struct sockaddr *) &from, fromlen) <
881 : 0) {
882 0 : wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
883 0 : strerror(errno));
884 : }
885 : }
886 : } else {
887 : /* return FAIL for all other signals */
888 0 : if (sendto(priv->sock, "FAIL\n", 5, 0,
889 : (struct sockaddr *) &from, fromlen) < 0) {
890 0 : wpa_printf(MSG_DEBUG,
891 : "ctrl_iface sendto failed: %s",
892 0 : strerror(errno));
893 : }
894 : }
895 0 : }
896 : }
897 :
898 :
899 : /* Global ctrl_iface */
900 :
901 66217 : static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
902 : void *sock_ctx)
903 : {
904 66217 : struct wpa_global *global = eloop_ctx;
905 66217 : struct ctrl_iface_global_priv *priv = sock_ctx;
906 : char buf[4096];
907 : int res;
908 : struct sockaddr_un from;
909 66217 : socklen_t fromlen = sizeof(from);
910 66217 : char *reply = NULL, *reply_buf = NULL;
911 : size_t reply_len;
912 :
913 66217 : res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
914 : (struct sockaddr *) &from, &fromlen);
915 66217 : if (res < 0) {
916 0 : wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
917 0 : strerror(errno));
918 66217 : return;
919 : }
920 66217 : buf[res] = '\0';
921 :
922 66217 : if (os_strcmp(buf, "ATTACH") == 0) {
923 3634 : if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
924 : fromlen, 1))
925 0 : reply_len = 1;
926 : else
927 3634 : reply_len = 2;
928 62583 : } else if (os_strcmp(buf, "DETACH") == 0) {
929 3634 : if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
930 : fromlen))
931 8 : reply_len = 1;
932 : else
933 3626 : reply_len = 2;
934 : } else {
935 58949 : reply_buf = wpa_supplicant_global_ctrl_iface_process(
936 : global, buf, &reply_len);
937 58949 : reply = reply_buf;
938 :
939 : /*
940 : * There could be some password/key material in the command, so
941 : * clear the buffer explicitly now that it is not needed
942 : * anymore.
943 : */
944 58949 : os_memset(buf, 0, res);
945 : }
946 :
947 66217 : if (!reply && reply_len == 1) {
948 10 : reply = "FAIL\n";
949 10 : reply_len = 5;
950 66207 : } else if (!reply && reply_len == 2) {
951 7260 : reply = "OK\n";
952 7260 : reply_len = 3;
953 : }
954 :
955 66217 : if (reply) {
956 66217 : wpas_ctrl_sock_debug("global_ctrl_sock-sendto",
957 : sock, reply, reply_len);
958 66217 : if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
959 : fromlen) < 0) {
960 65 : wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
961 65 : strerror(errno));
962 : }
963 : }
964 66217 : os_free(reply_buf);
965 : }
966 :
967 :
968 35 : static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
969 : struct ctrl_iface_global_priv *priv)
970 : {
971 : struct sockaddr_un addr;
972 35 : const char *ctrl = global->params.ctrl_interface;
973 : int flags;
974 :
975 35 : wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
976 :
977 : #ifdef ANDROID
978 : if (os_strncmp(ctrl, "@android:", 9) == 0) {
979 : priv->sock = android_get_control_socket(ctrl + 9);
980 : if (priv->sock < 0) {
981 : wpa_printf(MSG_ERROR, "Failed to open Android control "
982 : "socket '%s'", ctrl + 9);
983 : goto fail;
984 : }
985 : wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
986 : ctrl + 9);
987 : priv->android_control_socket = 1;
988 : goto havesock;
989 : }
990 :
991 : if (os_strncmp(ctrl, "@abstract:", 10) != 0) {
992 : /*
993 : * Backwards compatibility - try to open an Android control
994 : * socket and if that fails, assume this was a UNIX domain
995 : * socket instead.
996 : */
997 : priv->sock = android_get_control_socket(ctrl);
998 : if (priv->sock >= 0) {
999 : wpa_printf(MSG_DEBUG,
1000 : "Using Android control socket '%s'",
1001 : ctrl);
1002 : priv->android_control_socket = 1;
1003 : goto havesock;
1004 : }
1005 : }
1006 : #endif /* ANDROID */
1007 :
1008 35 : priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
1009 35 : if (priv->sock < 0) {
1010 0 : wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
1011 0 : goto fail;
1012 : }
1013 :
1014 35 : os_memset(&addr, 0, sizeof(addr));
1015 : #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1016 : addr.sun_len = sizeof(addr);
1017 : #endif /* __FreeBSD__ */
1018 35 : addr.sun_family = AF_UNIX;
1019 :
1020 35 : if (os_strncmp(ctrl, "@abstract:", 10) == 0) {
1021 0 : addr.sun_path[0] = '\0';
1022 0 : os_strlcpy(addr.sun_path + 1, ctrl + 10,
1023 : sizeof(addr.sun_path) - 1);
1024 0 : if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
1025 : 0) {
1026 0 : wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
1027 : "bind(PF_UNIX;%s) failed: %s",
1028 0 : ctrl, strerror(errno));
1029 0 : goto fail;
1030 : }
1031 0 : wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
1032 : ctrl + 10);
1033 0 : goto havesock;
1034 : }
1035 :
1036 35 : os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
1037 35 : if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1038 0 : wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s",
1039 0 : ctrl, strerror(errno));
1040 0 : if (connect(priv->sock, (struct sockaddr *) &addr,
1041 : sizeof(addr)) < 0) {
1042 0 : wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1043 : " allow connections - assuming it was left"
1044 : "over from forced program termination");
1045 0 : if (unlink(ctrl) < 0) {
1046 0 : wpa_printf(MSG_ERROR,
1047 : "Could not unlink existing ctrl_iface socket '%s': %s",
1048 0 : ctrl, strerror(errno));
1049 0 : goto fail;
1050 : }
1051 0 : if (bind(priv->sock, (struct sockaddr *) &addr,
1052 : sizeof(addr)) < 0) {
1053 0 : wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s",
1054 0 : ctrl, strerror(errno));
1055 0 : goto fail;
1056 : }
1057 0 : wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1058 : "ctrl_iface socket '%s'",
1059 : ctrl);
1060 : } else {
1061 0 : wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1062 : "be in use - cannot override it");
1063 0 : wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1064 : "not used anymore",
1065 : ctrl);
1066 0 : goto fail;
1067 : }
1068 : }
1069 :
1070 35 : wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl);
1071 :
1072 35 : if (global->params.ctrl_interface_group) {
1073 24 : char *gid_str = global->params.ctrl_interface_group;
1074 24 : gid_t gid = 0;
1075 : struct group *grp;
1076 : char *endp;
1077 :
1078 24 : grp = getgrnam(gid_str);
1079 24 : if (grp) {
1080 24 : gid = grp->gr_gid;
1081 24 : wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
1082 : " (from group name '%s')",
1083 : (int) gid, gid_str);
1084 : } else {
1085 : /* Group name not found - try to parse this as gid */
1086 0 : gid = strtol(gid_str, &endp, 10);
1087 0 : if (*gid_str == '\0' || *endp != '\0') {
1088 0 : wpa_printf(MSG_ERROR, "CTRL: Invalid group "
1089 : "'%s'", gid_str);
1090 0 : goto fail;
1091 : }
1092 0 : wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
1093 : (int) gid);
1094 : }
1095 24 : if (chown(ctrl, -1, gid) < 0) {
1096 0 : wpa_printf(MSG_ERROR,
1097 : "chown[global_ctrl_interface=%s,gid=%d]: %s",
1098 0 : ctrl, (int) gid, strerror(errno));
1099 0 : goto fail;
1100 : }
1101 :
1102 24 : if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
1103 0 : wpa_printf(MSG_ERROR,
1104 : "chmod[global_ctrl_interface=%s]: %s",
1105 0 : ctrl, strerror(errno));
1106 0 : goto fail;
1107 : }
1108 : } else {
1109 11 : if (chmod(ctrl, S_IRWXU) < 0) {
1110 0 : wpa_printf(MSG_DEBUG,
1111 : "chmod[global_ctrl_interface=%s](S_IRWXU): %s",
1112 0 : ctrl, strerror(errno));
1113 : /* continue anyway since group change was not required
1114 : */
1115 : }
1116 : }
1117 :
1118 : havesock:
1119 :
1120 : /*
1121 : * Make socket non-blocking so that we don't hang forever if
1122 : * target dies unexpectedly.
1123 : */
1124 35 : flags = fcntl(priv->sock, F_GETFL);
1125 35 : if (flags >= 0) {
1126 35 : flags |= O_NONBLOCK;
1127 35 : if (fcntl(priv->sock, F_SETFL, flags) < 0) {
1128 0 : wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
1129 0 : strerror(errno));
1130 : /* Not fatal, continue on.*/
1131 : }
1132 : }
1133 :
1134 35 : eloop_register_read_sock(priv->sock,
1135 : wpa_supplicant_global_ctrl_iface_receive,
1136 : global, priv);
1137 :
1138 35 : return 0;
1139 :
1140 : fail:
1141 0 : if (priv->sock >= 0) {
1142 0 : close(priv->sock);
1143 0 : priv->sock = -1;
1144 : }
1145 0 : return -1;
1146 : }
1147 :
1148 :
1149 : struct ctrl_iface_global_priv *
1150 49 : wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
1151 : {
1152 : struct ctrl_iface_global_priv *priv;
1153 :
1154 49 : priv = os_zalloc(sizeof(*priv));
1155 49 : if (priv == NULL)
1156 0 : return NULL;
1157 49 : dl_list_init(&priv->ctrl_dst);
1158 49 : priv->global = global;
1159 49 : priv->sock = -1;
1160 :
1161 49 : if (global->params.ctrl_interface == NULL)
1162 14 : return priv;
1163 :
1164 35 : if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
1165 0 : os_free(priv);
1166 0 : return NULL;
1167 : }
1168 :
1169 35 : wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
1170 :
1171 35 : return priv;
1172 : }
1173 :
1174 :
1175 0 : static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
1176 : struct ctrl_iface_global_priv *priv)
1177 : {
1178 : int res;
1179 :
1180 0 : if (priv->sock <= 0)
1181 0 : return -1;
1182 :
1183 : /*
1184 : * On Android, the control socket being used may be the socket
1185 : * that is created when wpa_supplicant is started as a /init.*.rc
1186 : * service. Such a socket is maintained as a key-value pair in
1187 : * Android's environment. Closing this control socket would leave us
1188 : * in a bad state with an invalid socket descriptor.
1189 : */
1190 0 : if (priv->android_control_socket)
1191 0 : return priv->sock;
1192 :
1193 0 : eloop_unregister_read_sock(priv->sock);
1194 0 : close(priv->sock);
1195 0 : priv->sock = -1;
1196 0 : res = wpas_global_ctrl_iface_open_sock(global, priv);
1197 0 : if (res < 0)
1198 0 : return -1;
1199 0 : return priv->sock;
1200 : }
1201 :
1202 :
1203 : void
1204 49 : wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
1205 : {
1206 : struct wpa_ctrl_dst *dst, *prev;
1207 :
1208 49 : if (priv->sock >= 0) {
1209 35 : eloop_unregister_read_sock(priv->sock);
1210 35 : close(priv->sock);
1211 : }
1212 49 : if (priv->global->params.ctrl_interface)
1213 35 : unlink(priv->global->params.ctrl_interface);
1214 49 : dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
1215 : list)
1216 0 : os_free(dst);
1217 49 : os_free(priv);
1218 49 : }
|