083a097f488fde80861fe1ab7e8f148436ceda20
[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 #ifdef CONFIG_P2P_MANAGER
159 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
160                                   u8 minor_reason_code, const u8 *addr)
161 {
162         struct ieee80211_mgmt *mgmt;
163         int ret;
164         u8 *pos;
165
166         if (hapd->driver->send_frame == NULL)
167                 return -1;
168
169         mgmt = os_zalloc(sizeof(*mgmt) + 100);
170         if (mgmt == NULL)
171                 return -1;
172
173         wpa_printf(MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor "
174                    "reason code %u (stype=%u)",
175                    MAC2STR(addr), minor_reason_code, stype);
176
177         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
178         os_memcpy(mgmt->da, addr, ETH_ALEN);
179         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
180         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
181         if (stype == WLAN_FC_STYPE_DEAUTH) {
182                 mgmt->u.deauth.reason_code =
183                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
184                 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
185         } else {
186                 mgmt->u.disassoc.reason_code =
187                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
188                 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
189         }
190
191         *pos++ = WLAN_EID_VENDOR_SPECIFIC;
192         *pos++ = 4 + 3 + 1;
193         WPA_PUT_BE24(pos, OUI_WFA);
194         pos += 3;
195         *pos++ = P2P_OUI_TYPE;
196
197         *pos++ = P2P_ATTR_MINOR_REASON_CODE;
198         WPA_PUT_LE16(pos, 1);
199         pos += 2;
200         *pos++ = minor_reason_code;
201
202         ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
203                                        pos - (u8 *) mgmt, 1);
204         os_free(mgmt);
205
206         return ret < 0 ? -1 : 0;
207 }
208 #endif /* CONFIG_P2P_MANAGER */
209
210
211 static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
212                                              const char *txtaddr)
213 {
214         u8 addr[ETH_ALEN];
215         struct sta_info *sta;
216         const char *pos;
217
218         wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
219
220         if (hwaddr_aton(txtaddr, addr))
221                 return -1;
222
223         pos = os_strstr(txtaddr, " test=");
224         if (pos) {
225                 struct ieee80211_mgmt mgmt;
226                 int encrypt;
227                 if (hapd->driver->send_frame == NULL)
228                         return -1;
229                 pos += 6;
230                 encrypt = atoi(pos);
231                 os_memset(&mgmt, 0, sizeof(mgmt));
232                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
233                                                   WLAN_FC_STYPE_DEAUTH);
234                 os_memcpy(mgmt.da, addr, ETH_ALEN);
235                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
236                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
237                 mgmt.u.deauth.reason_code =
238                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
239                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
240                                              IEEE80211_HDRLEN +
241                                              sizeof(mgmt.u.deauth),
242                                              encrypt) < 0)
243                         return -1;
244                 return 0;
245         }
246
247 #ifdef CONFIG_P2P_MANAGER
248         pos = os_strstr(txtaddr, " p2p=");
249         if (pos) {
250                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
251                                               atoi(pos + 5), addr);
252         }
253 #endif /* CONFIG_P2P_MANAGER */
254
255         hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
256         sta = ap_get_sta(hapd, addr);
257         if (sta)
258                 ap_sta_deauthenticate(hapd, sta,
259                                       WLAN_REASON_PREV_AUTH_NOT_VALID);
260
261         return 0;
262 }
263
264
265 static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
266                                            const char *txtaddr)
267 {
268         u8 addr[ETH_ALEN];
269         struct sta_info *sta;
270         const char *pos;
271
272         wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
273
274         if (hwaddr_aton(txtaddr, addr))
275                 return -1;
276
277         pos = os_strstr(txtaddr, " test=");
278         if (pos) {
279                 struct ieee80211_mgmt mgmt;
280                 int encrypt;
281                 if (hapd->driver->send_frame == NULL)
282                         return -1;
283                 pos += 6;
284                 encrypt = atoi(pos);
285                 os_memset(&mgmt, 0, sizeof(mgmt));
286                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
287                                                   WLAN_FC_STYPE_DISASSOC);
288                 os_memcpy(mgmt.da, addr, ETH_ALEN);
289                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
290                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
291                 mgmt.u.disassoc.reason_code =
292                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
293                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
294                                              IEEE80211_HDRLEN +
295                                              sizeof(mgmt.u.deauth),
296                                              encrypt) < 0)
297                         return -1;
298                 return 0;
299         }
300
301 #ifdef CONFIG_P2P_MANAGER
302         pos = os_strstr(txtaddr, " p2p=");
303         if (pos) {
304                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
305                                               atoi(pos + 5), addr);
306         }
307 #endif /* CONFIG_P2P_MANAGER */
308
309         hapd->drv.sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
310         sta = ap_get_sta(hapd, addr);
311         if (sta)
312                 ap_sta_disassociate(hapd, sta,
313                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
314
315         return 0;
316 }
317
318
319 #ifdef CONFIG_IEEE80211W
320 #ifdef NEED_AP_MLME
321 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
322                                        const char *txtaddr)
323 {
324         u8 addr[ETH_ALEN];
325         u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
326
327         wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
328
329         if (hwaddr_aton(txtaddr, addr) ||
330             os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
331                 return -1;
332
333         ieee802_11_send_sa_query_req(hapd, addr, trans_id);
334
335         return 0;
336 }
337 #endif /* NEED_AP_MLME */
338 #endif /* CONFIG_IEEE80211W */
339
340
341 #ifdef CONFIG_WPS
342 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
343 {
344         char *pin = os_strchr(txt, ' ');
345         char *timeout_txt;
346         int timeout;
347         u8 addr_buf[ETH_ALEN], *addr = NULL;
348         char *pos;
349
350         if (pin == NULL)
351                 return -1;
352         *pin++ = '\0';
353
354         timeout_txt = os_strchr(pin, ' ');
355         if (timeout_txt) {
356                 *timeout_txt++ = '\0';
357                 timeout = atoi(timeout_txt);
358                 pos = os_strchr(timeout_txt, ' ');
359                 if (pos) {
360                         *pos++ = '\0';
361                         if (hwaddr_aton(pos, addr_buf) == 0)
362                                 addr = addr_buf;
363                 }
364         } else
365                 timeout = 0;
366
367         return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
368 }
369
370
371 #ifdef CONFIG_WPS_OOB
372 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
373 {
374         char *path, *method, *name;
375
376         path = os_strchr(txt, ' ');
377         if (path == NULL)
378                 return -1;
379         *path++ = '\0';
380
381         method = os_strchr(path, ' ');
382         if (method == NULL)
383                 return -1;
384         *method++ = '\0';
385
386         name = os_strchr(method, ' ');
387         if (name != NULL)
388                 *name++ = '\0';
389
390         return hostapd_wps_start_oob(hapd, txt, path, method, name);
391 }
392 #endif /* CONFIG_WPS_OOB */
393
394
395 static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
396                                          char *buf, size_t buflen)
397 {
398         int timeout = 300;
399         char *pos;
400         const char *pin_txt;
401
402         pos = os_strchr(txt, ' ');
403         if (pos)
404                 *pos++ = '\0';
405
406         if (os_strcmp(txt, "disable") == 0) {
407                 hostapd_wps_ap_pin_disable(hapd);
408                 return os_snprintf(buf, buflen, "OK\n");
409         }
410
411         if (os_strcmp(txt, "random") == 0) {
412                 if (pos)
413                         timeout = atoi(pos);
414                 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
415                 if (pin_txt == NULL)
416                         return -1;
417                 return os_snprintf(buf, buflen, "%s", pin_txt);
418         }
419
420         if (os_strcmp(txt, "get") == 0) {
421                 pin_txt = hostapd_wps_ap_pin_get(hapd);
422                 if (pin_txt == NULL)
423                         return -1;
424                 return os_snprintf(buf, buflen, "%s", pin_txt);
425         }
426
427         if (os_strcmp(txt, "set") == 0) {
428                 char *pin;
429                 if (pos == NULL)
430                         return -1;
431                 pin = pos;
432                 pos = os_strchr(pos, ' ');
433                 if (pos) {
434                         *pos++ = '\0';
435                         timeout = atoi(pos);
436                 }
437                 if (os_strlen(pin) > buflen)
438                         return -1;
439                 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
440                         return -1;
441                 return os_snprintf(buf, buflen, "%s", pin);
442         }
443
444         return -1;
445 }
446 #endif /* CONFIG_WPS */
447
448
449 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
450                                        void *sock_ctx)
451 {
452         struct hostapd_data *hapd = eloop_ctx;
453         char buf[256];
454         int res;
455         struct sockaddr_un from;
456         socklen_t fromlen = sizeof(from);
457         char *reply;
458         const int reply_size = 4096;
459         int reply_len;
460
461         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
462                        (struct sockaddr *) &from, &fromlen);
463         if (res < 0) {
464                 perror("recvfrom(ctrl_iface)");
465                 return;
466         }
467         buf[res] = '\0';
468         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
469
470         reply = os_malloc(reply_size);
471         if (reply == NULL) {
472                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
473                        fromlen);
474                 return;
475         }
476
477         os_memcpy(reply, "OK\n", 3);
478         reply_len = 3;
479
480         if (os_strcmp(buf, "PING") == 0) {
481                 os_memcpy(reply, "PONG\n", 5);
482                 reply_len = 5;
483         } else if (os_strcmp(buf, "MIB") == 0) {
484                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
485                 if (reply_len >= 0) {
486                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
487                                           reply_size - reply_len);
488                         if (res < 0)
489                                 reply_len = -1;
490                         else
491                                 reply_len += res;
492                 }
493                 if (reply_len >= 0) {
494                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
495                                                  reply_size - reply_len);
496                         if (res < 0)
497                                 reply_len = -1;
498                         else
499                                 reply_len += res;
500                 }
501 #ifndef CONFIG_NO_RADIUS
502                 if (reply_len >= 0) {
503                         res = radius_client_get_mib(hapd->radius,
504                                                     reply + reply_len,
505                                                     reply_size - reply_len);
506                         if (res < 0)
507                                 reply_len = -1;
508                         else
509                                 reply_len += res;
510                 }
511 #endif /* CONFIG_NO_RADIUS */
512         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
513                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
514                                                          reply_size);
515         } else if (os_strncmp(buf, "STA ", 4) == 0) {
516                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
517                                                    reply_size);
518         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
519                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
520                                                         reply_size);
521         } else if (os_strcmp(buf, "ATTACH") == 0) {
522                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
523                         reply_len = -1;
524         } else if (os_strcmp(buf, "DETACH") == 0) {
525                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
526                         reply_len = -1;
527         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
528                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
529                                                     buf + 6))
530                         reply_len = -1;
531         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
532                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
533                         reply_len = -1;
534         } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
535                 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
536                         reply_len = -1;
537         } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
538                 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
539                         reply_len = -1;
540 #ifdef CONFIG_IEEE80211W
541 #ifdef NEED_AP_MLME
542         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
543                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
544                         reply_len = -1;
545 #endif /* NEED_AP_MLME */
546 #endif /* CONFIG_IEEE80211W */
547 #ifdef CONFIG_WPS
548         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
549                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
550                         reply_len = -1;
551         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
552                 if (hostapd_wps_button_pushed(hapd))
553                         reply_len = -1;
554 #ifdef CONFIG_WPS_OOB
555         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
556                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
557                         reply_len = -1;
558 #endif /* CONFIG_WPS_OOB */
559         } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
560                 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
561                                                           reply, reply_size);
562 #endif /* CONFIG_WPS */
563         } else {
564                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
565                 reply_len = 16;
566         }
567
568         if (reply_len < 0) {
569                 os_memcpy(reply, "FAIL\n", 5);
570                 reply_len = 5;
571         }
572         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
573         os_free(reply);
574 }
575
576
577 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
578 {
579         char *buf;
580         size_t len;
581
582         if (hapd->conf->ctrl_interface == NULL)
583                 return NULL;
584
585         len = os_strlen(hapd->conf->ctrl_interface) +
586                 os_strlen(hapd->conf->iface) + 2;
587         buf = os_malloc(len);
588         if (buf == NULL)
589                 return NULL;
590
591         os_snprintf(buf, len, "%s/%s",
592                     hapd->conf->ctrl_interface, hapd->conf->iface);
593         buf[len - 1] = '\0';
594         return buf;
595 }
596
597
598 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
599                                       const char *txt, size_t len)
600 {
601         struct hostapd_data *hapd = ctx;
602         if (hapd == NULL)
603                 return;
604         hostapd_ctrl_iface_send(hapd, level, txt, len);
605 }
606
607
608 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
609 {
610         struct sockaddr_un addr;
611         int s = -1;
612         char *fname = NULL;
613
614         hapd->ctrl_sock = -1;
615
616         if (hapd->conf->ctrl_interface == NULL)
617                 return 0;
618
619         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
620                 if (errno == EEXIST) {
621                         wpa_printf(MSG_DEBUG, "Using existing control "
622                                    "interface directory.");
623                 } else {
624                         perror("mkdir[ctrl_interface]");
625                         goto fail;
626                 }
627         }
628
629         if (hapd->conf->ctrl_interface_gid_set &&
630             chown(hapd->conf->ctrl_interface, 0,
631                   hapd->conf->ctrl_interface_gid) < 0) {
632                 perror("chown[ctrl_interface]");
633                 return -1;
634         }
635
636         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
637             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
638                 goto fail;
639
640         s = socket(PF_UNIX, SOCK_DGRAM, 0);
641         if (s < 0) {
642                 perror("socket(PF_UNIX)");
643                 goto fail;
644         }
645
646         os_memset(&addr, 0, sizeof(addr));
647 #ifdef __FreeBSD__
648         addr.sun_len = sizeof(addr);
649 #endif /* __FreeBSD__ */
650         addr.sun_family = AF_UNIX;
651         fname = hostapd_ctrl_iface_path(hapd);
652         if (fname == NULL)
653                 goto fail;
654         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
655         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
656                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
657                            strerror(errno));
658                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
659                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
660                                    " allow connections - assuming it was left"
661                                    "over from forced program termination");
662                         if (unlink(fname) < 0) {
663                                 perror("unlink[ctrl_iface]");
664                                 wpa_printf(MSG_ERROR, "Could not unlink "
665                                            "existing ctrl_iface socket '%s'",
666                                            fname);
667                                 goto fail;
668                         }
669                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
670                             0) {
671                                 perror("bind(PF_UNIX)");
672                                 goto fail;
673                         }
674                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
675                                    "ctrl_iface socket '%s'", fname);
676                 } else {
677                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
678                                    "be in use - cannot override it");
679                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
680                                    "not used anymore", fname);
681                         os_free(fname);
682                         fname = NULL;
683                         goto fail;
684                 }
685         }
686
687         if (hapd->conf->ctrl_interface_gid_set &&
688             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
689                 perror("chown[ctrl_interface/ifname]");
690                 goto fail;
691         }
692
693         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
694                 perror("chmod[ctrl_interface/ifname]");
695                 goto fail;
696         }
697         os_free(fname);
698
699         hapd->ctrl_sock = s;
700         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
701                                  NULL);
702         hapd->msg_ctx = hapd;
703         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
704
705         return 0;
706
707 fail:
708         if (s >= 0)
709                 close(s);
710         if (fname) {
711                 unlink(fname);
712                 os_free(fname);
713         }
714         return -1;
715 }
716
717
718 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
719 {
720         struct wpa_ctrl_dst *dst, *prev;
721
722         if (hapd->ctrl_sock > -1) {
723                 char *fname;
724                 eloop_unregister_read_sock(hapd->ctrl_sock);
725                 close(hapd->ctrl_sock);
726                 hapd->ctrl_sock = -1;
727                 fname = hostapd_ctrl_iface_path(hapd);
728                 if (fname)
729                         unlink(fname);
730                 os_free(fname);
731
732                 if (hapd->conf->ctrl_interface &&
733                     rmdir(hapd->conf->ctrl_interface) < 0) {
734                         if (errno == ENOTEMPTY) {
735                                 wpa_printf(MSG_DEBUG, "Control interface "
736                                            "directory not empty - leaving it "
737                                            "behind");
738                         } else {
739                                 perror("rmdir[ctrl_interface]");
740                         }
741                 }
742         }
743
744         dst = hapd->ctrl_dst;
745         while (dst) {
746                 prev = dst;
747                 dst = dst->next;
748                 os_free(prev);
749         }
750 }
751
752
753 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
754                                     const char *buf, size_t len)
755 {
756         struct wpa_ctrl_dst *dst, *next;
757         struct msghdr msg;
758         int idx;
759         struct iovec io[2];
760         char levelstr[10];
761
762         dst = hapd->ctrl_dst;
763         if (hapd->ctrl_sock < 0 || dst == NULL)
764                 return;
765
766         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
767         io[0].iov_base = levelstr;
768         io[0].iov_len = os_strlen(levelstr);
769         io[1].iov_base = (char *) buf;
770         io[1].iov_len = len;
771         os_memset(&msg, 0, sizeof(msg));
772         msg.msg_iov = io;
773         msg.msg_iovlen = 2;
774
775         idx = 0;
776         while (dst) {
777                 next = dst->next;
778                 if (level >= dst->debug_level) {
779                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
780                                     (u8 *) dst->addr.sun_path, dst->addrlen -
781                                     offsetof(struct sockaddr_un, sun_path));
782                         msg.msg_name = &dst->addr;
783                         msg.msg_namelen = dst->addrlen;
784                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
785                                 int _errno = errno;
786                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
787                                            "%d - %s",
788                                            idx, errno, strerror(errno));
789                                 dst->errors++;
790                                 if (dst->errors > 10 || _errno == ENOENT) {
791                                         hostapd_ctrl_iface_detach(
792                                                 hapd, &dst->addr,
793                                                 dst->addrlen);
794                                 }
795                         } else
796                                 dst->errors = 0;
797                 }
798                 idx++;
799                 dst = next;
800         }
801 }
802
803 #endif /* CONFIG_NATIVE_WINDOWS */