WPS: Add hostapd_cli get_config command
[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_get_config(struct hostapd_data *hapd,
497                                          char *buf, size_t buflen)
498 {
499         int ret;
500         char *pos, *end;
501
502         pos = buf;
503         end = buf + buflen;
504
505         ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
506                           "ssid=%s\n",
507                           MAC2STR(hapd->own_addr),
508                           hapd->conf->ssid.ssid);
509         if (ret < 0 || ret >= end - pos)
510                 return pos - buf;
511         pos += ret;
512
513 #ifdef CONFIG_WPS
514         ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
515                           hapd->conf->wps_state == 0 ? "disabled" :
516                           (hapd->conf->wps_state == 1 ? "not configured" :
517                            "configured"));
518         if (ret < 0 || ret >= end - pos)
519                 return pos - buf;
520         pos += ret;
521
522         if (hapd->conf->wps_state &&
523             hapd->conf->ssid.wpa_passphrase) {
524                 ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
525                                   hapd->conf->ssid.wpa_passphrase);
526                 if (ret < 0 || ret >= end - pos)
527                         return pos - buf;
528                 pos += ret;
529         }
530
531         if (hapd->conf->wps_state && hapd->conf->ssid.wpa_psk &&
532             hapd->conf->ssid.wpa_psk->group) {
533                 char hex[PMK_LEN * 2 + 1];
534                 wpa_snprintf_hex(hex, sizeof(hex),
535                                  hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
536                 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
537                 if (ret < 0 || ret >= end - pos)
538                         return pos - buf;
539                 pos += ret;
540         }
541 #endif /* CONFIG_WPS */
542
543         if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
544                 ret = os_snprintf(pos, end - pos, "key_mgmt=");
545                 if (ret < 0 || ret >= end - pos)
546                         return pos - buf;
547                 pos += ret;
548
549                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
550                         ret = os_snprintf(pos, end - pos, "WPA-PSK ");
551                         if (ret < 0 || ret >= end - pos)
552                                 return pos - buf;
553                         pos += ret;
554                 }
555                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
556                         ret = os_snprintf(pos, end - pos, "WPA-EAP ");
557                         if (ret < 0 || ret >= end - pos)
558                                 return pos - buf;
559                         pos += ret;
560                 }
561 #ifdef CONFIG_IEEE80211R
562                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
563                         ret = os_snprintf(pos, end - pos, "FT-PSK ");
564                         if (ret < 0 || ret >= end - pos)
565                                 return pos - buf;
566                         pos += ret;
567                 }
568                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
569                         ret = os_snprintf(pos, end - pos, "FT-EAP ");
570                         if (ret < 0 || ret >= end - pos)
571                                 return pos - buf;
572                         pos += ret;
573                 }
574 #endif /* CONFIG_IEEE80211R */
575 #ifdef CONFIG_IEEE80211W
576                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
577                         ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
578                         if (ret < 0 || ret >= end - pos)
579                                 return pos - buf;
580                         pos += ret;
581                 }
582                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
583                         ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
584                         if (ret < 0 || ret >= end - pos)
585                                 return pos - buf;
586                         pos += ret;
587                 }
588 #endif /* CONFIG_IEEE80211W */
589
590                 ret = os_snprintf(pos, end - pos, "\n");
591                 if (ret < 0 || ret >= end - pos)
592                         return pos - buf;
593                 pos += ret;
594         }
595
596         if (hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
597                 ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
598                 if (ret < 0 || ret >= end - pos)
599                         return pos - buf;
600                 pos += ret;
601         } else if (hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
602                 ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
603                 if (ret < 0 || ret >= end - pos)
604                         return pos - buf;
605                 pos += ret;
606         }
607
608         if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
609                 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
610                 if (ret < 0 || ret >= end - pos)
611                         return pos - buf;
612                 pos += ret;
613
614                 if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
615                         ret = os_snprintf(pos, end - pos, "CCMP ");
616                         if (ret < 0 || ret >= end - pos)
617                                 return pos - buf;
618                         pos += ret;
619                 }
620                 if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
621                         ret = os_snprintf(pos, end - pos, "TKIP ");
622                         if (ret < 0 || ret >= end - pos)
623                                 return pos - buf;
624                         pos += ret;
625                 }
626
627                 ret = os_snprintf(pos, end - pos, "\n");
628                 if (ret < 0 || ret >= end - pos)
629                         return pos - buf;
630                 pos += ret;
631         }
632
633         if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
634                 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
635                 if (ret < 0 || ret >= end - pos)
636                         return pos - buf;
637                 pos += ret;
638
639                 if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
640                         ret = os_snprintf(pos, end - pos, "CCMP ");
641                         if (ret < 0 || ret >= end - pos)
642                                 return pos - buf;
643                         pos += ret;
644                 }
645                 if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
646                         ret = os_snprintf(pos, end - pos, "TKIP ");
647                         if (ret < 0 || ret >= end - pos)
648                                 return pos - buf;
649                         pos += ret;
650                 }
651
652                 ret = os_snprintf(pos, end - pos, "\n");
653                 if (ret < 0 || ret >= end - pos)
654                         return pos - buf;
655                 pos += ret;
656         }
657
658         return pos - buf;
659 }
660
661
662 static int hostapd_ctrl_iface_set(struct hostapd_data *wpa_s, char *cmd)
663 {
664         char *value;
665         int ret = 0;
666
667         value = os_strchr(cmd, ' ');
668         if (value == NULL)
669                 return -1;
670         *value++ = '\0';
671
672         wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
673         if (0) {
674 #ifdef CONFIG_WPS_TESTING
675         } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
676                 long int val;
677                 val = strtol(value, NULL, 0);
678                 if (val < 0 || val > 0xff) {
679                         ret = -1;
680                         wpa_printf(MSG_DEBUG, "WPS: Invalid "
681                                    "wps_version_number %ld", val);
682                 } else {
683                         wps_version_number = val;
684                         wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
685                                    "version %u.%u",
686                                    (wps_version_number & 0xf0) >> 4,
687                                    wps_version_number & 0x0f);
688                 }
689         } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
690                 wps_testing_dummy_cred = atoi(value);
691                 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
692                            wps_testing_dummy_cred);
693 #endif /* CONFIG_WPS_TESTING */
694         } else {
695                 ret = -1;
696         }
697
698         return ret;
699 }
700
701
702 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
703                                        void *sock_ctx)
704 {
705         struct hostapd_data *hapd = eloop_ctx;
706         char buf[256];
707         int res;
708         struct sockaddr_un from;
709         socklen_t fromlen = sizeof(from);
710         char *reply;
711         const int reply_size = 4096;
712         int reply_len;
713
714         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
715                        (struct sockaddr *) &from, &fromlen);
716         if (res < 0) {
717                 perror("recvfrom(ctrl_iface)");
718                 return;
719         }
720         buf[res] = '\0';
721         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
722
723         reply = os_malloc(reply_size);
724         if (reply == NULL) {
725                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
726                        fromlen);
727                 return;
728         }
729
730         os_memcpy(reply, "OK\n", 3);
731         reply_len = 3;
732
733         if (os_strcmp(buf, "PING") == 0) {
734                 os_memcpy(reply, "PONG\n", 5);
735                 reply_len = 5;
736         } else if (os_strcmp(buf, "MIB") == 0) {
737                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
738                 if (reply_len >= 0) {
739                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
740                                           reply_size - reply_len);
741                         if (res < 0)
742                                 reply_len = -1;
743                         else
744                                 reply_len += res;
745                 }
746                 if (reply_len >= 0) {
747                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
748                                                  reply_size - reply_len);
749                         if (res < 0)
750                                 reply_len = -1;
751                         else
752                                 reply_len += res;
753                 }
754 #ifndef CONFIG_NO_RADIUS
755                 if (reply_len >= 0) {
756                         res = radius_client_get_mib(hapd->radius,
757                                                     reply + reply_len,
758                                                     reply_size - reply_len);
759                         if (res < 0)
760                                 reply_len = -1;
761                         else
762                                 reply_len += res;
763                 }
764 #endif /* CONFIG_NO_RADIUS */
765         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
766                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
767                                                          reply_size);
768         } else if (os_strncmp(buf, "STA ", 4) == 0) {
769                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
770                                                    reply_size);
771         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
772                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
773                                                         reply_size);
774         } else if (os_strcmp(buf, "ATTACH") == 0) {
775                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
776                         reply_len = -1;
777         } else if (os_strcmp(buf, "DETACH") == 0) {
778                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
779                         reply_len = -1;
780         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
781                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
782                                                     buf + 6))
783                         reply_len = -1;
784         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
785                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
786                         reply_len = -1;
787         } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
788                 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
789                         reply_len = -1;
790         } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
791                 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
792                         reply_len = -1;
793 #ifdef CONFIG_IEEE80211W
794 #ifdef NEED_AP_MLME
795         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
796                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
797                         reply_len = -1;
798 #endif /* NEED_AP_MLME */
799 #endif /* CONFIG_IEEE80211W */
800 #ifdef CONFIG_WPS
801         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
802                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
803                         reply_len = -1;
804         } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
805                 reply_len = hostapd_ctrl_iface_wps_check_pin(
806                         hapd, buf + 14, reply, reply_size);
807         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
808                 if (hostapd_wps_button_pushed(hapd))
809                         reply_len = -1;
810 #ifdef CONFIG_WPS_OOB
811         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
812                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
813                         reply_len = -1;
814 #endif /* CONFIG_WPS_OOB */
815         } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
816                 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
817                                                           reply, reply_size);
818 #endif /* CONFIG_WPS */
819         } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
820                 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
821                                                           reply_size);
822         } else if (os_strncmp(buf, "SET ", 4) == 0) {
823                 if (hostapd_ctrl_iface_set(hapd, buf + 4))
824                         reply_len = -1;
825         } else {
826                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
827                 reply_len = 16;
828         }
829
830         if (reply_len < 0) {
831                 os_memcpy(reply, "FAIL\n", 5);
832                 reply_len = 5;
833         }
834         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
835         os_free(reply);
836 }
837
838
839 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
840 {
841         char *buf;
842         size_t len;
843
844         if (hapd->conf->ctrl_interface == NULL)
845                 return NULL;
846
847         len = os_strlen(hapd->conf->ctrl_interface) +
848                 os_strlen(hapd->conf->iface) + 2;
849         buf = os_malloc(len);
850         if (buf == NULL)
851                 return NULL;
852
853         os_snprintf(buf, len, "%s/%s",
854                     hapd->conf->ctrl_interface, hapd->conf->iface);
855         buf[len - 1] = '\0';
856         return buf;
857 }
858
859
860 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
861                                       const char *txt, size_t len)
862 {
863         struct hostapd_data *hapd = ctx;
864         if (hapd == NULL)
865                 return;
866         hostapd_ctrl_iface_send(hapd, level, txt, len);
867 }
868
869
870 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
871 {
872         struct sockaddr_un addr;
873         int s = -1;
874         char *fname = NULL;
875
876         hapd->ctrl_sock = -1;
877
878         if (hapd->conf->ctrl_interface == NULL)
879                 return 0;
880
881         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
882                 if (errno == EEXIST) {
883                         wpa_printf(MSG_DEBUG, "Using existing control "
884                                    "interface directory.");
885                 } else {
886                         perror("mkdir[ctrl_interface]");
887                         goto fail;
888                 }
889         }
890
891         if (hapd->conf->ctrl_interface_gid_set &&
892             chown(hapd->conf->ctrl_interface, 0,
893                   hapd->conf->ctrl_interface_gid) < 0) {
894                 perror("chown[ctrl_interface]");
895                 return -1;
896         }
897
898         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
899             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
900                 goto fail;
901
902         s = socket(PF_UNIX, SOCK_DGRAM, 0);
903         if (s < 0) {
904                 perror("socket(PF_UNIX)");
905                 goto fail;
906         }
907
908         os_memset(&addr, 0, sizeof(addr));
909 #ifdef __FreeBSD__
910         addr.sun_len = sizeof(addr);
911 #endif /* __FreeBSD__ */
912         addr.sun_family = AF_UNIX;
913         fname = hostapd_ctrl_iface_path(hapd);
914         if (fname == NULL)
915                 goto fail;
916         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
917         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
918                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
919                            strerror(errno));
920                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
921                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
922                                    " allow connections - assuming it was left"
923                                    "over from forced program termination");
924                         if (unlink(fname) < 0) {
925                                 perror("unlink[ctrl_iface]");
926                                 wpa_printf(MSG_ERROR, "Could not unlink "
927                                            "existing ctrl_iface socket '%s'",
928                                            fname);
929                                 goto fail;
930                         }
931                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
932                             0) {
933                                 perror("bind(PF_UNIX)");
934                                 goto fail;
935                         }
936                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
937                                    "ctrl_iface socket '%s'", fname);
938                 } else {
939                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
940                                    "be in use - cannot override it");
941                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
942                                    "not used anymore", fname);
943                         os_free(fname);
944                         fname = NULL;
945                         goto fail;
946                 }
947         }
948
949         if (hapd->conf->ctrl_interface_gid_set &&
950             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
951                 perror("chown[ctrl_interface/ifname]");
952                 goto fail;
953         }
954
955         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
956                 perror("chmod[ctrl_interface/ifname]");
957                 goto fail;
958         }
959         os_free(fname);
960
961         hapd->ctrl_sock = s;
962         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
963                                  NULL);
964         hapd->msg_ctx = hapd;
965         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
966
967         return 0;
968
969 fail:
970         if (s >= 0)
971                 close(s);
972         if (fname) {
973                 unlink(fname);
974                 os_free(fname);
975         }
976         return -1;
977 }
978
979
980 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
981 {
982         struct wpa_ctrl_dst *dst, *prev;
983
984         if (hapd->ctrl_sock > -1) {
985                 char *fname;
986                 eloop_unregister_read_sock(hapd->ctrl_sock);
987                 close(hapd->ctrl_sock);
988                 hapd->ctrl_sock = -1;
989                 fname = hostapd_ctrl_iface_path(hapd);
990                 if (fname)
991                         unlink(fname);
992                 os_free(fname);
993
994                 if (hapd->conf->ctrl_interface &&
995                     rmdir(hapd->conf->ctrl_interface) < 0) {
996                         if (errno == ENOTEMPTY) {
997                                 wpa_printf(MSG_DEBUG, "Control interface "
998                                            "directory not empty - leaving it "
999                                            "behind");
1000                         } else {
1001                                 perror("rmdir[ctrl_interface]");
1002                         }
1003                 }
1004         }
1005
1006         dst = hapd->ctrl_dst;
1007         while (dst) {
1008                 prev = dst;
1009                 dst = dst->next;
1010                 os_free(prev);
1011         }
1012 }
1013
1014
1015 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1016                                     const char *buf, size_t len)
1017 {
1018         struct wpa_ctrl_dst *dst, *next;
1019         struct msghdr msg;
1020         int idx;
1021         struct iovec io[2];
1022         char levelstr[10];
1023
1024         dst = hapd->ctrl_dst;
1025         if (hapd->ctrl_sock < 0 || dst == NULL)
1026                 return;
1027
1028         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1029         io[0].iov_base = levelstr;
1030         io[0].iov_len = os_strlen(levelstr);
1031         io[1].iov_base = (char *) buf;
1032         io[1].iov_len = len;
1033         os_memset(&msg, 0, sizeof(msg));
1034         msg.msg_iov = io;
1035         msg.msg_iovlen = 2;
1036
1037         idx = 0;
1038         while (dst) {
1039                 next = dst->next;
1040                 if (level >= dst->debug_level) {
1041                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1042                                     (u8 *) dst->addr.sun_path, dst->addrlen -
1043                                     offsetof(struct sockaddr_un, sun_path));
1044                         msg.msg_name = &dst->addr;
1045                         msg.msg_namelen = dst->addrlen;
1046                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1047                                 int _errno = errno;
1048                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1049                                            "%d - %s",
1050                                            idx, errno, strerror(errno));
1051                                 dst->errors++;
1052                                 if (dst->errors > 10 || _errno == ENOENT) {
1053                                         hostapd_ctrl_iface_detach(
1054                                                 hapd, &dst->addr,
1055                                                 dst->addrlen);
1056                                 }
1057                         } else
1058                                 dst->errors = 0;
1059                 }
1060                 idx++;
1061                 dst = next;
1062         }
1063 }
1064
1065 #endif /* CONFIG_NATIVE_WINDOWS */