]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * hostapd / UNIX domain socket -based control interface | |
3 | * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> | |
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 | ||
17 | #ifndef CONFIG_NATIVE_WINDOWS | |
18 | ||
19 | #include <sys/un.h> | |
20 | #include <sys/stat.h> | |
75864b7f | 21 | #include <stddef.h> |
6fc6879b JM |
22 | |
23 | #include "hostapd.h" | |
24 | #include "eloop.h" | |
25 | #include "config.h" | |
26 | #include "ieee802_1x.h" | |
27 | #include "wpa.h" | |
28 | #include "radius/radius_client.h" | |
29 | #include "ieee802_11.h" | |
30 | #include "ctrl_iface.h" | |
31 | #include "sta_info.h" | |
32 | #include "accounting.h" | |
ad08c363 | 33 | #include "wps_hostapd.h" |
c5121837 | 34 | #include "drivers/driver.h" |
6fc6879b JM |
35 | |
36 | ||
37 | struct wpa_ctrl_dst { | |
38 | struct wpa_ctrl_dst *next; | |
39 | struct sockaddr_un addr; | |
40 | socklen_t addrlen; | |
41 | int debug_level; | |
42 | int errors; | |
43 | }; | |
44 | ||
45 | ||
42d16805 JM |
46 | static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, |
47 | const char *buf, size_t len); | |
48 | ||
49 | ||
6fc6879b JM |
50 | static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, |
51 | struct sockaddr_un *from, | |
52 | socklen_t fromlen) | |
53 | { | |
54 | struct wpa_ctrl_dst *dst; | |
55 | ||
56 | dst = os_zalloc(sizeof(*dst)); | |
57 | if (dst == NULL) | |
58 | return -1; | |
59 | os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); | |
60 | dst->addrlen = fromlen; | |
61 | dst->debug_level = MSG_INFO; | |
62 | dst->next = hapd->ctrl_dst; | |
63 | hapd->ctrl_dst = dst; | |
64 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", | |
75864b7f JM |
65 | (u8 *) from->sun_path, |
66 | fromlen - offsetof(struct sockaddr_un, sun_path)); | |
6fc6879b JM |
67 | return 0; |
68 | } | |
69 | ||
70 | ||
71 | static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, | |
72 | struct sockaddr_un *from, | |
73 | socklen_t fromlen) | |
74 | { | |
75 | struct wpa_ctrl_dst *dst, *prev = NULL; | |
76 | ||
77 | dst = hapd->ctrl_dst; | |
78 | while (dst) { | |
79 | if (fromlen == dst->addrlen && | |
75864b7f JM |
80 | os_memcmp(from->sun_path, dst->addr.sun_path, |
81 | fromlen - offsetof(struct sockaddr_un, sun_path)) | |
82 | == 0) { | |
6fc6879b JM |
83 | if (prev == NULL) |
84 | hapd->ctrl_dst = dst->next; | |
85 | else | |
86 | prev->next = dst->next; | |
87 | os_free(dst); | |
88 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", | |
75864b7f JM |
89 | (u8 *) from->sun_path, |
90 | fromlen - | |
91 | offsetof(struct sockaddr_un, sun_path)); | |
6fc6879b JM |
92 | return 0; |
93 | } | |
94 | prev = dst; | |
95 | dst = dst->next; | |
96 | } | |
97 | return -1; | |
98 | } | |
99 | ||
100 | ||
101 | static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, | |
102 | struct sockaddr_un *from, | |
103 | socklen_t fromlen, | |
104 | char *level) | |
105 | { | |
106 | struct wpa_ctrl_dst *dst; | |
107 | ||
108 | wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); | |
109 | ||
110 | dst = hapd->ctrl_dst; | |
111 | while (dst) { | |
112 | if (fromlen == dst->addrlen && | |
75864b7f JM |
113 | os_memcmp(from->sun_path, dst->addr.sun_path, |
114 | fromlen - offsetof(struct sockaddr_un, sun_path)) | |
115 | == 0) { | |
6fc6879b | 116 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " |
75864b7f JM |
117 | "level", (u8 *) from->sun_path, fromlen - |
118 | offsetof(struct sockaddr_un, sun_path)); | |
6fc6879b JM |
119 | dst->debug_level = atoi(level); |
120 | return 0; | |
121 | } | |
122 | dst = dst->next; | |
123 | } | |
124 | ||
125 | return -1; | |
126 | } | |
127 | ||
128 | ||
129 | static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, | |
130 | struct sta_info *sta, | |
131 | char *buf, size_t buflen) | |
132 | { | |
133 | int len, res, ret; | |
134 | ||
135 | if (sta == NULL) { | |
136 | ret = os_snprintf(buf, buflen, "FAIL\n"); | |
137 | if (ret < 0 || (size_t) ret >= buflen) | |
138 | return 0; | |
139 | return ret; | |
140 | } | |
141 | ||
142 | len = 0; | |
143 | ret = os_snprintf(buf + len, buflen - len, MACSTR "\n", | |
144 | MAC2STR(sta->addr)); | |
145 | if (ret < 0 || (size_t) ret >= buflen - len) | |
146 | return len; | |
147 | len += ret; | |
148 | ||
149 | res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); | |
150 | if (res >= 0) | |
151 | len += res; | |
152 | res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len); | |
153 | if (res >= 0) | |
154 | len += res; | |
155 | res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); | |
156 | if (res >= 0) | |
157 | len += res; | |
158 | ||
159 | return len; | |
160 | } | |
161 | ||
162 | ||
163 | static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, | |
164 | char *buf, size_t buflen) | |
165 | { | |
166 | return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen); | |
167 | } | |
168 | ||
169 | ||
170 | static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, | |
171 | const char *txtaddr, | |
172 | char *buf, size_t buflen) | |
173 | { | |
174 | u8 addr[ETH_ALEN]; | |
175 | int ret; | |
176 | ||
177 | if (hwaddr_aton(txtaddr, addr)) { | |
178 | ret = os_snprintf(buf, buflen, "FAIL\n"); | |
179 | if (ret < 0 || (size_t) ret >= buflen) | |
180 | return 0; | |
181 | return ret; | |
182 | } | |
183 | return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr), | |
184 | buf, buflen); | |
185 | } | |
186 | ||
187 | ||
188 | static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, | |
189 | const char *txtaddr, | |
190 | char *buf, size_t buflen) | |
191 | { | |
192 | u8 addr[ETH_ALEN]; | |
193 | struct sta_info *sta; | |
194 | int ret; | |
195 | ||
196 | if (hwaddr_aton(txtaddr, addr) || | |
197 | (sta = ap_get_sta(hapd, addr)) == NULL) { | |
198 | ret = os_snprintf(buf, buflen, "FAIL\n"); | |
199 | if (ret < 0 || (size_t) ret >= buflen) | |
200 | return 0; | |
201 | return ret; | |
202 | } | |
203 | return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); | |
204 | } | |
205 | ||
206 | ||
207 | static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, | |
208 | const char *txtaddr) | |
209 | { | |
210 | u8 addr[ETH_ALEN]; | |
211 | struct sta_info *sta; | |
212 | ||
213 | wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); | |
214 | ||
215 | if (hwaddr_aton(txtaddr, addr)) | |
216 | return -1; | |
217 | ||
218 | sta = ap_get_sta(hapd, addr); | |
219 | if (sta) | |
220 | return 0; | |
221 | ||
222 | wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " | |
223 | "notification", MAC2STR(addr)); | |
224 | sta = ap_sta_add(hapd, addr); | |
225 | if (sta == NULL) | |
226 | return -1; | |
227 | ||
228 | hostapd_new_assoc_sta(hapd, sta, 0); | |
6fc6879b JM |
229 | return 0; |
230 | } | |
231 | ||
232 | ||
88b4b424 | 233 | #ifdef CONFIG_IEEE80211W |
c5121837 | 234 | #ifdef NEED_MLME |
88b4b424 JM |
235 | static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, |
236 | const char *txtaddr) | |
237 | { | |
238 | u8 addr[ETH_ALEN]; | |
239 | u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; | |
240 | ||
241 | wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); | |
242 | ||
243 | if (hwaddr_aton(txtaddr, addr)) | |
244 | return -1; | |
245 | ||
246 | os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN); | |
247 | ieee802_11_send_sa_query_req(hapd, addr, trans_id); | |
248 | ||
249 | return 0; | |
250 | } | |
c5121837 | 251 | #endif /* NEED_MLME */ |
88b4b424 JM |
252 | #endif /* CONFIG_IEEE80211W */ |
253 | ||
254 | ||
ad08c363 JM |
255 | #ifdef CONFIG_WPS |
256 | static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) | |
257 | { | |
258 | char *pin = os_strchr(txt, ' '); | |
077a781f JM |
259 | char *timeout_txt; |
260 | int timeout; | |
261 | ||
ad08c363 JM |
262 | if (pin == NULL) |
263 | return -1; | |
264 | *pin++ = '\0'; | |
077a781f JM |
265 | |
266 | timeout_txt = os_strchr(pin, ' '); | |
267 | if (timeout_txt) { | |
268 | *timeout_txt++ = '\0'; | |
269 | timeout = atoi(timeout_txt); | |
270 | } else | |
271 | timeout = 0; | |
272 | ||
273 | return hostapd_wps_add_pin(hapd, txt, pin, timeout); | |
ad08c363 | 274 | } |
46bdb83a MH |
275 | |
276 | ||
116f7bb0 | 277 | #ifdef CONFIG_WPS_OOB |
46bdb83a MH |
278 | static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt) |
279 | { | |
e1ee6b60 | 280 | char *path, *method, *name; |
46bdb83a MH |
281 | |
282 | path = os_strchr(txt, ' '); | |
283 | if (path == NULL) | |
284 | return -1; | |
285 | *path++ = '\0'; | |
286 | ||
287 | method = os_strchr(path, ' '); | |
288 | if (method == NULL) | |
289 | return -1; | |
290 | *method++ = '\0'; | |
291 | ||
e1ee6b60 MH |
292 | name = os_strchr(method, ' '); |
293 | if (name != NULL) | |
294 | *name++ = '\0'; | |
295 | ||
296 | return hostapd_wps_start_oob(hapd, txt, path, method, name); | |
46bdb83a | 297 | } |
116f7bb0 | 298 | #endif /* CONFIG_WPS_OOB */ |
ad08c363 JM |
299 | #endif /* CONFIG_WPS */ |
300 | ||
301 | ||
6fc6879b JM |
302 | static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, |
303 | void *sock_ctx) | |
304 | { | |
305 | struct hostapd_data *hapd = eloop_ctx; | |
306 | char buf[256]; | |
307 | int res; | |
308 | struct sockaddr_un from; | |
309 | socklen_t fromlen = sizeof(from); | |
310 | char *reply; | |
311 | const int reply_size = 4096; | |
312 | int reply_len; | |
313 | ||
314 | res = recvfrom(sock, buf, sizeof(buf) - 1, 0, | |
315 | (struct sockaddr *) &from, &fromlen); | |
316 | if (res < 0) { | |
317 | perror("recvfrom(ctrl_iface)"); | |
318 | return; | |
319 | } | |
320 | buf[res] = '\0'; | |
321 | wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res); | |
322 | ||
323 | reply = os_malloc(reply_size); | |
324 | if (reply == NULL) { | |
325 | sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, | |
326 | fromlen); | |
327 | return; | |
328 | } | |
329 | ||
330 | os_memcpy(reply, "OK\n", 3); | |
331 | reply_len = 3; | |
332 | ||
333 | if (os_strcmp(buf, "PING") == 0) { | |
334 | os_memcpy(reply, "PONG\n", 5); | |
335 | reply_len = 5; | |
336 | } else if (os_strcmp(buf, "MIB") == 0) { | |
337 | reply_len = ieee802_11_get_mib(hapd, reply, reply_size); | |
338 | if (reply_len >= 0) { | |
339 | res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, | |
340 | reply_size - reply_len); | |
341 | if (res < 0) | |
342 | reply_len = -1; | |
343 | else | |
344 | reply_len += res; | |
345 | } | |
346 | if (reply_len >= 0) { | |
347 | res = ieee802_1x_get_mib(hapd, reply + reply_len, | |
348 | reply_size - reply_len); | |
349 | if (res < 0) | |
350 | reply_len = -1; | |
351 | else | |
352 | reply_len += res; | |
353 | } | |
354 | if (reply_len >= 0) { | |
355 | res = radius_client_get_mib(hapd->radius, | |
356 | reply + reply_len, | |
357 | reply_size - reply_len); | |
358 | if (res < 0) | |
359 | reply_len = -1; | |
360 | else | |
361 | reply_len += res; | |
362 | } | |
363 | } else if (os_strcmp(buf, "STA-FIRST") == 0) { | |
364 | reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, | |
365 | reply_size); | |
366 | } else if (os_strncmp(buf, "STA ", 4) == 0) { | |
367 | reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, | |
368 | reply_size); | |
369 | } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { | |
370 | reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, | |
371 | reply_size); | |
372 | } else if (os_strcmp(buf, "ATTACH") == 0) { | |
373 | if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) | |
374 | reply_len = -1; | |
375 | } else if (os_strcmp(buf, "DETACH") == 0) { | |
376 | if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) | |
377 | reply_len = -1; | |
378 | } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { | |
379 | if (hostapd_ctrl_iface_level(hapd, &from, fromlen, | |
380 | buf + 6)) | |
381 | reply_len = -1; | |
382 | } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { | |
383 | if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) | |
384 | reply_len = -1; | |
88b4b424 | 385 | #ifdef CONFIG_IEEE80211W |
c5121837 | 386 | #ifdef NEED_MLME |
88b4b424 JM |
387 | } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { |
388 | if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) | |
389 | reply_len = -1; | |
c5121837 | 390 | #endif /* NEED_MLME */ |
88b4b424 | 391 | #endif /* CONFIG_IEEE80211W */ |
ad08c363 JM |
392 | #ifdef CONFIG_WPS |
393 | } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { | |
394 | if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) | |
395 | reply_len = -1; | |
396 | } else if (os_strcmp(buf, "WPS_PBC") == 0) { | |
397 | if (hostapd_wps_button_pushed(hapd)) | |
398 | reply_len = -1; | |
116f7bb0 | 399 | #ifdef CONFIG_WPS_OOB |
46bdb83a MH |
400 | } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) { |
401 | if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8)) | |
402 | reply_len = -1; | |
116f7bb0 | 403 | #endif /* CONFIG_WPS_OOB */ |
ad08c363 | 404 | #endif /* CONFIG_WPS */ |
6fc6879b JM |
405 | } else { |
406 | os_memcpy(reply, "UNKNOWN COMMAND\n", 16); | |
407 | reply_len = 16; | |
408 | } | |
409 | ||
410 | if (reply_len < 0) { | |
411 | os_memcpy(reply, "FAIL\n", 5); | |
412 | reply_len = 5; | |
413 | } | |
414 | sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); | |
415 | os_free(reply); | |
416 | } | |
417 | ||
418 | ||
419 | static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) | |
420 | { | |
421 | char *buf; | |
422 | size_t len; | |
423 | ||
424 | if (hapd->conf->ctrl_interface == NULL) | |
425 | return NULL; | |
426 | ||
427 | len = os_strlen(hapd->conf->ctrl_interface) + | |
428 | os_strlen(hapd->conf->iface) + 2; | |
429 | buf = os_malloc(len); | |
430 | if (buf == NULL) | |
431 | return NULL; | |
432 | ||
433 | os_snprintf(buf, len, "%s/%s", | |
434 | hapd->conf->ctrl_interface, hapd->conf->iface); | |
435 | buf[len - 1] = '\0'; | |
436 | return buf; | |
437 | } | |
438 | ||
439 | ||
42d16805 JM |
440 | static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, |
441 | const char *txt, size_t len) | |
442 | { | |
443 | struct hostapd_data *hapd = ctx; | |
444 | if (hapd == NULL) | |
445 | return; | |
446 | hostapd_ctrl_iface_send(hapd, level, txt, len); | |
447 | } | |
448 | ||
449 | ||
6fc6879b JM |
450 | int hostapd_ctrl_iface_init(struct hostapd_data *hapd) |
451 | { | |
452 | struct sockaddr_un addr; | |
453 | int s = -1; | |
454 | char *fname = NULL; | |
455 | ||
456 | hapd->ctrl_sock = -1; | |
457 | ||
458 | if (hapd->conf->ctrl_interface == NULL) | |
459 | return 0; | |
460 | ||
461 | if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { | |
462 | if (errno == EEXIST) { | |
463 | wpa_printf(MSG_DEBUG, "Using existing control " | |
464 | "interface directory."); | |
465 | } else { | |
466 | perror("mkdir[ctrl_interface]"); | |
467 | goto fail; | |
468 | } | |
469 | } | |
470 | ||
471 | if (hapd->conf->ctrl_interface_gid_set && | |
472 | chown(hapd->conf->ctrl_interface, 0, | |
473 | hapd->conf->ctrl_interface_gid) < 0) { | |
474 | perror("chown[ctrl_interface]"); | |
475 | return -1; | |
476 | } | |
477 | ||
478 | if (os_strlen(hapd->conf->ctrl_interface) + 1 + | |
479 | os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) | |
480 | goto fail; | |
481 | ||
482 | s = socket(PF_UNIX, SOCK_DGRAM, 0); | |
483 | if (s < 0) { | |
484 | perror("socket(PF_UNIX)"); | |
485 | goto fail; | |
486 | } | |
487 | ||
488 | os_memset(&addr, 0, sizeof(addr)); | |
75864b7f JM |
489 | #ifdef __FreeBSD__ |
490 | addr.sun_len = sizeof(addr); | |
491 | #endif /* __FreeBSD__ */ | |
6fc6879b JM |
492 | addr.sun_family = AF_UNIX; |
493 | fname = hostapd_ctrl_iface_path(hapd); | |
494 | if (fname == NULL) | |
495 | goto fail; | |
496 | os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); | |
497 | if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { | |
617d1555 JM |
498 | wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", |
499 | strerror(errno)); | |
500 | if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { | |
501 | wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" | |
502 | " allow connections - assuming it was left" | |
503 | "over from forced program termination"); | |
504 | if (unlink(fname) < 0) { | |
505 | perror("unlink[ctrl_iface]"); | |
506 | wpa_printf(MSG_ERROR, "Could not unlink " | |
507 | "existing ctrl_iface socket '%s'", | |
508 | fname); | |
509 | goto fail; | |
510 | } | |
511 | if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < | |
512 | 0) { | |
513 | perror("bind(PF_UNIX)"); | |
514 | goto fail; | |
515 | } | |
516 | wpa_printf(MSG_DEBUG, "Successfully replaced leftover " | |
517 | "ctrl_iface socket '%s'", fname); | |
518 | } else { | |
519 | wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " | |
520 | "be in use - cannot override it"); | |
521 | wpa_printf(MSG_INFO, "Delete '%s' manually if it is " | |
522 | "not used anymore", fname); | |
523 | os_free(fname); | |
524 | fname = NULL; | |
525 | goto fail; | |
526 | } | |
6fc6879b JM |
527 | } |
528 | ||
529 | if (hapd->conf->ctrl_interface_gid_set && | |
530 | chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) { | |
531 | perror("chown[ctrl_interface/ifname]"); | |
532 | goto fail; | |
533 | } | |
534 | ||
535 | if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { | |
536 | perror("chmod[ctrl_interface/ifname]"); | |
537 | goto fail; | |
538 | } | |
539 | os_free(fname); | |
540 | ||
541 | hapd->ctrl_sock = s; | |
542 | eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, | |
543 | NULL); | |
42d16805 | 544 | wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); |
6fc6879b JM |
545 | |
546 | return 0; | |
547 | ||
548 | fail: | |
549 | if (s >= 0) | |
550 | close(s); | |
551 | if (fname) { | |
552 | unlink(fname); | |
553 | os_free(fname); | |
554 | } | |
555 | return -1; | |
556 | } | |
557 | ||
558 | ||
559 | void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) | |
560 | { | |
561 | struct wpa_ctrl_dst *dst, *prev; | |
562 | ||
563 | if (hapd->ctrl_sock > -1) { | |
564 | char *fname; | |
565 | eloop_unregister_read_sock(hapd->ctrl_sock); | |
566 | close(hapd->ctrl_sock); | |
567 | hapd->ctrl_sock = -1; | |
568 | fname = hostapd_ctrl_iface_path(hapd); | |
569 | if (fname) | |
570 | unlink(fname); | |
571 | os_free(fname); | |
572 | ||
573 | if (hapd->conf->ctrl_interface && | |
574 | rmdir(hapd->conf->ctrl_interface) < 0) { | |
575 | if (errno == ENOTEMPTY) { | |
576 | wpa_printf(MSG_DEBUG, "Control interface " | |
577 | "directory not empty - leaving it " | |
578 | "behind"); | |
579 | } else { | |
580 | perror("rmdir[ctrl_interface]"); | |
581 | } | |
582 | } | |
583 | } | |
584 | ||
585 | dst = hapd->ctrl_dst; | |
586 | while (dst) { | |
587 | prev = dst; | |
588 | dst = dst->next; | |
589 | os_free(prev); | |
590 | } | |
591 | } | |
592 | ||
593 | ||
42d16805 JM |
594 | static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, |
595 | const char *buf, size_t len) | |
6fc6879b JM |
596 | { |
597 | struct wpa_ctrl_dst *dst, *next; | |
598 | struct msghdr msg; | |
599 | int idx; | |
600 | struct iovec io[2]; | |
601 | char levelstr[10]; | |
602 | ||
603 | dst = hapd->ctrl_dst; | |
604 | if (hapd->ctrl_sock < 0 || dst == NULL) | |
605 | return; | |
606 | ||
607 | os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); | |
608 | io[0].iov_base = levelstr; | |
609 | io[0].iov_len = os_strlen(levelstr); | |
42d16805 | 610 | io[1].iov_base = (char *) buf; |
6fc6879b JM |
611 | io[1].iov_len = len; |
612 | os_memset(&msg, 0, sizeof(msg)); | |
613 | msg.msg_iov = io; | |
614 | msg.msg_iovlen = 2; | |
615 | ||
616 | idx = 0; | |
617 | while (dst) { | |
618 | next = dst->next; | |
619 | if (level >= dst->debug_level) { | |
620 | wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", | |
75864b7f JM |
621 | (u8 *) dst->addr.sun_path, dst->addrlen - |
622 | offsetof(struct sockaddr_un, sun_path)); | |
6fc6879b JM |
623 | msg.msg_name = &dst->addr; |
624 | msg.msg_namelen = dst->addrlen; | |
625 | if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { | |
c5aaa015 JM |
626 | int _errno = errno; |
627 | wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " | |
628 | "%d - %s", | |
629 | idx, errno, strerror(errno)); | |
6fc6879b | 630 | dst->errors++; |
c5aaa015 | 631 | if (dst->errors > 10 || _errno == ENOENT) { |
6fc6879b JM |
632 | hostapd_ctrl_iface_detach( |
633 | hapd, &dst->addr, | |
634 | dst->addrlen); | |
635 | } | |
636 | } else | |
637 | dst->errors = 0; | |
638 | } | |
639 | idx++; | |
640 | dst = next; | |
641 | } | |
642 | } | |
643 | ||
644 | #endif /* CONFIG_NATIVE_WINDOWS */ |