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