WPS 2.0: Add support for AuthorizedMACs attribute
[libeap.git] / hostapd / ctrl_iface.c
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         u8 addr_buf[ETH_ALEN], *addr = NULL;
279         char *pos;
280
281         if (pin == NULL)
282                 return -1;
283         *pin++ = '\0';
284
285         timeout_txt = os_strchr(pin, ' ');
286         if (timeout_txt) {
287                 *timeout_txt++ = '\0';
288                 timeout = atoi(timeout_txt);
289                 pos = os_strchr(timeout_txt, ' ');
290                 if (pos) {
291                         *pos++ = '\0';
292                         if (hwaddr_aton(pos, addr_buf) == 0)
293                                 addr = addr_buf;
294                 }
295         } else
296                 timeout = 0;
297
298         return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
299 }
300
301
302 #ifdef CONFIG_WPS_OOB
303 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
304 {
305         char *path, *method, *name;
306
307         path = os_strchr(txt, ' ');
308         if (path == NULL)
309                 return -1;
310         *path++ = '\0';
311
312         method = os_strchr(path, ' ');
313         if (method == NULL)
314                 return -1;
315         *method++ = '\0';
316
317         name = os_strchr(method, ' ');
318         if (name != NULL)
319                 *name++ = '\0';
320
321         return hostapd_wps_start_oob(hapd, txt, path, method, name);
322 }
323 #endif /* CONFIG_WPS_OOB */
324
325
326 static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
327                                          char *buf, size_t buflen)
328 {
329         int timeout = 300;
330         char *pos;
331         const char *pin_txt;
332
333         pos = os_strchr(txt, ' ');
334         if (pos)
335                 *pos++ = '\0';
336
337         if (os_strcmp(txt, "disable") == 0) {
338                 hostapd_wps_ap_pin_disable(hapd);
339                 return os_snprintf(buf, buflen, "OK\n");
340         }
341
342         if (os_strcmp(txt, "random") == 0) {
343                 if (pos)
344                         timeout = atoi(pos);
345                 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
346                 if (pin_txt == NULL)
347                         return -1;
348                 return os_snprintf(buf, buflen, "%s", pin_txt);
349         }
350
351         if (os_strcmp(txt, "get") == 0) {
352                 pin_txt = hostapd_wps_ap_pin_get(hapd);
353                 if (pin_txt == NULL)
354                         return -1;
355                 return os_snprintf(buf, buflen, "%s", pin_txt);
356         }
357
358         if (os_strcmp(txt, "set") == 0) {
359                 char *pin;
360                 if (pos == NULL)
361                         return -1;
362                 pin = pos;
363                 pos = os_strchr(pos, ' ');
364                 if (pos) {
365                         *pos++ = '\0';
366                         timeout = atoi(pos);
367                 }
368                 if (os_strlen(pin) > buflen)
369                         return -1;
370                 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
371                         return -1;
372                 return os_snprintf(buf, buflen, "%s", pin);
373         }
374
375         return -1;
376 }
377 #endif /* CONFIG_WPS */
378
379
380 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
381                                        void *sock_ctx)
382 {
383         struct hostapd_data *hapd = eloop_ctx;
384         char buf[256];
385         int res;
386         struct sockaddr_un from;
387         socklen_t fromlen = sizeof(from);
388         char *reply;
389         const int reply_size = 4096;
390         int reply_len;
391
392         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
393                        (struct sockaddr *) &from, &fromlen);
394         if (res < 0) {
395                 perror("recvfrom(ctrl_iface)");
396                 return;
397         }
398         buf[res] = '\0';
399         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
400
401         reply = os_malloc(reply_size);
402         if (reply == NULL) {
403                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
404                        fromlen);
405                 return;
406         }
407
408         os_memcpy(reply, "OK\n", 3);
409         reply_len = 3;
410
411         if (os_strcmp(buf, "PING") == 0) {
412                 os_memcpy(reply, "PONG\n", 5);
413                 reply_len = 5;
414         } else if (os_strcmp(buf, "MIB") == 0) {
415                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
416                 if (reply_len >= 0) {
417                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
418                                           reply_size - reply_len);
419                         if (res < 0)
420                                 reply_len = -1;
421                         else
422                                 reply_len += res;
423                 }
424                 if (reply_len >= 0) {
425                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
426                                                  reply_size - reply_len);
427                         if (res < 0)
428                                 reply_len = -1;
429                         else
430                                 reply_len += res;
431                 }
432 #ifndef CONFIG_NO_RADIUS
433                 if (reply_len >= 0) {
434                         res = radius_client_get_mib(hapd->radius,
435                                                     reply + reply_len,
436                                                     reply_size - reply_len);
437                         if (res < 0)
438                                 reply_len = -1;
439                         else
440                                 reply_len += res;
441                 }
442 #endif /* CONFIG_NO_RADIUS */
443         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
444                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
445                                                          reply_size);
446         } else if (os_strncmp(buf, "STA ", 4) == 0) {
447                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
448                                                    reply_size);
449         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
450                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
451                                                         reply_size);
452         } else if (os_strcmp(buf, "ATTACH") == 0) {
453                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
454                         reply_len = -1;
455         } else if (os_strcmp(buf, "DETACH") == 0) {
456                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
457                         reply_len = -1;
458         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
459                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
460                                                     buf + 6))
461                         reply_len = -1;
462         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
463                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
464                         reply_len = -1;
465         } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
466                 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
467                         reply_len = -1;
468         } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
469                 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
470                         reply_len = -1;
471 #ifdef CONFIG_IEEE80211W
472 #ifdef NEED_AP_MLME
473         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
474                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
475                         reply_len = -1;
476 #endif /* NEED_AP_MLME */
477 #endif /* CONFIG_IEEE80211W */
478 #ifdef CONFIG_WPS
479         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
480                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
481                         reply_len = -1;
482         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
483                 if (hostapd_wps_button_pushed(hapd))
484                         reply_len = -1;
485 #ifdef CONFIG_WPS_OOB
486         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
487                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
488                         reply_len = -1;
489 #endif /* CONFIG_WPS_OOB */
490         } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
491                 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
492                                                           reply, reply_size);
493 #endif /* CONFIG_WPS */
494         } else {
495                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
496                 reply_len = 16;
497         }
498
499         if (reply_len < 0) {
500                 os_memcpy(reply, "FAIL\n", 5);
501                 reply_len = 5;
502         }
503         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
504         os_free(reply);
505 }
506
507
508 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
509 {
510         char *buf;
511         size_t len;
512
513         if (hapd->conf->ctrl_interface == NULL)
514                 return NULL;
515
516         len = os_strlen(hapd->conf->ctrl_interface) +
517                 os_strlen(hapd->conf->iface) + 2;
518         buf = os_malloc(len);
519         if (buf == NULL)
520                 return NULL;
521
522         os_snprintf(buf, len, "%s/%s",
523                     hapd->conf->ctrl_interface, hapd->conf->iface);
524         buf[len - 1] = '\0';
525         return buf;
526 }
527
528
529 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
530                                       const char *txt, size_t len)
531 {
532         struct hostapd_data *hapd = ctx;
533         if (hapd == NULL)
534                 return;
535         hostapd_ctrl_iface_send(hapd, level, txt, len);
536 }
537
538
539 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
540 {
541         struct sockaddr_un addr;
542         int s = -1;
543         char *fname = NULL;
544
545         hapd->ctrl_sock = -1;
546
547         if (hapd->conf->ctrl_interface == NULL)
548                 return 0;
549
550         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
551                 if (errno == EEXIST) {
552                         wpa_printf(MSG_DEBUG, "Using existing control "
553                                    "interface directory.");
554                 } else {
555                         perror("mkdir[ctrl_interface]");
556                         goto fail;
557                 }
558         }
559
560         if (hapd->conf->ctrl_interface_gid_set &&
561             chown(hapd->conf->ctrl_interface, 0,
562                   hapd->conf->ctrl_interface_gid) < 0) {
563                 perror("chown[ctrl_interface]");
564                 return -1;
565         }
566
567         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
568             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
569                 goto fail;
570
571         s = socket(PF_UNIX, SOCK_DGRAM, 0);
572         if (s < 0) {
573                 perror("socket(PF_UNIX)");
574                 goto fail;
575         }
576
577         os_memset(&addr, 0, sizeof(addr));
578 #ifdef __FreeBSD__
579         addr.sun_len = sizeof(addr);
580 #endif /* __FreeBSD__ */
581         addr.sun_family = AF_UNIX;
582         fname = hostapd_ctrl_iface_path(hapd);
583         if (fname == NULL)
584                 goto fail;
585         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
586         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
587                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
588                            strerror(errno));
589                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
590                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
591                                    " allow connections - assuming it was left"
592                                    "over from forced program termination");
593                         if (unlink(fname) < 0) {
594                                 perror("unlink[ctrl_iface]");
595                                 wpa_printf(MSG_ERROR, "Could not unlink "
596                                            "existing ctrl_iface socket '%s'",
597                                            fname);
598                                 goto fail;
599                         }
600                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
601                             0) {
602                                 perror("bind(PF_UNIX)");
603                                 goto fail;
604                         }
605                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
606                                    "ctrl_iface socket '%s'", fname);
607                 } else {
608                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
609                                    "be in use - cannot override it");
610                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
611                                    "not used anymore", fname);
612                         os_free(fname);
613                         fname = NULL;
614                         goto fail;
615                 }
616         }
617
618         if (hapd->conf->ctrl_interface_gid_set &&
619             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
620                 perror("chown[ctrl_interface/ifname]");
621                 goto fail;
622         }
623
624         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
625                 perror("chmod[ctrl_interface/ifname]");
626                 goto fail;
627         }
628         os_free(fname);
629
630         hapd->ctrl_sock = s;
631         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
632                                  NULL);
633         hapd->msg_ctx = hapd;
634         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
635
636         return 0;
637
638 fail:
639         if (s >= 0)
640                 close(s);
641         if (fname) {
642                 unlink(fname);
643                 os_free(fname);
644         }
645         return -1;
646 }
647
648
649 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
650 {
651         struct wpa_ctrl_dst *dst, *prev;
652
653         if (hapd->ctrl_sock > -1) {
654                 char *fname;
655                 eloop_unregister_read_sock(hapd->ctrl_sock);
656                 close(hapd->ctrl_sock);
657                 hapd->ctrl_sock = -1;
658                 fname = hostapd_ctrl_iface_path(hapd);
659                 if (fname)
660                         unlink(fname);
661                 os_free(fname);
662
663                 if (hapd->conf->ctrl_interface &&
664                     rmdir(hapd->conf->ctrl_interface) < 0) {
665                         if (errno == ENOTEMPTY) {
666                                 wpa_printf(MSG_DEBUG, "Control interface "
667                                            "directory not empty - leaving it "
668                                            "behind");
669                         } else {
670                                 perror("rmdir[ctrl_interface]");
671                         }
672                 }
673         }
674
675         dst = hapd->ctrl_dst;
676         while (dst) {
677                 prev = dst;
678                 dst = dst->next;
679                 os_free(prev);
680         }
681 }
682
683
684 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
685                                     const char *buf, size_t len)
686 {
687         struct wpa_ctrl_dst *dst, *next;
688         struct msghdr msg;
689         int idx;
690         struct iovec io[2];
691         char levelstr[10];
692
693         dst = hapd->ctrl_dst;
694         if (hapd->ctrl_sock < 0 || dst == NULL)
695                 return;
696
697         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
698         io[0].iov_base = levelstr;
699         io[0].iov_len = os_strlen(levelstr);
700         io[1].iov_base = (char *) buf;
701         io[1].iov_len = len;
702         os_memset(&msg, 0, sizeof(msg));
703         msg.msg_iov = io;
704         msg.msg_iovlen = 2;
705
706         idx = 0;
707         while (dst) {
708                 next = dst->next;
709                 if (level >= dst->debug_level) {
710                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
711                                     (u8 *) dst->addr.sun_path, dst->addrlen -
712                                     offsetof(struct sockaddr_un, sun_path));
713                         msg.msg_name = &dst->addr;
714                         msg.msg_namelen = dst->addrlen;
715                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
716                                 int _errno = errno;
717                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
718                                            "%d - %s",
719                                            idx, errno, strerror(errno));
720                                 dst->errors++;
721                                 if (dst->errors > 10 || _errno == ENOENT) {
722                                         hostapd_ctrl_iface_detach(
723                                                 hapd, &dst->addr,
724                                                 dst->addrlen);
725                                 }
726                         } else
727                                 dst->errors = 0;
728                 }
729                 idx++;
730                 dst = next;
731         }
732 }
733
734 #endif /* CONFIG_NATIVE_WINDOWS */