7f628f1456b5feaf463ed22aaeb8e1676d190fef
[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 "wps/wps_defs.h"
38 #include "wps/wps.h"
39 #include "ctrl_iface.h"
40
41
42 struct wpa_ctrl_dst {
43         struct wpa_ctrl_dst *next;
44         struct sockaddr_un addr;
45         socklen_t addrlen;
46         int debug_level;
47         int errors;
48 };
49
50
51 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
52                                     const char *buf, size_t len);
53
54
55 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
56                                      struct sockaddr_un *from,
57                                      socklen_t fromlen)
58 {
59         struct wpa_ctrl_dst *dst;
60
61         dst = os_zalloc(sizeof(*dst));
62         if (dst == NULL)
63                 return -1;
64         os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
65         dst->addrlen = fromlen;
66         dst->debug_level = MSG_INFO;
67         dst->next = hapd->ctrl_dst;
68         hapd->ctrl_dst = dst;
69         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
70                     (u8 *) from->sun_path,
71                     fromlen - offsetof(struct sockaddr_un, sun_path));
72         return 0;
73 }
74
75
76 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
77                                      struct sockaddr_un *from,
78                                      socklen_t fromlen)
79 {
80         struct wpa_ctrl_dst *dst, *prev = NULL;
81
82         dst = hapd->ctrl_dst;
83         while (dst) {
84                 if (fromlen == dst->addrlen &&
85                     os_memcmp(from->sun_path, dst->addr.sun_path,
86                               fromlen - offsetof(struct sockaddr_un, sun_path))
87                     == 0) {
88                         if (prev == NULL)
89                                 hapd->ctrl_dst = dst->next;
90                         else
91                                 prev->next = dst->next;
92                         os_free(dst);
93                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
94                                     (u8 *) from->sun_path,
95                                     fromlen -
96                                     offsetof(struct sockaddr_un, sun_path));
97                         return 0;
98                 }
99                 prev = dst;
100                 dst = dst->next;
101         }
102         return -1;
103 }
104
105
106 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
107                                     struct sockaddr_un *from,
108                                     socklen_t fromlen,
109                                     char *level)
110 {
111         struct wpa_ctrl_dst *dst;
112
113         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
114
115         dst = hapd->ctrl_dst;
116         while (dst) {
117                 if (fromlen == dst->addrlen &&
118                     os_memcmp(from->sun_path, dst->addr.sun_path,
119                               fromlen - offsetof(struct sockaddr_un, sun_path))
120                     == 0) {
121                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
122                                     "level", (u8 *) from->sun_path, fromlen -
123                                     offsetof(struct sockaddr_un, sun_path));
124                         dst->debug_level = atoi(level);
125                         return 0;
126                 }
127                 dst = dst->next;
128         }
129
130         return -1;
131 }
132
133
134 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
135                                       const char *txtaddr)
136 {
137         u8 addr[ETH_ALEN];
138         struct sta_info *sta;
139
140         wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
141
142         if (hwaddr_aton(txtaddr, addr))
143                 return -1;
144
145         sta = ap_get_sta(hapd, addr);
146         if (sta)
147                 return 0;
148
149         wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
150                    "notification", MAC2STR(addr));
151         sta = ap_sta_add(hapd, addr);
152         if (sta == NULL)
153                 return -1;
154
155         hostapd_new_assoc_sta(hapd, sta, 0);
156         return 0;
157 }
158
159
160 #ifdef CONFIG_P2P_MANAGER
161 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
162                                   u8 minor_reason_code, const u8 *addr)
163 {
164         struct ieee80211_mgmt *mgmt;
165         int ret;
166         u8 *pos;
167
168         if (hapd->driver->send_frame == NULL)
169                 return -1;
170
171         mgmt = os_zalloc(sizeof(*mgmt) + 100);
172         if (mgmt == NULL)
173                 return -1;
174
175         wpa_printf(MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor "
176                    "reason code %u (stype=%u)",
177                    MAC2STR(addr), minor_reason_code, stype);
178
179         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
180         os_memcpy(mgmt->da, addr, ETH_ALEN);
181         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
182         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
183         if (stype == WLAN_FC_STYPE_DEAUTH) {
184                 mgmt->u.deauth.reason_code =
185                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
186                 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
187         } else {
188                 mgmt->u.disassoc.reason_code =
189                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
190                 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
191         }
192
193         *pos++ = WLAN_EID_VENDOR_SPECIFIC;
194         *pos++ = 4 + 3 + 1;
195         WPA_PUT_BE24(pos, OUI_WFA);
196         pos += 3;
197         *pos++ = P2P_OUI_TYPE;
198
199         *pos++ = P2P_ATTR_MINOR_REASON_CODE;
200         WPA_PUT_LE16(pos, 1);
201         pos += 2;
202         *pos++ = minor_reason_code;
203
204         ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
205                                        pos - (u8 *) mgmt, 1);
206         os_free(mgmt);
207
208         return ret < 0 ? -1 : 0;
209 }
210 #endif /* CONFIG_P2P_MANAGER */
211
212
213 static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
214                                              const char *txtaddr)
215 {
216         u8 addr[ETH_ALEN];
217         struct sta_info *sta;
218         const char *pos;
219
220         wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
221
222         if (hwaddr_aton(txtaddr, addr))
223                 return -1;
224
225         pos = os_strstr(txtaddr, " test=");
226         if (pos) {
227                 struct ieee80211_mgmt mgmt;
228                 int encrypt;
229                 if (hapd->driver->send_frame == NULL)
230                         return -1;
231                 pos += 6;
232                 encrypt = atoi(pos);
233                 os_memset(&mgmt, 0, sizeof(mgmt));
234                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
235                                                   WLAN_FC_STYPE_DEAUTH);
236                 os_memcpy(mgmt.da, addr, ETH_ALEN);
237                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
238                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
239                 mgmt.u.deauth.reason_code =
240                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
241                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
242                                              IEEE80211_HDRLEN +
243                                              sizeof(mgmt.u.deauth),
244                                              encrypt) < 0)
245                         return -1;
246                 return 0;
247         }
248
249 #ifdef CONFIG_P2P_MANAGER
250         pos = os_strstr(txtaddr, " p2p=");
251         if (pos) {
252                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
253                                               atoi(pos + 5), addr);
254         }
255 #endif /* CONFIG_P2P_MANAGER */
256
257         hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
258         sta = ap_get_sta(hapd, addr);
259         if (sta)
260                 ap_sta_deauthenticate(hapd, sta,
261                                       WLAN_REASON_PREV_AUTH_NOT_VALID);
262
263         return 0;
264 }
265
266
267 static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
268                                            const char *txtaddr)
269 {
270         u8 addr[ETH_ALEN];
271         struct sta_info *sta;
272         const char *pos;
273
274         wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
275
276         if (hwaddr_aton(txtaddr, addr))
277                 return -1;
278
279         pos = os_strstr(txtaddr, " test=");
280         if (pos) {
281                 struct ieee80211_mgmt mgmt;
282                 int encrypt;
283                 if (hapd->driver->send_frame == NULL)
284                         return -1;
285                 pos += 6;
286                 encrypt = atoi(pos);
287                 os_memset(&mgmt, 0, sizeof(mgmt));
288                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
289                                                   WLAN_FC_STYPE_DISASSOC);
290                 os_memcpy(mgmt.da, addr, ETH_ALEN);
291                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
292                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
293                 mgmt.u.disassoc.reason_code =
294                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
295                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
296                                              IEEE80211_HDRLEN +
297                                              sizeof(mgmt.u.deauth),
298                                              encrypt) < 0)
299                         return -1;
300                 return 0;
301         }
302
303 #ifdef CONFIG_P2P_MANAGER
304         pos = os_strstr(txtaddr, " p2p=");
305         if (pos) {
306                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
307                                               atoi(pos + 5), addr);
308         }
309 #endif /* CONFIG_P2P_MANAGER */
310
311         hapd->drv.sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
312         sta = ap_get_sta(hapd, addr);
313         if (sta)
314                 ap_sta_disassociate(hapd, sta,
315                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
316
317         return 0;
318 }
319
320
321 #ifdef CONFIG_IEEE80211W
322 #ifdef NEED_AP_MLME
323 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
324                                        const char *txtaddr)
325 {
326         u8 addr[ETH_ALEN];
327         u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
328
329         wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
330
331         if (hwaddr_aton(txtaddr, addr) ||
332             os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
333                 return -1;
334
335         ieee802_11_send_sa_query_req(hapd, addr, trans_id);
336
337         return 0;
338 }
339 #endif /* NEED_AP_MLME */
340 #endif /* CONFIG_IEEE80211W */
341
342
343 #ifdef CONFIG_WPS
344 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
345 {
346         char *pin = os_strchr(txt, ' ');
347         char *timeout_txt;
348         int timeout;
349         u8 addr_buf[ETH_ALEN], *addr = NULL;
350         char *pos;
351
352         if (pin == NULL)
353                 return -1;
354         *pin++ = '\0';
355
356         timeout_txt = os_strchr(pin, ' ');
357         if (timeout_txt) {
358                 *timeout_txt++ = '\0';
359                 timeout = atoi(timeout_txt);
360                 pos = os_strchr(timeout_txt, ' ');
361                 if (pos) {
362                         *pos++ = '\0';
363                         if (hwaddr_aton(pos, addr_buf) == 0)
364                                 addr = addr_buf;
365                 }
366         } else
367                 timeout = 0;
368
369         return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
370 }
371
372
373 static int hostapd_ctrl_iface_wps_check_pin(
374         struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
375 {
376         char pin[9];
377         size_t len;
378         char *pos;
379         int ret;
380
381         wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
382                               (u8 *) cmd, os_strlen(cmd));
383         for (pos = cmd, len = 0; *pos != '\0'; pos++) {
384                 if (*pos < '0' || *pos > '9')
385                         continue;
386                 pin[len++] = *pos;
387                 if (len == 9) {
388                         wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
389                         return -1;
390                 }
391         }
392         if (len != 4 && len != 8) {
393                 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
394                 return -1;
395         }
396         pin[len] = '\0';
397
398         if (len == 8) {
399                 unsigned int pin_val;
400                 pin_val = atoi(pin);
401                 if (!wps_pin_valid(pin_val)) {
402                         wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
403                         ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
404                         if (ret < 0 || (size_t) ret >= buflen)
405                                 return -1;
406                         return ret;
407                 }
408         }
409
410         ret = os_snprintf(buf, buflen, "%s", pin);
411         if (ret < 0 || (size_t) ret >= buflen)
412                 return -1;
413
414         return ret;
415 }
416
417
418 #ifdef CONFIG_WPS_OOB
419 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
420 {
421         char *path, *method, *name;
422
423         path = os_strchr(txt, ' ');
424         if (path == NULL)
425                 return -1;
426         *path++ = '\0';
427
428         method = os_strchr(path, ' ');
429         if (method == NULL)
430                 return -1;
431         *method++ = '\0';
432
433         name = os_strchr(method, ' ');
434         if (name != NULL)
435                 *name++ = '\0';
436
437         return hostapd_wps_start_oob(hapd, txt, path, method, name);
438 }
439 #endif /* CONFIG_WPS_OOB */
440
441
442 static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
443                                          char *buf, size_t buflen)
444 {
445         int timeout = 300;
446         char *pos;
447         const char *pin_txt;
448
449         pos = os_strchr(txt, ' ');
450         if (pos)
451                 *pos++ = '\0';
452
453         if (os_strcmp(txt, "disable") == 0) {
454                 hostapd_wps_ap_pin_disable(hapd);
455                 return os_snprintf(buf, buflen, "OK\n");
456         }
457
458         if (os_strcmp(txt, "random") == 0) {
459                 if (pos)
460                         timeout = atoi(pos);
461                 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
462                 if (pin_txt == NULL)
463                         return -1;
464                 return os_snprintf(buf, buflen, "%s", pin_txt);
465         }
466
467         if (os_strcmp(txt, "get") == 0) {
468                 pin_txt = hostapd_wps_ap_pin_get(hapd);
469                 if (pin_txt == NULL)
470                         return -1;
471                 return os_snprintf(buf, buflen, "%s", pin_txt);
472         }
473
474         if (os_strcmp(txt, "set") == 0) {
475                 char *pin;
476                 if (pos == NULL)
477                         return -1;
478                 pin = pos;
479                 pos = os_strchr(pos, ' ');
480                 if (pos) {
481                         *pos++ = '\0';
482                         timeout = atoi(pos);
483                 }
484                 if (os_strlen(pin) > buflen)
485                         return -1;
486                 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
487                         return -1;
488                 return os_snprintf(buf, buflen, "%s", pin);
489         }
490
491         return -1;
492 }
493 #endif /* CONFIG_WPS */
494
495
496 static int hostapd_ctrl_iface_set(struct hostapd_data *wpa_s, char *cmd)
497 {
498         char *value;
499         int ret = 0;
500
501         value = os_strchr(cmd, ' ');
502         if (value == NULL)
503                 return -1;
504         *value++ = '\0';
505
506         wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
507         if (0) {
508 #ifdef CONFIG_WPS_TESTING
509         } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
510                 long int val;
511                 val = strtol(value, NULL, 0);
512                 if (val < 0 || val > 0xff) {
513                         ret = -1;
514                         wpa_printf(MSG_DEBUG, "WPS: Invalid "
515                                    "wps_version_number %ld", val);
516                 } else {
517                         wps_version_number = val;
518                         wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
519                                    "version %u.%u",
520                                    (wps_version_number & 0xf0) >> 4,
521                                    wps_version_number & 0x0f);
522                 }
523         } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
524                 wps_testing_dummy_cred = atoi(value);
525                 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
526                            wps_testing_dummy_cred);
527 #endif /* CONFIG_WPS_TESTING */
528         } else {
529                 ret = -1;
530         }
531
532         return ret;
533 }
534
535
536 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
537                                        void *sock_ctx)
538 {
539         struct hostapd_data *hapd = eloop_ctx;
540         char buf[256];
541         int res;
542         struct sockaddr_un from;
543         socklen_t fromlen = sizeof(from);
544         char *reply;
545         const int reply_size = 4096;
546         int reply_len;
547
548         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
549                        (struct sockaddr *) &from, &fromlen);
550         if (res < 0) {
551                 perror("recvfrom(ctrl_iface)");
552                 return;
553         }
554         buf[res] = '\0';
555         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
556
557         reply = os_malloc(reply_size);
558         if (reply == NULL) {
559                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
560                        fromlen);
561                 return;
562         }
563
564         os_memcpy(reply, "OK\n", 3);
565         reply_len = 3;
566
567         if (os_strcmp(buf, "PING") == 0) {
568                 os_memcpy(reply, "PONG\n", 5);
569                 reply_len = 5;
570         } else if (os_strcmp(buf, "MIB") == 0) {
571                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
572                 if (reply_len >= 0) {
573                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
574                                           reply_size - reply_len);
575                         if (res < 0)
576                                 reply_len = -1;
577                         else
578                                 reply_len += res;
579                 }
580                 if (reply_len >= 0) {
581                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
582                                                  reply_size - reply_len);
583                         if (res < 0)
584                                 reply_len = -1;
585                         else
586                                 reply_len += res;
587                 }
588 #ifndef CONFIG_NO_RADIUS
589                 if (reply_len >= 0) {
590                         res = radius_client_get_mib(hapd->radius,
591                                                     reply + reply_len,
592                                                     reply_size - reply_len);
593                         if (res < 0)
594                                 reply_len = -1;
595                         else
596                                 reply_len += res;
597                 }
598 #endif /* CONFIG_NO_RADIUS */
599         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
600                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
601                                                          reply_size);
602         } else if (os_strncmp(buf, "STA ", 4) == 0) {
603                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
604                                                    reply_size);
605         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
606                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
607                                                         reply_size);
608         } else if (os_strcmp(buf, "ATTACH") == 0) {
609                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
610                         reply_len = -1;
611         } else if (os_strcmp(buf, "DETACH") == 0) {
612                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
613                         reply_len = -1;
614         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
615                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
616                                                     buf + 6))
617                         reply_len = -1;
618         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
619                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
620                         reply_len = -1;
621         } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
622                 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
623                         reply_len = -1;
624         } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
625                 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
626                         reply_len = -1;
627 #ifdef CONFIG_IEEE80211W
628 #ifdef NEED_AP_MLME
629         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
630                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
631                         reply_len = -1;
632 #endif /* NEED_AP_MLME */
633 #endif /* CONFIG_IEEE80211W */
634 #ifdef CONFIG_WPS
635         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
636                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
637                         reply_len = -1;
638         } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
639                 reply_len = hostapd_ctrl_iface_wps_check_pin(
640                         hapd, buf + 14, reply, reply_size);
641         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
642                 if (hostapd_wps_button_pushed(hapd))
643                         reply_len = -1;
644 #ifdef CONFIG_WPS_OOB
645         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
646                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
647                         reply_len = -1;
648 #endif /* CONFIG_WPS_OOB */
649         } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
650                 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
651                                                           reply, reply_size);
652 #endif /* CONFIG_WPS */
653         } else if (os_strncmp(buf, "SET ", 4) == 0) {
654                 if (hostapd_ctrl_iface_set(hapd, buf + 4))
655                         reply_len = -1;
656         } else {
657                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
658                 reply_len = 16;
659         }
660
661         if (reply_len < 0) {
662                 os_memcpy(reply, "FAIL\n", 5);
663                 reply_len = 5;
664         }
665         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
666         os_free(reply);
667 }
668
669
670 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
671 {
672         char *buf;
673         size_t len;
674
675         if (hapd->conf->ctrl_interface == NULL)
676                 return NULL;
677
678         len = os_strlen(hapd->conf->ctrl_interface) +
679                 os_strlen(hapd->conf->iface) + 2;
680         buf = os_malloc(len);
681         if (buf == NULL)
682                 return NULL;
683
684         os_snprintf(buf, len, "%s/%s",
685                     hapd->conf->ctrl_interface, hapd->conf->iface);
686         buf[len - 1] = '\0';
687         return buf;
688 }
689
690
691 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
692                                       const char *txt, size_t len)
693 {
694         struct hostapd_data *hapd = ctx;
695         if (hapd == NULL)
696                 return;
697         hostapd_ctrl_iface_send(hapd, level, txt, len);
698 }
699
700
701 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
702 {
703         struct sockaddr_un addr;
704         int s = -1;
705         char *fname = NULL;
706
707         hapd->ctrl_sock = -1;
708
709         if (hapd->conf->ctrl_interface == NULL)
710                 return 0;
711
712         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
713                 if (errno == EEXIST) {
714                         wpa_printf(MSG_DEBUG, "Using existing control "
715                                    "interface directory.");
716                 } else {
717                         perror("mkdir[ctrl_interface]");
718                         goto fail;
719                 }
720         }
721
722         if (hapd->conf->ctrl_interface_gid_set &&
723             chown(hapd->conf->ctrl_interface, 0,
724                   hapd->conf->ctrl_interface_gid) < 0) {
725                 perror("chown[ctrl_interface]");
726                 return -1;
727         }
728
729         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
730             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
731                 goto fail;
732
733         s = socket(PF_UNIX, SOCK_DGRAM, 0);
734         if (s < 0) {
735                 perror("socket(PF_UNIX)");
736                 goto fail;
737         }
738
739         os_memset(&addr, 0, sizeof(addr));
740 #ifdef __FreeBSD__
741         addr.sun_len = sizeof(addr);
742 #endif /* __FreeBSD__ */
743         addr.sun_family = AF_UNIX;
744         fname = hostapd_ctrl_iface_path(hapd);
745         if (fname == NULL)
746                 goto fail;
747         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
748         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
749                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
750                            strerror(errno));
751                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
752                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
753                                    " allow connections - assuming it was left"
754                                    "over from forced program termination");
755                         if (unlink(fname) < 0) {
756                                 perror("unlink[ctrl_iface]");
757                                 wpa_printf(MSG_ERROR, "Could not unlink "
758                                            "existing ctrl_iface socket '%s'",
759                                            fname);
760                                 goto fail;
761                         }
762                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
763                             0) {
764                                 perror("bind(PF_UNIX)");
765                                 goto fail;
766                         }
767                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
768                                    "ctrl_iface socket '%s'", fname);
769                 } else {
770                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
771                                    "be in use - cannot override it");
772                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
773                                    "not used anymore", fname);
774                         os_free(fname);
775                         fname = NULL;
776                         goto fail;
777                 }
778         }
779
780         if (hapd->conf->ctrl_interface_gid_set &&
781             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
782                 perror("chown[ctrl_interface/ifname]");
783                 goto fail;
784         }
785
786         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
787                 perror("chmod[ctrl_interface/ifname]");
788                 goto fail;
789         }
790         os_free(fname);
791
792         hapd->ctrl_sock = s;
793         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
794                                  NULL);
795         hapd->msg_ctx = hapd;
796         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
797
798         return 0;
799
800 fail:
801         if (s >= 0)
802                 close(s);
803         if (fname) {
804                 unlink(fname);
805                 os_free(fname);
806         }
807         return -1;
808 }
809
810
811 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
812 {
813         struct wpa_ctrl_dst *dst, *prev;
814
815         if (hapd->ctrl_sock > -1) {
816                 char *fname;
817                 eloop_unregister_read_sock(hapd->ctrl_sock);
818                 close(hapd->ctrl_sock);
819                 hapd->ctrl_sock = -1;
820                 fname = hostapd_ctrl_iface_path(hapd);
821                 if (fname)
822                         unlink(fname);
823                 os_free(fname);
824
825                 if (hapd->conf->ctrl_interface &&
826                     rmdir(hapd->conf->ctrl_interface) < 0) {
827                         if (errno == ENOTEMPTY) {
828                                 wpa_printf(MSG_DEBUG, "Control interface "
829                                            "directory not empty - leaving it "
830                                            "behind");
831                         } else {
832                                 perror("rmdir[ctrl_interface]");
833                         }
834                 }
835         }
836
837         dst = hapd->ctrl_dst;
838         while (dst) {
839                 prev = dst;
840                 dst = dst->next;
841                 os_free(prev);
842         }
843 }
844
845
846 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
847                                     const char *buf, size_t len)
848 {
849         struct wpa_ctrl_dst *dst, *next;
850         struct msghdr msg;
851         int idx;
852         struct iovec io[2];
853         char levelstr[10];
854
855         dst = hapd->ctrl_dst;
856         if (hapd->ctrl_sock < 0 || dst == NULL)
857                 return;
858
859         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
860         io[0].iov_base = levelstr;
861         io[0].iov_len = os_strlen(levelstr);
862         io[1].iov_base = (char *) buf;
863         io[1].iov_len = len;
864         os_memset(&msg, 0, sizeof(msg));
865         msg.msg_iov = io;
866         msg.msg_iovlen = 2;
867
868         idx = 0;
869         while (dst) {
870                 next = dst->next;
871                 if (level >= dst->debug_level) {
872                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
873                                     (u8 *) dst->addr.sun_path, dst->addrlen -
874                                     offsetof(struct sockaddr_un, sun_path));
875                         msg.msg_name = &dst->addr;
876                         msg.msg_namelen = dst->addrlen;
877                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
878                                 int _errno = errno;
879                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
880                                            "%d - %s",
881                                            idx, errno, strerror(errno));
882                                 dst->errors++;
883                                 if (dst->errors > 10 || _errno == ENOENT) {
884                                         hostapd_ctrl_iface_detach(
885                                                 hapd, &dst->addr,
886                                                 dst->addrlen);
887                                 }
888                         } else
889                                 dst->errors = 0;
890                 }
891                 idx++;
892                 dst = next;
893         }
894 }
895
896 #endif /* CONFIG_NATIVE_WINDOWS */