]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/wpa/hostapd/ctrl_iface.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / wpa / 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
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 */