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