]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * WPA Supplicant / UNIX domain socket -based control interface | |
09e47a07 | 3 | * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> |
6fc6879b JM |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
16 | #include <sys/un.h> | |
17 | #include <sys/stat.h> | |
18 | #include <grp.h> | |
19b9436c | 19 | #include <stddef.h> |
6fc6879b | 20 | |
09e47a07 JM |
21 | #include "utils/common.h" |
22 | #include "utils/eloop.h" | |
23 | #include "utils/list.h" | |
6fc6879b | 24 | #include "eapol_supp/eapol_supp_sm.h" |
09e47a07 | 25 | #include "config.h" |
6fc6879b JM |
26 | #include "wpa_supplicant_i.h" |
27 | #include "ctrl_iface.h" | |
28 | ||
29 | /* Per-interface ctrl_iface */ | |
30 | ||
31 | /** | |
32 | * struct wpa_ctrl_dst - Internal data structure of control interface monitors | |
33 | * | |
34 | * This structure is used to store information about registered control | |
35 | * interface monitors into struct wpa_supplicant. This data is private to | |
36 | * ctrl_iface_unix.c and should not be touched directly from other files. | |
37 | */ | |
38 | struct wpa_ctrl_dst { | |
09e47a07 | 39 | struct dl_list list; |
6fc6879b JM |
40 | struct sockaddr_un addr; |
41 | socklen_t addrlen; | |
42 | int debug_level; | |
43 | int errors; | |
44 | }; | |
45 | ||
46 | ||
47 | struct ctrl_iface_priv { | |
48 | struct wpa_supplicant *wpa_s; | |
49 | int sock; | |
09e47a07 | 50 | struct dl_list ctrl_dst; |
6fc6879b JM |
51 | }; |
52 | ||
53 | ||
54 | static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, | |
55 | int level, const char *buf, | |
56 | size_t len); | |
57 | ||
58 | ||
59 | static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, | |
60 | struct sockaddr_un *from, | |
61 | socklen_t fromlen) | |
62 | { | |
63 | struct wpa_ctrl_dst *dst; | |
64 | ||
65 | dst = os_zalloc(sizeof(*dst)); | |
66 | if (dst == NULL) | |
67 | return -1; | |
68 | os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); | |
69 | dst->addrlen = fromlen; | |
70 | dst->debug_level = MSG_INFO; | |
09e47a07 | 71 | dl_list_add(&priv->ctrl_dst, &dst->list); |
6fc6879b | 72 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", |
19b9436c SL |
73 | (u8 *) from->sun_path, |
74 | fromlen - offsetof(struct sockaddr_un, sun_path)); | |
6fc6879b JM |
75 | return 0; |
76 | } | |
77 | ||
78 | ||
79 | static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, | |
80 | struct sockaddr_un *from, | |
81 | socklen_t fromlen) | |
82 | { | |
09e47a07 | 83 | struct wpa_ctrl_dst *dst; |
6fc6879b | 84 | |
09e47a07 | 85 | dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { |
6fc6879b JM |
86 | if (fromlen == dst->addrlen && |
87 | os_memcmp(from->sun_path, dst->addr.sun_path, | |
19b9436c SL |
88 | fromlen - offsetof(struct sockaddr_un, sun_path)) |
89 | == 0) { | |
09e47a07 | 90 | dl_list_del(&dst->list); |
6fc6879b JM |
91 | os_free(dst); |
92 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", | |
93 | (u8 *) from->sun_path, | |
19b9436c SL |
94 | fromlen - |
95 | offsetof(struct sockaddr_un, sun_path)); | |
6fc6879b JM |
96 | return 0; |
97 | } | |
6fc6879b JM |
98 | } |
99 | return -1; | |
100 | } | |
101 | ||
102 | ||
103 | static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, | |
104 | struct sockaddr_un *from, | |
105 | socklen_t fromlen, | |
106 | char *level) | |
107 | { | |
108 | struct wpa_ctrl_dst *dst; | |
109 | ||
110 | wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); | |
111 | ||
09e47a07 | 112 | dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { |
6fc6879b JM |
113 | if (fromlen == dst->addrlen && |
114 | os_memcmp(from->sun_path, dst->addr.sun_path, | |
19b9436c SL |
115 | fromlen - offsetof(struct sockaddr_un, sun_path)) |
116 | == 0) { | |
6fc6879b JM |
117 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " |
118 | "level", (u8 *) from->sun_path, | |
19b9436c SL |
119 | fromlen - |
120 | offsetof(struct sockaddr_un, sun_path)); | |
6fc6879b JM |
121 | dst->debug_level = atoi(level); |
122 | return 0; | |
123 | } | |
6fc6879b JM |
124 | } |
125 | ||
126 | return -1; | |
127 | } | |
128 | ||
129 | ||
130 | static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, | |
131 | void *sock_ctx) | |
132 | { | |
133 | struct wpa_supplicant *wpa_s = eloop_ctx; | |
134 | struct ctrl_iface_priv *priv = sock_ctx; | |
b563b388 | 135 | char buf[4096]; |
6fc6879b JM |
136 | int res; |
137 | struct sockaddr_un from; | |
138 | socklen_t fromlen = sizeof(from); | |
139 | char *reply = NULL; | |
140 | size_t reply_len = 0; | |
141 | int new_attached = 0; | |
142 | ||
143 | res = recvfrom(sock, buf, sizeof(buf) - 1, 0, | |
144 | (struct sockaddr *) &from, &fromlen); | |
145 | if (res < 0) { | |
146 | perror("recvfrom(ctrl_iface)"); | |
147 | return; | |
148 | } | |
149 | buf[res] = '\0'; | |
150 | ||
151 | if (os_strcmp(buf, "ATTACH") == 0) { | |
152 | if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) | |
153 | reply_len = 1; | |
154 | else { | |
155 | new_attached = 1; | |
156 | reply_len = 2; | |
157 | } | |
158 | } else if (os_strcmp(buf, "DETACH") == 0) { | |
159 | if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) | |
160 | reply_len = 1; | |
161 | else | |
162 | reply_len = 2; | |
163 | } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { | |
164 | if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, | |
165 | buf + 6)) | |
166 | reply_len = 1; | |
167 | else | |
168 | reply_len = 2; | |
169 | } else { | |
170 | reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, | |
171 | &reply_len); | |
172 | } | |
173 | ||
174 | if (reply) { | |
175 | sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, | |
176 | fromlen); | |
177 | os_free(reply); | |
178 | } else if (reply_len == 1) { | |
179 | sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, | |
180 | fromlen); | |
181 | } else if (reply_len == 2) { | |
182 | sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, | |
183 | fromlen); | |
184 | } | |
185 | ||
186 | if (new_attached) | |
187 | eapol_sm_notify_ctrl_attached(wpa_s->eapol); | |
188 | } | |
189 | ||
190 | ||
191 | static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) | |
192 | { | |
193 | char *buf; | |
194 | size_t len; | |
195 | char *pbuf, *dir = NULL, *gid_str = NULL; | |
196 | int res; | |
197 | ||
198 | if (wpa_s->conf->ctrl_interface == NULL) | |
199 | return NULL; | |
200 | ||
201 | pbuf = os_strdup(wpa_s->conf->ctrl_interface); | |
202 | if (pbuf == NULL) | |
203 | return NULL; | |
204 | if (os_strncmp(pbuf, "DIR=", 4) == 0) { | |
205 | dir = pbuf + 4; | |
206 | gid_str = os_strstr(dir, " GROUP="); | |
207 | if (gid_str) { | |
208 | *gid_str = '\0'; | |
209 | gid_str += 7; | |
210 | } | |
211 | } else | |
212 | dir = pbuf; | |
213 | ||
214 | len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; | |
215 | buf = os_malloc(len); | |
216 | if (buf == NULL) { | |
217 | os_free(pbuf); | |
218 | return NULL; | |
219 | } | |
220 | ||
221 | res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); | |
222 | if (res < 0 || (size_t) res >= len) { | |
223 | os_free(pbuf); | |
224 | os_free(buf); | |
225 | return NULL; | |
226 | } | |
227 | #ifdef __CYGWIN__ | |
228 | { | |
229 | /* Windows/WinPcap uses interface names that are not suitable | |
230 | * as a file name - convert invalid chars to underscores */ | |
231 | char *pos = buf; | |
232 | while (*pos) { | |
233 | if (*pos == '\\') | |
234 | *pos = '_'; | |
235 | pos++; | |
236 | } | |
237 | } | |
238 | #endif /* __CYGWIN__ */ | |
239 | os_free(pbuf); | |
240 | return buf; | |
241 | } | |
242 | ||
243 | ||
244 | static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, | |
245 | const char *txt, size_t len) | |
246 | { | |
247 | struct wpa_supplicant *wpa_s = ctx; | |
248 | if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) | |
249 | return; | |
250 | wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); | |
251 | } | |
252 | ||
253 | ||
254 | struct ctrl_iface_priv * | |
255 | wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) | |
256 | { | |
257 | struct ctrl_iface_priv *priv; | |
258 | struct sockaddr_un addr; | |
259 | char *fname = NULL; | |
260 | gid_t gid = 0; | |
261 | int gid_set = 0; | |
262 | char *buf, *dir = NULL, *gid_str = NULL; | |
263 | struct group *grp; | |
264 | char *endp; | |
265 | ||
266 | priv = os_zalloc(sizeof(*priv)); | |
267 | if (priv == NULL) | |
268 | return NULL; | |
09e47a07 | 269 | dl_list_init(&priv->ctrl_dst); |
6fc6879b JM |
270 | priv->wpa_s = wpa_s; |
271 | priv->sock = -1; | |
272 | ||
273 | if (wpa_s->conf->ctrl_interface == NULL) | |
274 | return priv; | |
275 | ||
276 | buf = os_strdup(wpa_s->conf->ctrl_interface); | |
277 | if (buf == NULL) | |
278 | goto fail; | |
279 | if (os_strncmp(buf, "DIR=", 4) == 0) { | |
280 | dir = buf + 4; | |
281 | gid_str = os_strstr(dir, " GROUP="); | |
282 | if (gid_str) { | |
283 | *gid_str = '\0'; | |
284 | gid_str += 7; | |
285 | } | |
286 | } else { | |
287 | dir = buf; | |
288 | gid_str = wpa_s->conf->ctrl_interface_group; | |
289 | } | |
290 | ||
291 | if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { | |
292 | if (errno == EEXIST) { | |
293 | wpa_printf(MSG_DEBUG, "Using existing control " | |
294 | "interface directory."); | |
295 | } else { | |
296 | perror("mkdir[ctrl_interface]"); | |
297 | goto fail; | |
298 | } | |
299 | } | |
300 | ||
301 | if (gid_str) { | |
302 | grp = getgrnam(gid_str); | |
303 | if (grp) { | |
304 | gid = grp->gr_gid; | |
305 | gid_set = 1; | |
306 | wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" | |
307 | " (from group name '%s')", | |
308 | (int) gid, gid_str); | |
309 | } else { | |
310 | /* Group name not found - try to parse this as gid */ | |
311 | gid = strtol(gid_str, &endp, 10); | |
312 | if (*gid_str == '\0' || *endp != '\0') { | |
8e888179 | 313 | wpa_printf(MSG_ERROR, "CTRL: Invalid group " |
6fc6879b JM |
314 | "'%s'", gid_str); |
315 | goto fail; | |
316 | } | |
317 | gid_set = 1; | |
318 | wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", | |
319 | (int) gid); | |
320 | } | |
321 | } | |
322 | ||
323 | if (gid_set && chown(dir, -1, gid) < 0) { | |
324 | perror("chown[ctrl_interface]"); | |
325 | goto fail; | |
326 | } | |
327 | ||
3fd2a226 AAS |
328 | /* Make sure the group can enter and read the directory */ |
329 | if (gid_set && | |
330 | chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) { | |
331 | wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s", | |
332 | strerror(errno)); | |
333 | goto fail; | |
334 | } | |
335 | ||
6fc6879b JM |
336 | if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= |
337 | sizeof(addr.sun_path)) { | |
338 | wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); | |
339 | goto fail; | |
340 | } | |
341 | ||
342 | priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); | |
343 | if (priv->sock < 0) { | |
344 | perror("socket(PF_UNIX)"); | |
345 | goto fail; | |
346 | } | |
347 | ||
348 | os_memset(&addr, 0, sizeof(addr)); | |
09bd6e8c | 349 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
19b9436c SL |
350 | addr.sun_len = sizeof(addr); |
351 | #endif /* __FreeBSD__ */ | |
6fc6879b JM |
352 | addr.sun_family = AF_UNIX; |
353 | fname = wpa_supplicant_ctrl_iface_path(wpa_s); | |
354 | if (fname == NULL) | |
355 | goto fail; | |
356 | os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); | |
357 | if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { | |
358 | wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", | |
359 | strerror(errno)); | |
360 | if (connect(priv->sock, (struct sockaddr *) &addr, | |
361 | sizeof(addr)) < 0) { | |
362 | wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" | |
363 | " allow connections - assuming it was left" | |
364 | "over from forced program termination"); | |
365 | if (unlink(fname) < 0) { | |
366 | perror("unlink[ctrl_iface]"); | |
367 | wpa_printf(MSG_ERROR, "Could not unlink " | |
368 | "existing ctrl_iface socket '%s'", | |
369 | fname); | |
370 | goto fail; | |
371 | } | |
372 | if (bind(priv->sock, (struct sockaddr *) &addr, | |
373 | sizeof(addr)) < 0) { | |
374 | perror("bind(PF_UNIX)"); | |
375 | goto fail; | |
376 | } | |
377 | wpa_printf(MSG_DEBUG, "Successfully replaced leftover " | |
378 | "ctrl_iface socket '%s'", fname); | |
379 | } else { | |
380 | wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " | |
381 | "be in use - cannot override it"); | |
382 | wpa_printf(MSG_INFO, "Delete '%s' manually if it is " | |
383 | "not used anymore", fname); | |
384 | os_free(fname); | |
385 | fname = NULL; | |
386 | goto fail; | |
387 | } | |
388 | } | |
389 | ||
390 | if (gid_set && chown(fname, -1, gid) < 0) { | |
391 | perror("chown[ctrl_interface/ifname]"); | |
392 | goto fail; | |
393 | } | |
394 | ||
395 | if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { | |
396 | perror("chmod[ctrl_interface/ifname]"); | |
397 | goto fail; | |
398 | } | |
399 | os_free(fname); | |
400 | ||
401 | eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, | |
402 | wpa_s, priv); | |
403 | wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); | |
404 | ||
405 | os_free(buf); | |
406 | return priv; | |
407 | ||
408 | fail: | |
409 | if (priv->sock >= 0) | |
410 | close(priv->sock); | |
411 | os_free(priv); | |
412 | if (fname) { | |
413 | unlink(fname); | |
414 | os_free(fname); | |
415 | } | |
416 | os_free(buf); | |
417 | return NULL; | |
418 | } | |
419 | ||
420 | ||
421 | void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) | |
422 | { | |
423 | struct wpa_ctrl_dst *dst, *prev; | |
424 | ||
425 | if (priv->sock > -1) { | |
426 | char *fname; | |
427 | char *buf, *dir = NULL, *gid_str = NULL; | |
428 | eloop_unregister_read_sock(priv->sock); | |
09e47a07 | 429 | if (!dl_list_empty(&priv->ctrl_dst)) { |
6fc6879b JM |
430 | /* |
431 | * Wait a second before closing the control socket if | |
432 | * there are any attached monitors in order to allow | |
433 | * them to receive any pending messages. | |
434 | */ | |
435 | wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " | |
436 | "monitors to receive messages"); | |
437 | os_sleep(1, 0); | |
438 | } | |
439 | close(priv->sock); | |
440 | priv->sock = -1; | |
441 | fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); | |
442 | if (fname) { | |
443 | unlink(fname); | |
444 | os_free(fname); | |
445 | } | |
446 | ||
447 | buf = os_strdup(priv->wpa_s->conf->ctrl_interface); | |
448 | if (buf == NULL) | |
449 | goto free_dst; | |
450 | if (os_strncmp(buf, "DIR=", 4) == 0) { | |
451 | dir = buf + 4; | |
452 | gid_str = os_strstr(dir, " GROUP="); | |
453 | if (gid_str) { | |
454 | *gid_str = '\0'; | |
455 | gid_str += 7; | |
456 | } | |
457 | } else | |
458 | dir = buf; | |
459 | ||
460 | if (rmdir(dir) < 0) { | |
461 | if (errno == ENOTEMPTY) { | |
462 | wpa_printf(MSG_DEBUG, "Control interface " | |
463 | "directory not empty - leaving it " | |
464 | "behind"); | |
465 | } else { | |
466 | perror("rmdir[ctrl_interface]"); | |
467 | } | |
468 | } | |
469 | os_free(buf); | |
470 | } | |
471 | ||
472 | free_dst: | |
09e47a07 JM |
473 | dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, |
474 | list) | |
475 | os_free(dst); | |
6fc6879b JM |
476 | os_free(priv); |
477 | } | |
478 | ||
479 | ||
480 | /** | |
481 | * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors | |
482 | * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() | |
483 | * @level: Priority level of the message | |
484 | * @buf: Message data | |
485 | * @len: Message length | |
486 | * | |
487 | * Send a packet to all monitor programs attached to the control interface. | |
488 | */ | |
489 | static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, | |
490 | int level, const char *buf, | |
491 | size_t len) | |
492 | { | |
493 | struct wpa_ctrl_dst *dst, *next; | |
494 | char levelstr[10]; | |
495 | int idx, res; | |
496 | struct msghdr msg; | |
497 | struct iovec io[2]; | |
498 | ||
09e47a07 | 499 | if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst)) |
6fc6879b JM |
500 | return; |
501 | ||
502 | res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); | |
503 | if (res < 0 || (size_t) res >= sizeof(levelstr)) | |
504 | return; | |
505 | io[0].iov_base = levelstr; | |
506 | io[0].iov_len = os_strlen(levelstr); | |
507 | io[1].iov_base = (char *) buf; | |
508 | io[1].iov_len = len; | |
509 | os_memset(&msg, 0, sizeof(msg)); | |
510 | msg.msg_iov = io; | |
511 | msg.msg_iovlen = 2; | |
512 | ||
513 | idx = 0; | |
09e47a07 JM |
514 | dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst, |
515 | list) { | |
6fc6879b JM |
516 | if (level >= dst->debug_level) { |
517 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", | |
518 | (u8 *) dst->addr.sun_path, dst->addrlen - | |
19b9436c | 519 | offsetof(struct sockaddr_un, sun_path)); |
6fc6879b JM |
520 | msg.msg_name = (void *) &dst->addr; |
521 | msg.msg_namelen = dst->addrlen; | |
522 | if (sendmsg(priv->sock, &msg, 0) < 0) { | |
c5aaa015 JM |
523 | int _errno = errno; |
524 | wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " | |
525 | "%d - %s", | |
526 | idx, errno, strerror(errno)); | |
6fc6879b | 527 | dst->errors++; |
6700a277 JM |
528 | if (dst->errors > 1000 || |
529 | (_errno != ENOBUFS && dst->errors > 10) || | |
530 | _errno == ENOENT) { | |
6fc6879b JM |
531 | wpa_supplicant_ctrl_iface_detach( |
532 | priv, &dst->addr, | |
533 | dst->addrlen); | |
534 | } | |
535 | } else | |
536 | dst->errors = 0; | |
537 | } | |
538 | idx++; | |
6fc6879b JM |
539 | } |
540 | } | |
541 | ||
542 | ||
543 | void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) | |
544 | { | |
545 | char buf[256]; | |
546 | int res; | |
547 | struct sockaddr_un from; | |
548 | socklen_t fromlen = sizeof(from); | |
549 | ||
550 | for (;;) { | |
551 | wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " | |
552 | "attach", priv->wpa_s->ifname); | |
553 | eloop_wait_for_read_sock(priv->sock); | |
554 | ||
555 | res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, | |
556 | (struct sockaddr *) &from, &fromlen); | |
557 | if (res < 0) { | |
558 | perror("recvfrom(ctrl_iface)"); | |
559 | continue; | |
560 | } | |
561 | buf[res] = '\0'; | |
562 | ||
563 | if (os_strcmp(buf, "ATTACH") == 0) { | |
564 | /* handle ATTACH signal of first monitor interface */ | |
565 | if (!wpa_supplicant_ctrl_iface_attach(priv, &from, | |
566 | fromlen)) { | |
567 | sendto(priv->sock, "OK\n", 3, 0, | |
568 | (struct sockaddr *) &from, fromlen); | |
569 | /* OK to continue */ | |
570 | return; | |
571 | } else { | |
572 | sendto(priv->sock, "FAIL\n", 5, 0, | |
573 | (struct sockaddr *) &from, fromlen); | |
574 | } | |
575 | } else { | |
576 | /* return FAIL for all other signals */ | |
577 | sendto(priv->sock, "FAIL\n", 5, 0, | |
578 | (struct sockaddr *) &from, fromlen); | |
579 | } | |
580 | } | |
581 | } | |
582 | ||
583 | ||
584 | /* Global ctrl_iface */ | |
585 | ||
586 | struct ctrl_iface_global_priv { | |
587 | struct wpa_global *global; | |
588 | int sock; | |
589 | }; | |
590 | ||
591 | ||
592 | static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, | |
593 | void *sock_ctx) | |
594 | { | |
595 | struct wpa_global *global = eloop_ctx; | |
596 | char buf[256]; | |
597 | int res; | |
598 | struct sockaddr_un from; | |
599 | socklen_t fromlen = sizeof(from); | |
600 | char *reply; | |
601 | size_t reply_len; | |
602 | ||
603 | res = recvfrom(sock, buf, sizeof(buf) - 1, 0, | |
604 | (struct sockaddr *) &from, &fromlen); | |
605 | if (res < 0) { | |
606 | perror("recvfrom(ctrl_iface)"); | |
607 | return; | |
608 | } | |
609 | buf[res] = '\0'; | |
610 | ||
611 | reply = wpa_supplicant_global_ctrl_iface_process(global, buf, | |
612 | &reply_len); | |
613 | ||
614 | if (reply) { | |
615 | sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, | |
616 | fromlen); | |
617 | os_free(reply); | |
618 | } else if (reply_len) { | |
619 | sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, | |
620 | fromlen); | |
621 | } | |
622 | } | |
623 | ||
624 | ||
625 | struct ctrl_iface_global_priv * | |
626 | wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) | |
627 | { | |
628 | struct ctrl_iface_global_priv *priv; | |
629 | struct sockaddr_un addr; | |
630 | ||
631 | priv = os_zalloc(sizeof(*priv)); | |
632 | if (priv == NULL) | |
633 | return NULL; | |
634 | priv->global = global; | |
635 | priv->sock = -1; | |
636 | ||
637 | if (global->params.ctrl_interface == NULL) | |
638 | return priv; | |
639 | ||
640 | wpa_printf(MSG_DEBUG, "Global control interface '%s'", | |
641 | global->params.ctrl_interface); | |
642 | ||
643 | priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); | |
644 | if (priv->sock < 0) { | |
645 | perror("socket(PF_UNIX)"); | |
646 | goto fail; | |
647 | } | |
648 | ||
649 | os_memset(&addr, 0, sizeof(addr)); | |
09bd6e8c | 650 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
19b9436c SL |
651 | addr.sun_len = sizeof(addr); |
652 | #endif /* __FreeBSD__ */ | |
6fc6879b JM |
653 | addr.sun_family = AF_UNIX; |
654 | os_strlcpy(addr.sun_path, global->params.ctrl_interface, | |
655 | sizeof(addr.sun_path)); | |
656 | if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { | |
657 | perror("bind(PF_UNIX)"); | |
658 | if (connect(priv->sock, (struct sockaddr *) &addr, | |
659 | sizeof(addr)) < 0) { | |
660 | wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" | |
661 | " allow connections - assuming it was left" | |
662 | "over from forced program termination"); | |
663 | if (unlink(global->params.ctrl_interface) < 0) { | |
664 | perror("unlink[ctrl_iface]"); | |
665 | wpa_printf(MSG_ERROR, "Could not unlink " | |
666 | "existing ctrl_iface socket '%s'", | |
667 | global->params.ctrl_interface); | |
668 | goto fail; | |
669 | } | |
670 | if (bind(priv->sock, (struct sockaddr *) &addr, | |
671 | sizeof(addr)) < 0) { | |
672 | perror("bind(PF_UNIX)"); | |
673 | goto fail; | |
674 | } | |
675 | wpa_printf(MSG_DEBUG, "Successfully replaced leftover " | |
676 | "ctrl_iface socket '%s'", | |
677 | global->params.ctrl_interface); | |
678 | } else { | |
679 | wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " | |
680 | "be in use - cannot override it"); | |
681 | wpa_printf(MSG_INFO, "Delete '%s' manually if it is " | |
682 | "not used anymore", | |
683 | global->params.ctrl_interface); | |
684 | goto fail; | |
685 | } | |
686 | } | |
687 | ||
688 | eloop_register_read_sock(priv->sock, | |
689 | wpa_supplicant_global_ctrl_iface_receive, | |
690 | global, NULL); | |
691 | ||
692 | return priv; | |
693 | ||
694 | fail: | |
695 | if (priv->sock >= 0) | |
696 | close(priv->sock); | |
697 | os_free(priv); | |
698 | return NULL; | |
699 | } | |
700 | ||
701 | ||
702 | void | |
703 | wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) | |
704 | { | |
705 | if (priv->sock >= 0) { | |
706 | eloop_unregister_read_sock(priv->sock); | |
707 | close(priv->sock); | |
708 | } | |
709 | if (priv->global->params.ctrl_interface) | |
710 | unlink(priv->global->params.ctrl_interface); | |
711 | os_free(priv); | |
712 | } |