61bd1e5e5e87f30f6d1a711dd39e8837ea00c38b
[mech_eap.git] / hostapd / ctrl_iface.c
1 /*
2  * hostapd / UNIX domain socket -based control interface
3  * Copyright (c) 2004-2010, 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/version.h"
26 #include "common/ieee802_11_defs.h"
27 #include "drivers/driver.h"
28 #include "radius/radius_client.h"
29 #include "ap/hostapd.h"
30 #include "ap/ap_config.h"
31 #include "ap/ieee802_1x.h"
32 #include "ap/wpa_auth.h"
33 #include "ap/ieee802_11.h"
34 #include "ap/sta_info.h"
35 #include "ap/wps_hostapd.h"
36 #include "ap/ctrl_iface_ap.h"
37 #include "ap/ap_drv_ops.h"
38 #include "wps/wps_defs.h"
39 #include "wps/wps.h"
40 #include "ctrl_iface.h"
41
42
43 struct wpa_ctrl_dst {
44         struct wpa_ctrl_dst *next;
45         struct sockaddr_un addr;
46         socklen_t addrlen;
47         int debug_level;
48         int errors;
49 };
50
51
52 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
53                                     const char *buf, size_t len);
54
55
56 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
57                                      struct sockaddr_un *from,
58                                      socklen_t fromlen)
59 {
60         struct wpa_ctrl_dst *dst;
61
62         dst = os_zalloc(sizeof(*dst));
63         if (dst == NULL)
64                 return -1;
65         os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
66         dst->addrlen = fromlen;
67         dst->debug_level = MSG_INFO;
68         dst->next = hapd->ctrl_dst;
69         hapd->ctrl_dst = dst;
70         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
71                     (u8 *) from->sun_path,
72                     fromlen - offsetof(struct sockaddr_un, sun_path));
73         return 0;
74 }
75
76
77 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
78                                      struct sockaddr_un *from,
79                                      socklen_t fromlen)
80 {
81         struct wpa_ctrl_dst *dst, *prev = NULL;
82
83         dst = hapd->ctrl_dst;
84         while (dst) {
85                 if (fromlen == dst->addrlen &&
86                     os_memcmp(from->sun_path, dst->addr.sun_path,
87                               fromlen - offsetof(struct sockaddr_un, sun_path))
88                     == 0) {
89                         if (prev == NULL)
90                                 hapd->ctrl_dst = dst->next;
91                         else
92                                 prev->next = dst->next;
93                         os_free(dst);
94                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
95                                     (u8 *) from->sun_path,
96                                     fromlen -
97                                     offsetof(struct sockaddr_un, sun_path));
98                         return 0;
99                 }
100                 prev = dst;
101                 dst = dst->next;
102         }
103         return -1;
104 }
105
106
107 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
108                                     struct sockaddr_un *from,
109                                     socklen_t fromlen,
110                                     char *level)
111 {
112         struct wpa_ctrl_dst *dst;
113
114         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
115
116         dst = hapd->ctrl_dst;
117         while (dst) {
118                 if (fromlen == dst->addrlen &&
119                     os_memcmp(from->sun_path, dst->addr.sun_path,
120                               fromlen - offsetof(struct sockaddr_un, sun_path))
121                     == 0) {
122                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
123                                     "level", (u8 *) from->sun_path, fromlen -
124                                     offsetof(struct sockaddr_un, sun_path));
125                         dst->debug_level = atoi(level);
126                         return 0;
127                 }
128                 dst = dst->next;
129         }
130
131         return -1;
132 }
133
134
135 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
136                                       const char *txtaddr)
137 {
138         u8 addr[ETH_ALEN];
139         struct sta_info *sta;
140
141         wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
142
143         if (hwaddr_aton(txtaddr, addr))
144                 return -1;
145
146         sta = ap_get_sta(hapd, addr);
147         if (sta)
148                 return 0;
149
150         wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
151                    "notification", MAC2STR(addr));
152         sta = ap_sta_add(hapd, addr);
153         if (sta == NULL)
154                 return -1;
155
156         hostapd_new_assoc_sta(hapd, sta, 0);
157         return 0;
158 }
159
160
161 #ifdef CONFIG_P2P_MANAGER
162 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
163                                   u8 minor_reason_code, const u8 *addr)
164 {
165         struct ieee80211_mgmt *mgmt;
166         int ret;
167         u8 *pos;
168
169         if (hapd->driver->send_frame == NULL)
170                 return -1;
171
172         mgmt = os_zalloc(sizeof(*mgmt) + 100);
173         if (mgmt == NULL)
174                 return -1;
175
176         wpa_printf(MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor "
177                    "reason code %u (stype=%u)",
178                    MAC2STR(addr), minor_reason_code, stype);
179
180         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
181         os_memcpy(mgmt->da, addr, ETH_ALEN);
182         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
183         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
184         if (stype == WLAN_FC_STYPE_DEAUTH) {
185                 mgmt->u.deauth.reason_code =
186                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
187                 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
188         } else {
189                 mgmt->u.disassoc.reason_code =
190                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
191                 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
192         }
193
194         *pos++ = WLAN_EID_VENDOR_SPECIFIC;
195         *pos++ = 4 + 3 + 1;
196         WPA_PUT_BE24(pos, OUI_WFA);
197         pos += 3;
198         *pos++ = P2P_OUI_TYPE;
199
200         *pos++ = P2P_ATTR_MINOR_REASON_CODE;
201         WPA_PUT_LE16(pos, 1);
202         pos += 2;
203         *pos++ = minor_reason_code;
204
205         ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
206                                        pos - (u8 *) mgmt, 1);
207         os_free(mgmt);
208
209         return ret < 0 ? -1 : 0;
210 }
211 #endif /* CONFIG_P2P_MANAGER */
212
213
214 static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
215                                              const char *txtaddr)
216 {
217         u8 addr[ETH_ALEN];
218         struct sta_info *sta;
219         const char *pos;
220
221         wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
222
223         if (hwaddr_aton(txtaddr, addr))
224                 return -1;
225
226         pos = os_strstr(txtaddr, " test=");
227         if (pos) {
228                 struct ieee80211_mgmt mgmt;
229                 int encrypt;
230                 if (hapd->driver->send_frame == NULL)
231                         return -1;
232                 pos += 6;
233                 encrypt = atoi(pos);
234                 os_memset(&mgmt, 0, sizeof(mgmt));
235                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
236                                                   WLAN_FC_STYPE_DEAUTH);
237                 os_memcpy(mgmt.da, addr, ETH_ALEN);
238                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
239                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
240                 mgmt.u.deauth.reason_code =
241                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
242                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
243                                              IEEE80211_HDRLEN +
244                                              sizeof(mgmt.u.deauth),
245                                              encrypt) < 0)
246                         return -1;
247                 return 0;
248         }
249
250 #ifdef CONFIG_P2P_MANAGER
251         pos = os_strstr(txtaddr, " p2p=");
252         if (pos) {
253                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
254                                               atoi(pos + 5), addr);
255         }
256 #endif /* CONFIG_P2P_MANAGER */
257
258         hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
259         sta = ap_get_sta(hapd, addr);
260         if (sta)
261                 ap_sta_deauthenticate(hapd, sta,
262                                       WLAN_REASON_PREV_AUTH_NOT_VALID);
263         else if (addr[0] == 0xff)
264                 hostapd_free_stas(hapd);
265
266         return 0;
267 }
268
269
270 static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
271                                            const char *txtaddr)
272 {
273         u8 addr[ETH_ALEN];
274         struct sta_info *sta;
275         const char *pos;
276
277         wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
278
279         if (hwaddr_aton(txtaddr, addr))
280                 return -1;
281
282         pos = os_strstr(txtaddr, " test=");
283         if (pos) {
284                 struct ieee80211_mgmt mgmt;
285                 int encrypt;
286                 if (hapd->driver->send_frame == NULL)
287                         return -1;
288                 pos += 6;
289                 encrypt = atoi(pos);
290                 os_memset(&mgmt, 0, sizeof(mgmt));
291                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
292                                                   WLAN_FC_STYPE_DISASSOC);
293                 os_memcpy(mgmt.da, addr, ETH_ALEN);
294                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
295                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
296                 mgmt.u.disassoc.reason_code =
297                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
298                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
299                                              IEEE80211_HDRLEN +
300                                              sizeof(mgmt.u.deauth),
301                                              encrypt) < 0)
302                         return -1;
303                 return 0;
304         }
305
306 #ifdef CONFIG_P2P_MANAGER
307         pos = os_strstr(txtaddr, " p2p=");
308         if (pos) {
309                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
310                                               atoi(pos + 5), addr);
311         }
312 #endif /* CONFIG_P2P_MANAGER */
313
314         hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
315         sta = ap_get_sta(hapd, addr);
316         if (sta)
317                 ap_sta_disassociate(hapd, sta,
318                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
319         else if (addr[0] == 0xff)
320                 hostapd_free_stas(hapd);
321
322         return 0;
323 }
324
325
326 #ifdef CONFIG_IEEE80211W
327 #ifdef NEED_AP_MLME
328 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
329                                        const char *txtaddr)
330 {
331         u8 addr[ETH_ALEN];
332         u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
333
334         wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
335
336         if (hwaddr_aton(txtaddr, addr) ||
337             os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
338                 return -1;
339
340         ieee802_11_send_sa_query_req(hapd, addr, trans_id);
341
342         return 0;
343 }
344 #endif /* NEED_AP_MLME */
345 #endif /* CONFIG_IEEE80211W */
346
347
348 #ifdef CONFIG_WPS
349 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
350 {
351         char *pin = os_strchr(txt, ' ');
352         char *timeout_txt;
353         int timeout;
354         u8 addr_buf[ETH_ALEN], *addr = NULL;
355         char *pos;
356
357         if (pin == NULL)
358                 return -1;
359         *pin++ = '\0';
360
361         timeout_txt = os_strchr(pin, ' ');
362         if (timeout_txt) {
363                 *timeout_txt++ = '\0';
364                 timeout = atoi(timeout_txt);
365                 pos = os_strchr(timeout_txt, ' ');
366                 if (pos) {
367                         *pos++ = '\0';
368                         if (hwaddr_aton(pos, addr_buf) == 0)
369                                 addr = addr_buf;
370                 }
371         } else
372                 timeout = 0;
373
374         return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
375 }
376
377
378 static int hostapd_ctrl_iface_wps_check_pin(
379         struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
380 {
381         char pin[9];
382         size_t len;
383         char *pos;
384         int ret;
385
386         wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
387                               (u8 *) cmd, os_strlen(cmd));
388         for (pos = cmd, len = 0; *pos != '\0'; pos++) {
389                 if (*pos < '0' || *pos > '9')
390                         continue;
391                 pin[len++] = *pos;
392                 if (len == 9) {
393                         wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
394                         return -1;
395                 }
396         }
397         if (len != 4 && len != 8) {
398                 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
399                 return -1;
400         }
401         pin[len] = '\0';
402
403         if (len == 8) {
404                 unsigned int pin_val;
405                 pin_val = atoi(pin);
406                 if (!wps_pin_valid(pin_val)) {
407                         wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
408                         ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
409                         if (ret < 0 || (size_t) ret >= buflen)
410                                 return -1;
411                         return ret;
412                 }
413         }
414
415         ret = os_snprintf(buf, buflen, "%s", pin);
416         if (ret < 0 || (size_t) ret >= buflen)
417                 return -1;
418
419         return ret;
420 }
421
422
423 #ifdef CONFIG_WPS_OOB
424 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
425 {
426         char *path, *method, *name;
427
428         path = os_strchr(txt, ' ');
429         if (path == NULL)
430                 return -1;
431         *path++ = '\0';
432
433         method = os_strchr(path, ' ');
434         if (method == NULL)
435                 return -1;
436         *method++ = '\0';
437
438         name = os_strchr(method, ' ');
439         if (name != NULL)
440                 *name++ = '\0';
441
442         return hostapd_wps_start_oob(hapd, txt, path, method, name);
443 }
444 #endif /* CONFIG_WPS_OOB */
445
446
447 static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
448                                          char *buf, size_t buflen)
449 {
450         int timeout = 300;
451         char *pos;
452         const char *pin_txt;
453
454         pos = os_strchr(txt, ' ');
455         if (pos)
456                 *pos++ = '\0';
457
458         if (os_strcmp(txt, "disable") == 0) {
459                 hostapd_wps_ap_pin_disable(hapd);
460                 return os_snprintf(buf, buflen, "OK\n");
461         }
462
463         if (os_strcmp(txt, "random") == 0) {
464                 if (pos)
465                         timeout = atoi(pos);
466                 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
467                 if (pin_txt == NULL)
468                         return -1;
469                 return os_snprintf(buf, buflen, "%s", pin_txt);
470         }
471
472         if (os_strcmp(txt, "get") == 0) {
473                 pin_txt = hostapd_wps_ap_pin_get(hapd);
474                 if (pin_txt == NULL)
475                         return -1;
476                 return os_snprintf(buf, buflen, "%s", pin_txt);
477         }
478
479         if (os_strcmp(txt, "set") == 0) {
480                 char *pin;
481                 if (pos == NULL)
482                         return -1;
483                 pin = pos;
484                 pos = os_strchr(pos, ' ');
485                 if (pos) {
486                         *pos++ = '\0';
487                         timeout = atoi(pos);
488                 }
489                 if (os_strlen(pin) > buflen)
490                         return -1;
491                 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
492                         return -1;
493                 return os_snprintf(buf, buflen, "%s", pin);
494         }
495
496         return -1;
497 }
498
499
500 static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
501 {
502         char *pos;
503         char *ssid, *auth, *encr = NULL, *key = NULL;
504
505         ssid = txt;
506         pos = os_strchr(txt, ' ');
507         if (!pos)
508                 return -1;
509         *pos++ = '\0';
510
511         auth = pos;
512         pos = os_strchr(pos, ' ');
513         if (pos) {
514                 *pos++ = '\0';
515                 encr = pos;
516                 pos = os_strchr(pos, ' ');
517                 if (pos) {
518                         *pos++ = '\0';
519                         key = pos;
520                 }
521         }
522
523         return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
524 }
525 #endif /* CONFIG_WPS */
526
527
528 static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
529                                            const char *cmd)
530 {
531         u8 addr[ETH_ALEN];
532         const char *url;
533         u8 buf[1000], *pos;
534         struct ieee80211_mgmt *mgmt;
535         size_t url_len;
536
537         if (hwaddr_aton(cmd, addr))
538                 return -1;
539         url = cmd + 17;
540         if (*url != ' ')
541                 return -1;
542         url++;
543         url_len = os_strlen(url);
544         if (url_len > 255)
545                 return -1;
546
547         os_memset(buf, 0, sizeof(buf));
548         mgmt = (struct ieee80211_mgmt *) buf;
549         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
550                                            WLAN_FC_STYPE_ACTION);
551         os_memcpy(mgmt->da, addr, ETH_ALEN);
552         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
553         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
554         mgmt->u.action.category = WLAN_ACTION_WNM;
555         mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
556         mgmt->u.action.u.bss_tm_req.dialog_token = 1;
557         mgmt->u.action.u.bss_tm_req.req_mode =
558                 WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
559         mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
560         mgmt->u.action.u.bss_tm_req.validity_interval = 0;
561
562         pos = mgmt->u.action.u.bss_tm_req.variable;
563
564         /* Session Information URL */
565         *pos++ = url_len;
566         os_memcpy(pos, url, url_len);
567         pos += url_len;
568
569         if (hostapd_drv_send_mlme(hapd, buf, pos - buf) < 0) {
570                 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
571                            "Management Request frame");
572                 return -1;
573         }
574
575         return 0;
576 }
577
578
579 static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
580                                          char *buf, size_t buflen)
581 {
582         int ret;
583         char *pos, *end;
584
585         pos = buf;
586         end = buf + buflen;
587
588         ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
589                           "ssid=%s\n",
590                           MAC2STR(hapd->own_addr),
591                           hapd->conf->ssid.ssid);
592         if (ret < 0 || ret >= end - pos)
593                 return pos - buf;
594         pos += ret;
595
596 #ifdef CONFIG_WPS
597         ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
598                           hapd->conf->wps_state == 0 ? "disabled" :
599                           (hapd->conf->wps_state == 1 ? "not configured" :
600                            "configured"));
601         if (ret < 0 || ret >= end - pos)
602                 return pos - buf;
603         pos += ret;
604
605         if (hapd->conf->wps_state && hapd->conf->wpa &&
606             hapd->conf->ssid.wpa_passphrase) {
607                 ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
608                                   hapd->conf->ssid.wpa_passphrase);
609                 if (ret < 0 || ret >= end - pos)
610                         return pos - buf;
611                 pos += ret;
612         }
613
614         if (hapd->conf->wps_state && hapd->conf->wpa &&
615             hapd->conf->ssid.wpa_psk &&
616             hapd->conf->ssid.wpa_psk->group) {
617                 char hex[PMK_LEN * 2 + 1];
618                 wpa_snprintf_hex(hex, sizeof(hex),
619                                  hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
620                 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
621                 if (ret < 0 || ret >= end - pos)
622                         return pos - buf;
623                 pos += ret;
624         }
625 #endif /* CONFIG_WPS */
626
627         if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
628                 ret = os_snprintf(pos, end - pos, "key_mgmt=");
629                 if (ret < 0 || ret >= end - pos)
630                         return pos - buf;
631                 pos += ret;
632
633                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
634                         ret = os_snprintf(pos, end - pos, "WPA-PSK ");
635                         if (ret < 0 || ret >= end - pos)
636                                 return pos - buf;
637                         pos += ret;
638                 }
639                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
640                         ret = os_snprintf(pos, end - pos, "WPA-EAP ");
641                         if (ret < 0 || ret >= end - pos)
642                                 return pos - buf;
643                         pos += ret;
644                 }
645 #ifdef CONFIG_IEEE80211R
646                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
647                         ret = os_snprintf(pos, end - pos, "FT-PSK ");
648                         if (ret < 0 || ret >= end - pos)
649                                 return pos - buf;
650                         pos += ret;
651                 }
652                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
653                         ret = os_snprintf(pos, end - pos, "FT-EAP ");
654                         if (ret < 0 || ret >= end - pos)
655                                 return pos - buf;
656                         pos += ret;
657                 }
658 #endif /* CONFIG_IEEE80211R */
659 #ifdef CONFIG_IEEE80211W
660                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
661                         ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
662                         if (ret < 0 || ret >= end - pos)
663                                 return pos - buf;
664                         pos += ret;
665                 }
666                 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
667                         ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
668                         if (ret < 0 || ret >= end - pos)
669                                 return pos - buf;
670                         pos += ret;
671                 }
672 #endif /* CONFIG_IEEE80211W */
673
674                 ret = os_snprintf(pos, end - pos, "\n");
675                 if (ret < 0 || ret >= end - pos)
676                         return pos - buf;
677                 pos += ret;
678         }
679
680         if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
681                 ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
682                 if (ret < 0 || ret >= end - pos)
683                         return pos - buf;
684                 pos += ret;
685         } else if (hapd->conf->wpa &&
686                    hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
687                 ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
688                 if (ret < 0 || ret >= end - pos)
689                         return pos - buf;
690                 pos += ret;
691         }
692
693         if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
694                 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
695                 if (ret < 0 || ret >= end - pos)
696                         return pos - buf;
697                 pos += ret;
698
699                 if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
700                         ret = os_snprintf(pos, end - pos, "CCMP ");
701                         if (ret < 0 || ret >= end - pos)
702                                 return pos - buf;
703                         pos += ret;
704                 }
705                 if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
706                         ret = os_snprintf(pos, end - pos, "TKIP ");
707                         if (ret < 0 || ret >= end - pos)
708                                 return pos - buf;
709                         pos += ret;
710                 }
711
712                 ret = os_snprintf(pos, end - pos, "\n");
713                 if (ret < 0 || ret >= end - pos)
714                         return pos - buf;
715                 pos += ret;
716         }
717
718         if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
719                 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
720                 if (ret < 0 || ret >= end - pos)
721                         return pos - buf;
722                 pos += ret;
723
724                 if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
725                         ret = os_snprintf(pos, end - pos, "CCMP ");
726                         if (ret < 0 || ret >= end - pos)
727                                 return pos - buf;
728                         pos += ret;
729                 }
730                 if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
731                         ret = os_snprintf(pos, end - pos, "TKIP ");
732                         if (ret < 0 || ret >= end - pos)
733                                 return pos - buf;
734                         pos += ret;
735                 }
736
737                 ret = os_snprintf(pos, end - pos, "\n");
738                 if (ret < 0 || ret >= end - pos)
739                         return pos - buf;
740                 pos += ret;
741         }
742
743         return pos - buf;
744 }
745
746
747 static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
748 {
749         char *value;
750         int ret = 0;
751
752         value = os_strchr(cmd, ' ');
753         if (value == NULL)
754                 return -1;
755         *value++ = '\0';
756
757         wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
758         if (0) {
759 #ifdef CONFIG_WPS_TESTING
760         } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
761                 long int val;
762                 val = strtol(value, NULL, 0);
763                 if (val < 0 || val > 0xff) {
764                         ret = -1;
765                         wpa_printf(MSG_DEBUG, "WPS: Invalid "
766                                    "wps_version_number %ld", val);
767                 } else {
768                         wps_version_number = val;
769                         wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
770                                    "version %u.%u",
771                                    (wps_version_number & 0xf0) >> 4,
772                                    wps_version_number & 0x0f);
773                         hostapd_wps_update_ie(hapd);
774                 }
775         } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
776                 wps_testing_dummy_cred = atoi(value);
777                 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
778                            wps_testing_dummy_cred);
779 #endif /* CONFIG_WPS_TESTING */
780         } else {
781                 ret = -1;
782         }
783
784         return ret;
785 }
786
787
788 static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
789                                   char *buf, size_t buflen)
790 {
791         int res;
792
793         wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
794
795         if (os_strcmp(cmd, "version") == 0) {
796                 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
797                 if (res < 0 || (unsigned int) res >= buflen)
798                         return -1;
799                 return res;
800         }
801
802         return -1;
803 }
804
805
806 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
807                                        void *sock_ctx)
808 {
809         struct hostapd_data *hapd = eloop_ctx;
810         char buf[256];
811         int res;
812         struct sockaddr_un from;
813         socklen_t fromlen = sizeof(from);
814         char *reply;
815         const int reply_size = 4096;
816         int reply_len;
817         int level = MSG_DEBUG;
818
819         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
820                        (struct sockaddr *) &from, &fromlen);
821         if (res < 0) {
822                 perror("recvfrom(ctrl_iface)");
823                 return;
824         }
825         buf[res] = '\0';
826         if (os_strcmp(buf, "PING") == 0)
827                 level = MSG_EXCESSIVE;
828         wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
829
830         reply = os_malloc(reply_size);
831         if (reply == NULL) {
832                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
833                        fromlen);
834                 return;
835         }
836
837         os_memcpy(reply, "OK\n", 3);
838         reply_len = 3;
839
840         if (os_strcmp(buf, "PING") == 0) {
841                 os_memcpy(reply, "PONG\n", 5);
842                 reply_len = 5;
843         } else if (os_strncmp(buf, "RELOG", 5) == 0) {
844                 if (wpa_debug_reopen_file() < 0)
845                         reply_len = -1;
846         } else if (os_strcmp(buf, "MIB") == 0) {
847                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
848                 if (reply_len >= 0) {
849                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
850                                           reply_size - reply_len);
851                         if (res < 0)
852                                 reply_len = -1;
853                         else
854                                 reply_len += res;
855                 }
856                 if (reply_len >= 0) {
857                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
858                                                  reply_size - reply_len);
859                         if (res < 0)
860                                 reply_len = -1;
861                         else
862                                 reply_len += res;
863                 }
864 #ifndef CONFIG_NO_RADIUS
865                 if (reply_len >= 0) {
866                         res = radius_client_get_mib(hapd->radius,
867                                                     reply + reply_len,
868                                                     reply_size - reply_len);
869                         if (res < 0)
870                                 reply_len = -1;
871                         else
872                                 reply_len += res;
873                 }
874 #endif /* CONFIG_NO_RADIUS */
875         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
876                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
877                                                          reply_size);
878         } else if (os_strncmp(buf, "STA ", 4) == 0) {
879                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
880                                                    reply_size);
881         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
882                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
883                                                         reply_size);
884         } else if (os_strcmp(buf, "ATTACH") == 0) {
885                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
886                         reply_len = -1;
887         } else if (os_strcmp(buf, "DETACH") == 0) {
888                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
889                         reply_len = -1;
890         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
891                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
892                                                     buf + 6))
893                         reply_len = -1;
894         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
895                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
896                         reply_len = -1;
897         } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
898                 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
899                         reply_len = -1;
900         } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
901                 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
902                         reply_len = -1;
903 #ifdef CONFIG_IEEE80211W
904 #ifdef NEED_AP_MLME
905         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
906                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
907                         reply_len = -1;
908 #endif /* NEED_AP_MLME */
909 #endif /* CONFIG_IEEE80211W */
910 #ifdef CONFIG_WPS
911         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
912                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
913                         reply_len = -1;
914         } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
915                 reply_len = hostapd_ctrl_iface_wps_check_pin(
916                         hapd, buf + 14, reply, reply_size);
917         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
918                 if (hostapd_wps_button_pushed(hapd, NULL))
919                         reply_len = -1;
920 #ifdef CONFIG_WPS_OOB
921         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
922                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
923                         reply_len = -1;
924 #endif /* CONFIG_WPS_OOB */
925         } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
926                 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
927                                                           reply, reply_size);
928         } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
929                 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
930                         reply_len = -1;
931 #endif /* CONFIG_WPS */
932         } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
933                 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
934                         reply_len = -1;
935         } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
936                 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
937                                                           reply_size);
938         } else if (os_strncmp(buf, "SET ", 4) == 0) {
939                 if (hostapd_ctrl_iface_set(hapd, buf + 4))
940                         reply_len = -1;
941         } else if (os_strncmp(buf, "GET ", 4) == 0) {
942                 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
943                                                    reply_size);
944         } else {
945                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
946                 reply_len = 16;
947         }
948
949         if (reply_len < 0) {
950                 os_memcpy(reply, "FAIL\n", 5);
951                 reply_len = 5;
952         }
953         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
954         os_free(reply);
955 }
956
957
958 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
959 {
960         char *buf;
961         size_t len;
962
963         if (hapd->conf->ctrl_interface == NULL)
964                 return NULL;
965
966         len = os_strlen(hapd->conf->ctrl_interface) +
967                 os_strlen(hapd->conf->iface) + 2;
968         buf = os_malloc(len);
969         if (buf == NULL)
970                 return NULL;
971
972         os_snprintf(buf, len, "%s/%s",
973                     hapd->conf->ctrl_interface, hapd->conf->iface);
974         buf[len - 1] = '\0';
975         return buf;
976 }
977
978
979 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
980                                       const char *txt, size_t len)
981 {
982         struct hostapd_data *hapd = ctx;
983         if (hapd == NULL)
984                 return;
985         hostapd_ctrl_iface_send(hapd, level, txt, len);
986 }
987
988
989 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
990 {
991         struct sockaddr_un addr;
992         int s = -1;
993         char *fname = NULL;
994
995         hapd->ctrl_sock = -1;
996
997         if (hapd->conf->ctrl_interface == NULL)
998                 return 0;
999
1000         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1001                 if (errno == EEXIST) {
1002                         wpa_printf(MSG_DEBUG, "Using existing control "
1003                                    "interface directory.");
1004                 } else {
1005                         perror("mkdir[ctrl_interface]");
1006                         goto fail;
1007                 }
1008         }
1009
1010         if (hapd->conf->ctrl_interface_gid_set &&
1011             chown(hapd->conf->ctrl_interface, 0,
1012                   hapd->conf->ctrl_interface_gid) < 0) {
1013                 perror("chown[ctrl_interface]");
1014                 return -1;
1015         }
1016
1017         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
1018             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
1019                 goto fail;
1020
1021         s = socket(PF_UNIX, SOCK_DGRAM, 0);
1022         if (s < 0) {
1023                 perror("socket(PF_UNIX)");
1024                 goto fail;
1025         }
1026
1027         os_memset(&addr, 0, sizeof(addr));
1028 #ifdef __FreeBSD__
1029         addr.sun_len = sizeof(addr);
1030 #endif /* __FreeBSD__ */
1031         addr.sun_family = AF_UNIX;
1032         fname = hostapd_ctrl_iface_path(hapd);
1033         if (fname == NULL)
1034                 goto fail;
1035         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1036         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1037                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1038                            strerror(errno));
1039                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1040                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1041                                    " allow connections - assuming it was left"
1042                                    "over from forced program termination");
1043                         if (unlink(fname) < 0) {
1044                                 perror("unlink[ctrl_iface]");
1045                                 wpa_printf(MSG_ERROR, "Could not unlink "
1046                                            "existing ctrl_iface socket '%s'",
1047                                            fname);
1048                                 goto fail;
1049                         }
1050                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1051                             0) {
1052                                 perror("bind(PF_UNIX)");
1053                                 goto fail;
1054                         }
1055                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1056                                    "ctrl_iface socket '%s'", fname);
1057                 } else {
1058                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1059                                    "be in use - cannot override it");
1060                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1061                                    "not used anymore", fname);
1062                         os_free(fname);
1063                         fname = NULL;
1064                         goto fail;
1065                 }
1066         }
1067
1068         if (hapd->conf->ctrl_interface_gid_set &&
1069             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
1070                 perror("chown[ctrl_interface/ifname]");
1071                 goto fail;
1072         }
1073
1074         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1075                 perror("chmod[ctrl_interface/ifname]");
1076                 goto fail;
1077         }
1078         os_free(fname);
1079
1080         hapd->ctrl_sock = s;
1081         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
1082                                  NULL);
1083         hapd->msg_ctx = hapd;
1084         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
1085
1086         return 0;
1087
1088 fail:
1089         if (s >= 0)
1090                 close(s);
1091         if (fname) {
1092                 unlink(fname);
1093                 os_free(fname);
1094         }
1095         return -1;
1096 }
1097
1098
1099 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
1100 {
1101         struct wpa_ctrl_dst *dst, *prev;
1102
1103         if (hapd->ctrl_sock > -1) {
1104                 char *fname;
1105                 eloop_unregister_read_sock(hapd->ctrl_sock);
1106                 close(hapd->ctrl_sock);
1107                 hapd->ctrl_sock = -1;
1108                 fname = hostapd_ctrl_iface_path(hapd);
1109                 if (fname)
1110                         unlink(fname);
1111                 os_free(fname);
1112
1113                 if (hapd->conf->ctrl_interface &&
1114                     rmdir(hapd->conf->ctrl_interface) < 0) {
1115                         if (errno == ENOTEMPTY) {
1116                                 wpa_printf(MSG_DEBUG, "Control interface "
1117                                            "directory not empty - leaving it "
1118                                            "behind");
1119                         } else {
1120                                 perror("rmdir[ctrl_interface]");
1121                         }
1122                 }
1123         }
1124
1125         dst = hapd->ctrl_dst;
1126         while (dst) {
1127                 prev = dst;
1128                 dst = dst->next;
1129                 os_free(prev);
1130         }
1131 }
1132
1133
1134 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1135                                     const char *buf, size_t len)
1136 {
1137         struct wpa_ctrl_dst *dst, *next;
1138         struct msghdr msg;
1139         int idx;
1140         struct iovec io[2];
1141         char levelstr[10];
1142
1143         dst = hapd->ctrl_dst;
1144         if (hapd->ctrl_sock < 0 || dst == NULL)
1145                 return;
1146
1147         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1148         io[0].iov_base = levelstr;
1149         io[0].iov_len = os_strlen(levelstr);
1150         io[1].iov_base = (char *) buf;
1151         io[1].iov_len = len;
1152         os_memset(&msg, 0, sizeof(msg));
1153         msg.msg_iov = io;
1154         msg.msg_iovlen = 2;
1155
1156         idx = 0;
1157         while (dst) {
1158                 next = dst->next;
1159                 if (level >= dst->debug_level) {
1160                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1161                                     (u8 *) dst->addr.sun_path, dst->addrlen -
1162                                     offsetof(struct sockaddr_un, sun_path));
1163                         msg.msg_name = &dst->addr;
1164                         msg.msg_namelen = dst->addrlen;
1165                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1166                                 int _errno = errno;
1167                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1168                                            "%d - %s",
1169                                            idx, errno, strerror(errno));
1170                                 dst->errors++;
1171                                 if (dst->errors > 10 || _errno == ENOENT) {
1172                                         hostapd_ctrl_iface_detach(
1173                                                 hapd, &dst->addr,
1174                                                 dst->addrlen);
1175                                 }
1176                         } else
1177                                 dst->errors = 0;
1178                 }
1179                 idx++;
1180                 dst = next;
1181         }
1182 }
1183
1184 #endif /* CONFIG_NATIVE_WINDOWS */