0407b6c73996f8bf531157619c278d53370cf00d
[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         int level = MSG_DEBUG;
714
715         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
716                        (struct sockaddr *) &from, &fromlen);
717         if (res < 0) {
718                 perror("recvfrom(ctrl_iface)");
719                 return;
720         }
721         buf[res] = '\0';
722         if (os_strcmp(buf, "PING") == 0)
723                 level = MSG_EXCESSIVE;
724         wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
725
726         reply = os_malloc(reply_size);
727         if (reply == NULL) {
728                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
729                        fromlen);
730                 return;
731         }
732
733         os_memcpy(reply, "OK\n", 3);
734         reply_len = 3;
735
736         if (os_strcmp(buf, "PING") == 0) {
737                 os_memcpy(reply, "PONG\n", 5);
738                 reply_len = 5;
739         } else if (os_strcmp(buf, "MIB") == 0) {
740                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
741                 if (reply_len >= 0) {
742                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
743                                           reply_size - reply_len);
744                         if (res < 0)
745                                 reply_len = -1;
746                         else
747                                 reply_len += res;
748                 }
749                 if (reply_len >= 0) {
750                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
751                                                  reply_size - reply_len);
752                         if (res < 0)
753                                 reply_len = -1;
754                         else
755                                 reply_len += res;
756                 }
757 #ifndef CONFIG_NO_RADIUS
758                 if (reply_len >= 0) {
759                         res = radius_client_get_mib(hapd->radius,
760                                                     reply + reply_len,
761                                                     reply_size - reply_len);
762                         if (res < 0)
763                                 reply_len = -1;
764                         else
765                                 reply_len += res;
766                 }
767 #endif /* CONFIG_NO_RADIUS */
768         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
769                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
770                                                          reply_size);
771         } else if (os_strncmp(buf, "STA ", 4) == 0) {
772                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
773                                                    reply_size);
774         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
775                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
776                                                         reply_size);
777         } else if (os_strcmp(buf, "ATTACH") == 0) {
778                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
779                         reply_len = -1;
780         } else if (os_strcmp(buf, "DETACH") == 0) {
781                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
782                         reply_len = -1;
783         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
784                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
785                                                     buf + 6))
786                         reply_len = -1;
787         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
788                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
789                         reply_len = -1;
790         } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
791                 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
792                         reply_len = -1;
793         } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
794                 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
795                         reply_len = -1;
796 #ifdef CONFIG_IEEE80211W
797 #ifdef NEED_AP_MLME
798         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
799                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
800                         reply_len = -1;
801 #endif /* NEED_AP_MLME */
802 #endif /* CONFIG_IEEE80211W */
803 #ifdef CONFIG_WPS
804         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
805                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
806                         reply_len = -1;
807         } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
808                 reply_len = hostapd_ctrl_iface_wps_check_pin(
809                         hapd, buf + 14, reply, reply_size);
810         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
811                 if (hostapd_wps_button_pushed(hapd))
812                         reply_len = -1;
813 #ifdef CONFIG_WPS_OOB
814         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
815                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
816                         reply_len = -1;
817 #endif /* CONFIG_WPS_OOB */
818         } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
819                 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
820                                                           reply, reply_size);
821 #endif /* CONFIG_WPS */
822         } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
823                 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
824                                                           reply_size);
825         } else if (os_strncmp(buf, "SET ", 4) == 0) {
826                 if (hostapd_ctrl_iface_set(hapd, buf + 4))
827                         reply_len = -1;
828         } else {
829                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
830                 reply_len = 16;
831         }
832
833         if (reply_len < 0) {
834                 os_memcpy(reply, "FAIL\n", 5);
835                 reply_len = 5;
836         }
837         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
838         os_free(reply);
839 }
840
841
842 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
843 {
844         char *buf;
845         size_t len;
846
847         if (hapd->conf->ctrl_interface == NULL)
848                 return NULL;
849
850         len = os_strlen(hapd->conf->ctrl_interface) +
851                 os_strlen(hapd->conf->iface) + 2;
852         buf = os_malloc(len);
853         if (buf == NULL)
854                 return NULL;
855
856         os_snprintf(buf, len, "%s/%s",
857                     hapd->conf->ctrl_interface, hapd->conf->iface);
858         buf[len - 1] = '\0';
859         return buf;
860 }
861
862
863 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
864                                       const char *txt, size_t len)
865 {
866         struct hostapd_data *hapd = ctx;
867         if (hapd == NULL)
868                 return;
869         hostapd_ctrl_iface_send(hapd, level, txt, len);
870 }
871
872
873 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
874 {
875         struct sockaddr_un addr;
876         int s = -1;
877         char *fname = NULL;
878
879         hapd->ctrl_sock = -1;
880
881         if (hapd->conf->ctrl_interface == NULL)
882                 return 0;
883
884         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
885                 if (errno == EEXIST) {
886                         wpa_printf(MSG_DEBUG, "Using existing control "
887                                    "interface directory.");
888                 } else {
889                         perror("mkdir[ctrl_interface]");
890                         goto fail;
891                 }
892         }
893
894         if (hapd->conf->ctrl_interface_gid_set &&
895             chown(hapd->conf->ctrl_interface, 0,
896                   hapd->conf->ctrl_interface_gid) < 0) {
897                 perror("chown[ctrl_interface]");
898                 return -1;
899         }
900
901         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
902             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
903                 goto fail;
904
905         s = socket(PF_UNIX, SOCK_DGRAM, 0);
906         if (s < 0) {
907                 perror("socket(PF_UNIX)");
908                 goto fail;
909         }
910
911         os_memset(&addr, 0, sizeof(addr));
912 #ifdef __FreeBSD__
913         addr.sun_len = sizeof(addr);
914 #endif /* __FreeBSD__ */
915         addr.sun_family = AF_UNIX;
916         fname = hostapd_ctrl_iface_path(hapd);
917         if (fname == NULL)
918                 goto fail;
919         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
920         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
921                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
922                            strerror(errno));
923                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
924                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
925                                    " allow connections - assuming it was left"
926                                    "over from forced program termination");
927                         if (unlink(fname) < 0) {
928                                 perror("unlink[ctrl_iface]");
929                                 wpa_printf(MSG_ERROR, "Could not unlink "
930                                            "existing ctrl_iface socket '%s'",
931                                            fname);
932                                 goto fail;
933                         }
934                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
935                             0) {
936                                 perror("bind(PF_UNIX)");
937                                 goto fail;
938                         }
939                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
940                                    "ctrl_iface socket '%s'", fname);
941                 } else {
942                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
943                                    "be in use - cannot override it");
944                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
945                                    "not used anymore", fname);
946                         os_free(fname);
947                         fname = NULL;
948                         goto fail;
949                 }
950         }
951
952         if (hapd->conf->ctrl_interface_gid_set &&
953             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
954                 perror("chown[ctrl_interface/ifname]");
955                 goto fail;
956         }
957
958         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
959                 perror("chmod[ctrl_interface/ifname]");
960                 goto fail;
961         }
962         os_free(fname);
963
964         hapd->ctrl_sock = s;
965         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
966                                  NULL);
967         hapd->msg_ctx = hapd;
968         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
969
970         return 0;
971
972 fail:
973         if (s >= 0)
974                 close(s);
975         if (fname) {
976                 unlink(fname);
977                 os_free(fname);
978         }
979         return -1;
980 }
981
982
983 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
984 {
985         struct wpa_ctrl_dst *dst, *prev;
986
987         if (hapd->ctrl_sock > -1) {
988                 char *fname;
989                 eloop_unregister_read_sock(hapd->ctrl_sock);
990                 close(hapd->ctrl_sock);
991                 hapd->ctrl_sock = -1;
992                 fname = hostapd_ctrl_iface_path(hapd);
993                 if (fname)
994                         unlink(fname);
995                 os_free(fname);
996
997                 if (hapd->conf->ctrl_interface &&
998                     rmdir(hapd->conf->ctrl_interface) < 0) {
999                         if (errno == ENOTEMPTY) {
1000                                 wpa_printf(MSG_DEBUG, "Control interface "
1001                                            "directory not empty - leaving it "
1002                                            "behind");
1003                         } else {
1004                                 perror("rmdir[ctrl_interface]");
1005                         }
1006                 }
1007         }
1008
1009         dst = hapd->ctrl_dst;
1010         while (dst) {
1011                 prev = dst;
1012                 dst = dst->next;
1013                 os_free(prev);
1014         }
1015 }
1016
1017
1018 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1019                                     const char *buf, size_t len)
1020 {
1021         struct wpa_ctrl_dst *dst, *next;
1022         struct msghdr msg;
1023         int idx;
1024         struct iovec io[2];
1025         char levelstr[10];
1026
1027         dst = hapd->ctrl_dst;
1028         if (hapd->ctrl_sock < 0 || dst == NULL)
1029                 return;
1030
1031         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1032         io[0].iov_base = levelstr;
1033         io[0].iov_len = os_strlen(levelstr);
1034         io[1].iov_base = (char *) buf;
1035         io[1].iov_len = len;
1036         os_memset(&msg, 0, sizeof(msg));
1037         msg.msg_iov = io;
1038         msg.msg_iovlen = 2;
1039
1040         idx = 0;
1041         while (dst) {
1042                 next = dst->next;
1043                 if (level >= dst->debug_level) {
1044                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1045                                     (u8 *) dst->addr.sun_path, dst->addrlen -
1046                                     offsetof(struct sockaddr_un, sun_path));
1047                         msg.msg_name = &dst->addr;
1048                         msg.msg_namelen = dst->addrlen;
1049                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1050                                 int _errno = errno;
1051                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1052                                            "%d - %s",
1053                                            idx, errno, strerror(errno));
1054                                 dst->errors++;
1055                                 if (dst->errors > 10 || _errno == ENOENT) {
1056                                         hostapd_ctrl_iface_detach(
1057                                                 hapd, &dst->addr,
1058                                                 dst->addrlen);
1059                                 }
1060                         } else
1061                                 dst->errors = 0;
1062                 }
1063                 idx++;
1064                 dst = next;
1065         }
1066 }
1067
1068 #endif /* CONFIG_NATIVE_WINDOWS */