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