blob: 021cbe5790583d6b72b01e0fa6de7851ee22c5e2 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / UNIX domain socket -based control interface
Dmitry Shmidt04949592012-07-19 12:16:46 -07003 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
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"
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -070032#include "ap/wpa_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070033#include "wps/wps_defs.h"
34#include "wps/wps.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070035#include "config_file.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070036#include "ctrl_iface.h"
37
38
39struct wpa_ctrl_dst {
40 struct wpa_ctrl_dst *next;
41 struct sockaddr_un addr;
42 socklen_t addrlen;
43 int debug_level;
44 int errors;
45};
46
47
48static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
49 const char *buf, size_t len);
50
51
52static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
53 struct sockaddr_un *from,
54 socklen_t fromlen)
55{
56 struct wpa_ctrl_dst *dst;
57
58 dst = os_zalloc(sizeof(*dst));
59 if (dst == NULL)
60 return -1;
61 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
62 dst->addrlen = fromlen;
63 dst->debug_level = MSG_INFO;
64 dst->next = hapd->ctrl_dst;
65 hapd->ctrl_dst = dst;
66 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
67 (u8 *) from->sun_path,
68 fromlen - offsetof(struct sockaddr_un, sun_path));
69 return 0;
70}
71
72
73static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
74 struct sockaddr_un *from,
75 socklen_t fromlen)
76{
77 struct wpa_ctrl_dst *dst, *prev = NULL;
78
79 dst = hapd->ctrl_dst;
80 while (dst) {
81 if (fromlen == dst->addrlen &&
82 os_memcmp(from->sun_path, dst->addr.sun_path,
83 fromlen - offsetof(struct sockaddr_un, sun_path))
84 == 0) {
85 if (prev == NULL)
86 hapd->ctrl_dst = dst->next;
87 else
88 prev->next = dst->next;
89 os_free(dst);
90 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
91 (u8 *) from->sun_path,
92 fromlen -
93 offsetof(struct sockaddr_un, sun_path));
94 return 0;
95 }
96 prev = dst;
97 dst = dst->next;
98 }
99 return -1;
100}
101
102
103static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
104 struct sockaddr_un *from,
105 socklen_t fromlen,
106 char *level)
107{
108 struct wpa_ctrl_dst *dst;
109
110 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
111
112 dst = hapd->ctrl_dst;
113 while (dst) {
114 if (fromlen == dst->addrlen &&
115 os_memcmp(from->sun_path, dst->addr.sun_path,
116 fromlen - offsetof(struct sockaddr_un, sun_path))
117 == 0) {
118 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
119 "level", (u8 *) from->sun_path, fromlen -
120 offsetof(struct sockaddr_un, sun_path));
121 dst->debug_level = atoi(level);
122 return 0;
123 }
124 dst = dst->next;
125 }
126
127 return -1;
128}
129
130
131static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
132 const char *txtaddr)
133{
134 u8 addr[ETH_ALEN];
135 struct sta_info *sta;
136
137 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
138
139 if (hwaddr_aton(txtaddr, addr))
140 return -1;
141
142 sta = ap_get_sta(hapd, addr);
143 if (sta)
144 return 0;
145
146 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
147 "notification", MAC2STR(addr));
148 sta = ap_sta_add(hapd, addr);
149 if (sta == NULL)
150 return -1;
151
152 hostapd_new_assoc_sta(hapd, sta, 0);
153 return 0;
154}
155
156
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700157#ifdef CONFIG_IEEE80211W
158#ifdef NEED_AP_MLME
159static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
160 const char *txtaddr)
161{
162 u8 addr[ETH_ALEN];
163 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
164
165 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
166
167 if (hwaddr_aton(txtaddr, addr) ||
168 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
169 return -1;
170
171 ieee802_11_send_sa_query_req(hapd, addr, trans_id);
172
173 return 0;
174}
175#endif /* NEED_AP_MLME */
176#endif /* CONFIG_IEEE80211W */
177
178
179#ifdef CONFIG_WPS
180static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
181{
182 char *pin = os_strchr(txt, ' ');
183 char *timeout_txt;
184 int timeout;
185 u8 addr_buf[ETH_ALEN], *addr = NULL;
186 char *pos;
187
188 if (pin == NULL)
189 return -1;
190 *pin++ = '\0';
191
192 timeout_txt = os_strchr(pin, ' ');
193 if (timeout_txt) {
194 *timeout_txt++ = '\0';
195 timeout = atoi(timeout_txt);
196 pos = os_strchr(timeout_txt, ' ');
197 if (pos) {
198 *pos++ = '\0';
199 if (hwaddr_aton(pos, addr_buf) == 0)
200 addr = addr_buf;
201 }
202 } else
203 timeout = 0;
204
205 return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
206}
207
208
209static int hostapd_ctrl_iface_wps_check_pin(
210 struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
211{
212 char pin[9];
213 size_t len;
214 char *pos;
215 int ret;
216
217 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
218 (u8 *) cmd, os_strlen(cmd));
219 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
220 if (*pos < '0' || *pos > '9')
221 continue;
222 pin[len++] = *pos;
223 if (len == 9) {
224 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
225 return -1;
226 }
227 }
228 if (len != 4 && len != 8) {
229 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
230 return -1;
231 }
232 pin[len] = '\0';
233
234 if (len == 8) {
235 unsigned int pin_val;
236 pin_val = atoi(pin);
237 if (!wps_pin_valid(pin_val)) {
238 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
239 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
240 if (ret < 0 || (size_t) ret >= buflen)
241 return -1;
242 return ret;
243 }
244 }
245
246 ret = os_snprintf(buf, buflen, "%s", pin);
247 if (ret < 0 || (size_t) ret >= buflen)
248 return -1;
249
250 return ret;
251}
252
253
Dmitry Shmidt04949592012-07-19 12:16:46 -0700254#ifdef CONFIG_WPS_NFC
255static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
256 char *pos)
257{
258 size_t len;
259 struct wpabuf *buf;
260 int ret;
261
262 len = os_strlen(pos);
263 if (len & 0x01)
264 return -1;
265 len /= 2;
266
267 buf = wpabuf_alloc(len);
268 if (buf == NULL)
269 return -1;
270 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
271 wpabuf_free(buf);
272 return -1;
273 }
274
275 ret = hostapd_wps_nfc_tag_read(hapd, buf);
276 wpabuf_free(buf);
277
278 return ret;
279}
280
281
282static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
283 char *cmd, char *reply,
284 size_t max_len)
285{
286 int ndef;
287 struct wpabuf *buf;
288 int res;
289
290 if (os_strcmp(cmd, "WPS") == 0)
291 ndef = 0;
292 else if (os_strcmp(cmd, "NDEF") == 0)
293 ndef = 1;
294 else
295 return -1;
296
297 buf = hostapd_wps_nfc_config_token(hapd, ndef);
298 if (buf == NULL)
299 return -1;
300
301 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
302 wpabuf_len(buf));
303 reply[res++] = '\n';
304 reply[res] = '\0';
305
306 wpabuf_free(buf);
307
308 return res;
309}
310
311
312static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
313 char *reply, size_t max_len,
314 int ndef)
315{
316 struct wpabuf *buf;
317 int res;
318
319 buf = hostapd_wps_nfc_token_gen(hapd, ndef);
320 if (buf == NULL)
321 return -1;
322
323 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
324 wpabuf_len(buf));
325 reply[res++] = '\n';
326 reply[res] = '\0';
327
328 wpabuf_free(buf);
329
330 return res;
331}
332
333
334static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
335 char *cmd, char *reply,
336 size_t max_len)
337{
338 if (os_strcmp(cmd, "WPS") == 0)
339 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
340 max_len, 0);
341
342 if (os_strcmp(cmd, "NDEF") == 0)
343 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
344 max_len, 1);
345
346 if (os_strcmp(cmd, "enable") == 0)
347 return hostapd_wps_nfc_token_enable(hapd);
348
349 if (os_strcmp(cmd, "disable") == 0) {
350 hostapd_wps_nfc_token_disable(hapd);
351 return 0;
352 }
353
354 return -1;
355}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800356
357
358static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
359 char *cmd, char *reply,
360 size_t max_len)
361{
362 struct wpabuf *buf;
363 int res;
364 char *pos;
365 int ndef;
366
367 pos = os_strchr(cmd, ' ');
368 if (pos == NULL)
369 return -1;
370 *pos++ = '\0';
371
372 if (os_strcmp(cmd, "WPS") == 0)
373 ndef = 0;
374 else if (os_strcmp(cmd, "NDEF") == 0)
375 ndef = 1;
376 else
377 return -1;
378
379 if (os_strcmp(pos, "WPS-CR") == 0)
380 buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
381 else
382 buf = NULL;
383 if (buf == NULL)
384 return -1;
385
386 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
387 wpabuf_len(buf));
388 reply[res++] = '\n';
389 reply[res] = '\0';
390
391 wpabuf_free(buf);
392
393 return res;
394}
395
396
397static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
398 char *cmd)
399{
400 /*
401 * Since NFC connection handover provided full WPS Credential, there is
402 * no need for additional operations within hostapd. Just report this in
403 * debug log.
404 */
405 wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
406 return 0;
407}
408
Dmitry Shmidt04949592012-07-19 12:16:46 -0700409#endif /* CONFIG_WPS_NFC */
410
411
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700412static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
413 char *buf, size_t buflen)
414{
415 int timeout = 300;
416 char *pos;
417 const char *pin_txt;
418
419 pos = os_strchr(txt, ' ');
420 if (pos)
421 *pos++ = '\0';
422
423 if (os_strcmp(txt, "disable") == 0) {
424 hostapd_wps_ap_pin_disable(hapd);
425 return os_snprintf(buf, buflen, "OK\n");
426 }
427
428 if (os_strcmp(txt, "random") == 0) {
429 if (pos)
430 timeout = atoi(pos);
431 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
432 if (pin_txt == NULL)
433 return -1;
434 return os_snprintf(buf, buflen, "%s", pin_txt);
435 }
436
437 if (os_strcmp(txt, "get") == 0) {
438 pin_txt = hostapd_wps_ap_pin_get(hapd);
439 if (pin_txt == NULL)
440 return -1;
441 return os_snprintf(buf, buflen, "%s", pin_txt);
442 }
443
444 if (os_strcmp(txt, "set") == 0) {
445 char *pin;
446 if (pos == NULL)
447 return -1;
448 pin = pos;
449 pos = os_strchr(pos, ' ');
450 if (pos) {
451 *pos++ = '\0';
452 timeout = atoi(pos);
453 }
454 if (os_strlen(pin) > buflen)
455 return -1;
456 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
457 return -1;
458 return os_snprintf(buf, buflen, "%s", pin);
459 }
460
461 return -1;
462}
463
464
465static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
466{
467 char *pos;
468 char *ssid, *auth, *encr = NULL, *key = NULL;
469
470 ssid = txt;
471 pos = os_strchr(txt, ' ');
472 if (!pos)
473 return -1;
474 *pos++ = '\0';
475
476 auth = pos;
477 pos = os_strchr(pos, ' ');
478 if (pos) {
479 *pos++ = '\0';
480 encr = pos;
481 pos = os_strchr(pos, ' ');
482 if (pos) {
483 *pos++ = '\0';
484 key = pos;
485 }
486 }
487
488 return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
489}
490#endif /* CONFIG_WPS */
491
492
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800493#ifdef CONFIG_WNM
494
495static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
496 const char *cmd)
497{
498 u8 addr[ETH_ALEN];
499 u8 buf[1000], *pos;
500 struct ieee80211_mgmt *mgmt;
501 int disassoc_timer;
502
503 if (hwaddr_aton(cmd, addr))
504 return -1;
505 if (cmd[17] != ' ')
506 return -1;
507 disassoc_timer = atoi(cmd + 17);
508
509 os_memset(buf, 0, sizeof(buf));
510 mgmt = (struct ieee80211_mgmt *) buf;
511 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
512 WLAN_FC_STYPE_ACTION);
513 os_memcpy(mgmt->da, addr, ETH_ALEN);
514 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
515 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
516 mgmt->u.action.category = WLAN_ACTION_WNM;
517 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
518 mgmt->u.action.u.bss_tm_req.dialog_token = 1;
519 mgmt->u.action.u.bss_tm_req.req_mode =
520 WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
521 mgmt->u.action.u.bss_tm_req.disassoc_timer =
522 host_to_le16(disassoc_timer);
523 mgmt->u.action.u.bss_tm_req.validity_interval = 0;
524
525 pos = mgmt->u.action.u.bss_tm_req.variable;
526
527 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
528 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
529 "Management Request frame");
530 return -1;
531 }
532
533 return 0;
534}
535
536
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800537static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
538 const char *cmd)
539{
540 u8 addr[ETH_ALEN];
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700541 const char *url, *timerstr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800542 u8 buf[1000], *pos;
543 struct ieee80211_mgmt *mgmt;
544 size_t url_len;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700545 int disassoc_timer;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800546
547 if (hwaddr_aton(cmd, addr))
548 return -1;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700549
550 timerstr = cmd + 17;
551 if (*timerstr != ' ')
552 return -1;
553 timerstr++;
554 disassoc_timer = atoi(timerstr);
555 if (disassoc_timer < 0 || disassoc_timer > 65535)
556 return -1;
557
558 url = os_strchr(timerstr, ' ');
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700559 if (url == NULL)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800560 return -1;
561 url++;
562 url_len = os_strlen(url);
563 if (url_len > 255)
564 return -1;
565
566 os_memset(buf, 0, sizeof(buf));
567 mgmt = (struct ieee80211_mgmt *) buf;
568 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
569 WLAN_FC_STYPE_ACTION);
570 os_memcpy(mgmt->da, addr, ETH_ALEN);
571 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
572 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
573 mgmt->u.action.category = WLAN_ACTION_WNM;
574 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
575 mgmt->u.action.u.bss_tm_req.dialog_token = 1;
576 mgmt->u.action.u.bss_tm_req.req_mode =
577 WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700578 mgmt->u.action.u.bss_tm_req.disassoc_timer =
579 host_to_le16(disassoc_timer);
580 mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800581
582 pos = mgmt->u.action.u.bss_tm_req.variable;
583
584 /* Session Information URL */
585 *pos++ = url_len;
586 os_memcpy(pos, url, url_len);
587 pos += url_len;
588
589 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
590 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
591 "Management Request frame");
592 return -1;
593 }
594
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700595 /* send disassociation frame after time-out */
596 if (disassoc_timer) {
597 struct sta_info *sta;
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -0700598 int timeout, beacon_int;
599
600 /*
601 * Prevent STA from reconnecting using cached PMKSA to force
602 * full authentication with the authentication server (which may
603 * decide to reject the connection),
604 */
605 wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700606
607 sta = ap_get_sta(hapd, addr);
608 if (sta == NULL) {
609 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
610 "for ESS disassociation imminent message",
611 MAC2STR(addr));
612 return -1;
613 }
614
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -0700615 beacon_int = hapd->iconf->beacon_int;
616 if (beacon_int < 1)
617 beacon_int = 100; /* best guess */
618 /* Calculate timeout in ms based on beacon_int in TU */
619 timeout = disassoc_timer * beacon_int * 128 / 125;
620 wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
621 " set to %d ms", MAC2STR(addr), timeout);
622
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700623 sta->timeout_next = STA_DISASSOC_FROM_CLI;
624 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -0700625 eloop_register_timeout(timeout / 1000,
626 timeout % 1000 * 1000,
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700627 ap_handle_timer, hapd, sta);
628 }
629
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800630 return 0;
631}
632
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800633#endif /* CONFIG_WNM */
634
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800635
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700636static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
637 char *buf, size_t buflen)
638{
639 int ret;
640 char *pos, *end;
641
642 pos = buf;
643 end = buf + buflen;
644
645 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
646 "ssid=%s\n",
647 MAC2STR(hapd->own_addr),
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700648 wpa_ssid_txt(hapd->conf->ssid.ssid,
649 hapd->conf->ssid.ssid_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700650 if (ret < 0 || ret >= end - pos)
651 return pos - buf;
652 pos += ret;
653
654#ifdef CONFIG_WPS
655 ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
656 hapd->conf->wps_state == 0 ? "disabled" :
657 (hapd->conf->wps_state == 1 ? "not configured" :
658 "configured"));
659 if (ret < 0 || ret >= end - pos)
660 return pos - buf;
661 pos += ret;
662
663 if (hapd->conf->wps_state && hapd->conf->wpa &&
664 hapd->conf->ssid.wpa_passphrase) {
665 ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
666 hapd->conf->ssid.wpa_passphrase);
667 if (ret < 0 || ret >= end - pos)
668 return pos - buf;
669 pos += ret;
670 }
671
672 if (hapd->conf->wps_state && hapd->conf->wpa &&
673 hapd->conf->ssid.wpa_psk &&
674 hapd->conf->ssid.wpa_psk->group) {
675 char hex[PMK_LEN * 2 + 1];
676 wpa_snprintf_hex(hex, sizeof(hex),
677 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
678 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
679 if (ret < 0 || ret >= end - pos)
680 return pos - buf;
681 pos += ret;
682 }
683#endif /* CONFIG_WPS */
684
685 if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
686 ret = os_snprintf(pos, end - pos, "key_mgmt=");
687 if (ret < 0 || ret >= end - pos)
688 return pos - buf;
689 pos += ret;
690
691 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
692 ret = os_snprintf(pos, end - pos, "WPA-PSK ");
693 if (ret < 0 || ret >= end - pos)
694 return pos - buf;
695 pos += ret;
696 }
697 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
698 ret = os_snprintf(pos, end - pos, "WPA-EAP ");
699 if (ret < 0 || ret >= end - pos)
700 return pos - buf;
701 pos += ret;
702 }
703#ifdef CONFIG_IEEE80211R
704 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
705 ret = os_snprintf(pos, end - pos, "FT-PSK ");
706 if (ret < 0 || ret >= end - pos)
707 return pos - buf;
708 pos += ret;
709 }
710 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
711 ret = os_snprintf(pos, end - pos, "FT-EAP ");
712 if (ret < 0 || ret >= end - pos)
713 return pos - buf;
714 pos += ret;
715 }
716#endif /* CONFIG_IEEE80211R */
717#ifdef CONFIG_IEEE80211W
718 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
719 ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
720 if (ret < 0 || ret >= end - pos)
721 return pos - buf;
722 pos += ret;
723 }
724 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
725 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
726 if (ret < 0 || ret >= end - pos)
727 return pos - buf;
728 pos += ret;
729 }
730#endif /* CONFIG_IEEE80211W */
731
732 ret = os_snprintf(pos, end - pos, "\n");
733 if (ret < 0 || ret >= end - pos)
734 return pos - buf;
735 pos += ret;
736 }
737
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800738 if (hapd->conf->wpa) {
739 ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
740 wpa_cipher_txt(hapd->conf->wpa_group));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700741 if (ret < 0 || ret >= end - pos)
742 return pos - buf;
743 pos += ret;
744 }
745
746 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
747 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
748 if (ret < 0 || ret >= end - pos)
749 return pos - buf;
750 pos += ret;
751
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800752 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
753 " ");
754 if (ret < 0)
755 return pos - buf;
756 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700757
758 ret = os_snprintf(pos, end - pos, "\n");
759 if (ret < 0 || ret >= end - pos)
760 return pos - buf;
761 pos += ret;
762 }
763
764 if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
765 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
766 if (ret < 0 || ret >= end - pos)
767 return pos - buf;
768 pos += ret;
769
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800770 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
771 " ");
772 if (ret < 0)
773 return pos - buf;
774 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700775
776 ret = os_snprintf(pos, end - pos, "\n");
777 if (ret < 0 || ret >= end - pos)
778 return pos - buf;
779 pos += ret;
780 }
781
782 return pos - buf;
783}
784
785
786static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
787{
788 char *value;
789 int ret = 0;
790
791 value = os_strchr(cmd, ' ');
792 if (value == NULL)
793 return -1;
794 *value++ = '\0';
795
796 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
797 if (0) {
798#ifdef CONFIG_WPS_TESTING
799 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
800 long int val;
801 val = strtol(value, NULL, 0);
802 if (val < 0 || val > 0xff) {
803 ret = -1;
804 wpa_printf(MSG_DEBUG, "WPS: Invalid "
805 "wps_version_number %ld", val);
806 } else {
807 wps_version_number = val;
808 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
809 "version %u.%u",
810 (wps_version_number & 0xf0) >> 4,
811 wps_version_number & 0x0f);
812 hostapd_wps_update_ie(hapd);
813 }
814 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
815 wps_testing_dummy_cred = atoi(value);
816 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
817 wps_testing_dummy_cred);
818#endif /* CONFIG_WPS_TESTING */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700819#ifdef CONFIG_INTERWORKING
820 } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
821 int val = atoi(value);
822 if (val <= 0)
823 ret = -1;
824 else
825 hapd->gas_frag_limit = val;
826#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700827 } else {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700828 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700829 }
830
831 return ret;
832}
833
834
835static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
836 char *buf, size_t buflen)
837{
838 int res;
839
840 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
841
842 if (os_strcmp(cmd, "version") == 0) {
843 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
844 if (res < 0 || (unsigned int) res >= buflen)
845 return -1;
846 return res;
847 }
848
849 return -1;
850}
851
852
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700853static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
854{
855 if (hostapd_enable_iface(iface) < 0) {
856 wpa_printf(MSG_ERROR, "Enabling of interface failed");
857 return -1;
858 }
859 return 0;
860}
861
862
863static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
864{
865 if (hostapd_reload_iface(iface) < 0) {
866 wpa_printf(MSG_ERROR, "Reloading of interface failed");
867 return -1;
868 }
869 return 0;
870}
871
872
873static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
874{
875 if (hostapd_disable_iface(iface) < 0) {
876 wpa_printf(MSG_ERROR, "Disabling of interface failed");
877 return -1;
878 }
879 return 0;
880}
881
882
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700883static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
884 void *sock_ctx)
885{
886 struct hostapd_data *hapd = eloop_ctx;
887 char buf[256];
888 int res;
889 struct sockaddr_un from;
890 socklen_t fromlen = sizeof(from);
891 char *reply;
892 const int reply_size = 4096;
893 int reply_len;
894 int level = MSG_DEBUG;
895
896 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
897 (struct sockaddr *) &from, &fromlen);
898 if (res < 0) {
899 perror("recvfrom(ctrl_iface)");
900 return;
901 }
902 buf[res] = '\0';
903 if (os_strcmp(buf, "PING") == 0)
904 level = MSG_EXCESSIVE;
905 wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
906
907 reply = os_malloc(reply_size);
908 if (reply == NULL) {
909 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
910 fromlen);
911 return;
912 }
913
914 os_memcpy(reply, "OK\n", 3);
915 reply_len = 3;
916
917 if (os_strcmp(buf, "PING") == 0) {
918 os_memcpy(reply, "PONG\n", 5);
919 reply_len = 5;
920 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
921 if (wpa_debug_reopen_file() < 0)
922 reply_len = -1;
923 } else if (os_strcmp(buf, "MIB") == 0) {
924 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
925 if (reply_len >= 0) {
926 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
927 reply_size - reply_len);
928 if (res < 0)
929 reply_len = -1;
930 else
931 reply_len += res;
932 }
933 if (reply_len >= 0) {
934 res = ieee802_1x_get_mib(hapd, reply + reply_len,
935 reply_size - reply_len);
936 if (res < 0)
937 reply_len = -1;
938 else
939 reply_len += res;
940 }
941#ifndef CONFIG_NO_RADIUS
942 if (reply_len >= 0) {
943 res = radius_client_get_mib(hapd->radius,
944 reply + reply_len,
945 reply_size - reply_len);
946 if (res < 0)
947 reply_len = -1;
948 else
949 reply_len += res;
950 }
951#endif /* CONFIG_NO_RADIUS */
952 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
953 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
954 reply_size);
955 } else if (os_strncmp(buf, "STA ", 4) == 0) {
956 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
957 reply_size);
958 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
959 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
960 reply_size);
961 } else if (os_strcmp(buf, "ATTACH") == 0) {
962 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
963 reply_len = -1;
964 } else if (os_strcmp(buf, "DETACH") == 0) {
965 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
966 reply_len = -1;
967 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
968 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
969 buf + 6))
970 reply_len = -1;
971 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
972 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
973 reply_len = -1;
974 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
975 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
976 reply_len = -1;
977 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
978 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
979 reply_len = -1;
980#ifdef CONFIG_IEEE80211W
981#ifdef NEED_AP_MLME
982 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
983 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
984 reply_len = -1;
985#endif /* NEED_AP_MLME */
986#endif /* CONFIG_IEEE80211W */
987#ifdef CONFIG_WPS
988 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
989 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
990 reply_len = -1;
991 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
992 reply_len = hostapd_ctrl_iface_wps_check_pin(
993 hapd, buf + 14, reply, reply_size);
994 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
995 if (hostapd_wps_button_pushed(hapd, NULL))
996 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700997 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
998 if (hostapd_wps_cancel(hapd))
999 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001000 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
1001 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
1002 reply, reply_size);
1003 } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
1004 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
1005 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001006#ifdef CONFIG_WPS_NFC
1007 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
1008 if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
1009 reply_len = -1;
1010 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
1011 reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
1012 hapd, buf + 21, reply, reply_size);
1013 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
1014 reply_len = hostapd_ctrl_iface_wps_nfc_token(
1015 hapd, buf + 14, reply, reply_size);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001016 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
1017 reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
1018 hapd, buf + 21, reply, reply_size);
1019 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
1020 if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
1021 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001022#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001023#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001024#ifdef CONFIG_WNM
1025 } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
1026 if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
1027 reply_len = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001028 } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
1029 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
1030 reply_len = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001031#endif /* CONFIG_WNM */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001032 } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
1033 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
1034 reply_size);
1035 } else if (os_strncmp(buf, "SET ", 4) == 0) {
1036 if (hostapd_ctrl_iface_set(hapd, buf + 4))
1037 reply_len = -1;
1038 } else if (os_strncmp(buf, "GET ", 4) == 0) {
1039 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
1040 reply_size);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001041 } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
1042 if (hostapd_ctrl_iface_enable(hapd->iface))
1043 reply_len = -1;
1044 } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
1045 if (hostapd_ctrl_iface_reload(hapd->iface))
1046 reply_len = -1;
1047 } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
1048 if (hostapd_ctrl_iface_disable(hapd->iface))
1049 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001050 } else {
1051 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1052 reply_len = 16;
1053 }
1054
1055 if (reply_len < 0) {
1056 os_memcpy(reply, "FAIL\n", 5);
1057 reply_len = 5;
1058 }
1059 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1060 os_free(reply);
1061}
1062
1063
1064static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
1065{
1066 char *buf;
1067 size_t len;
1068
1069 if (hapd->conf->ctrl_interface == NULL)
1070 return NULL;
1071
1072 len = os_strlen(hapd->conf->ctrl_interface) +
1073 os_strlen(hapd->conf->iface) + 2;
1074 buf = os_malloc(len);
1075 if (buf == NULL)
1076 return NULL;
1077
1078 os_snprintf(buf, len, "%s/%s",
1079 hapd->conf->ctrl_interface, hapd->conf->iface);
1080 buf[len - 1] = '\0';
1081 return buf;
1082}
1083
1084
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001085static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001086 const char *txt, size_t len)
1087{
1088 struct hostapd_data *hapd = ctx;
1089 if (hapd == NULL)
1090 return;
1091 hostapd_ctrl_iface_send(hapd, level, txt, len);
1092}
1093
1094
1095int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
1096{
1097 struct sockaddr_un addr;
1098 int s = -1;
1099 char *fname = NULL;
1100
Dmitry Shmidt04949592012-07-19 12:16:46 -07001101 if (hapd->ctrl_sock > -1) {
1102 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
1103 return 0;
1104 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001105
1106 if (hapd->conf->ctrl_interface == NULL)
1107 return 0;
1108
1109 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1110 if (errno == EEXIST) {
1111 wpa_printf(MSG_DEBUG, "Using existing control "
1112 "interface directory.");
1113 } else {
1114 perror("mkdir[ctrl_interface]");
1115 goto fail;
1116 }
1117 }
1118
1119 if (hapd->conf->ctrl_interface_gid_set &&
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001120 chown(hapd->conf->ctrl_interface, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001121 hapd->conf->ctrl_interface_gid) < 0) {
1122 perror("chown[ctrl_interface]");
1123 return -1;
1124 }
1125
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07001126 if (!hapd->conf->ctrl_interface_gid_set &&
1127 hapd->iface->interfaces->ctrl_iface_group &&
1128 chown(hapd->conf->ctrl_interface, -1,
1129 hapd->iface->interfaces->ctrl_iface_group) < 0) {
1130 perror("chown[ctrl_interface]");
1131 return -1;
1132 }
1133
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001134#ifdef ANDROID
1135 /*
1136 * Android is using umask 0077 which would leave the control interface
1137 * directory without group access. This breaks things since Wi-Fi
1138 * framework assumes that this directory can be accessed by other
1139 * applications in the wifi group. Fix this by adding group access even
1140 * if umask value would prevent this.
1141 */
1142 if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1143 wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
1144 strerror(errno));
1145 /* Try to continue anyway */
1146 }
1147#endif /* ANDROID */
1148
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001149 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
1150 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
1151 goto fail;
1152
1153 s = socket(PF_UNIX, SOCK_DGRAM, 0);
1154 if (s < 0) {
1155 perror("socket(PF_UNIX)");
1156 goto fail;
1157 }
1158
1159 os_memset(&addr, 0, sizeof(addr));
1160#ifdef __FreeBSD__
1161 addr.sun_len = sizeof(addr);
1162#endif /* __FreeBSD__ */
1163 addr.sun_family = AF_UNIX;
1164 fname = hostapd_ctrl_iface_path(hapd);
1165 if (fname == NULL)
1166 goto fail;
1167 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1168 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1169 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1170 strerror(errno));
1171 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1172 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1173 " allow connections - assuming it was left"
1174 "over from forced program termination");
1175 if (unlink(fname) < 0) {
1176 perror("unlink[ctrl_iface]");
1177 wpa_printf(MSG_ERROR, "Could not unlink "
1178 "existing ctrl_iface socket '%s'",
1179 fname);
1180 goto fail;
1181 }
1182 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1183 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001184 perror("hostapd-ctrl-iface: bind(PF_UNIX)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001185 goto fail;
1186 }
1187 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1188 "ctrl_iface socket '%s'", fname);
1189 } else {
1190 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1191 "be in use - cannot override it");
1192 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1193 "not used anymore", fname);
1194 os_free(fname);
1195 fname = NULL;
1196 goto fail;
1197 }
1198 }
1199
1200 if (hapd->conf->ctrl_interface_gid_set &&
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001201 chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001202 perror("chown[ctrl_interface/ifname]");
1203 goto fail;
1204 }
1205
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07001206 if (!hapd->conf->ctrl_interface_gid_set &&
1207 hapd->iface->interfaces->ctrl_iface_group &&
1208 chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
1209 perror("chown[ctrl_interface/ifname]");
1210 goto fail;
1211 }
1212
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001213 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1214 perror("chmod[ctrl_interface/ifname]");
1215 goto fail;
1216 }
1217 os_free(fname);
1218
1219 hapd->ctrl_sock = s;
1220 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
1221 NULL);
1222 hapd->msg_ctx = hapd;
1223 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
1224
1225 return 0;
1226
1227fail:
1228 if (s >= 0)
1229 close(s);
1230 if (fname) {
1231 unlink(fname);
1232 os_free(fname);
1233 }
1234 return -1;
1235}
1236
1237
1238void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
1239{
1240 struct wpa_ctrl_dst *dst, *prev;
1241
1242 if (hapd->ctrl_sock > -1) {
1243 char *fname;
1244 eloop_unregister_read_sock(hapd->ctrl_sock);
1245 close(hapd->ctrl_sock);
1246 hapd->ctrl_sock = -1;
1247 fname = hostapd_ctrl_iface_path(hapd);
1248 if (fname)
1249 unlink(fname);
1250 os_free(fname);
1251
1252 if (hapd->conf->ctrl_interface &&
1253 rmdir(hapd->conf->ctrl_interface) < 0) {
1254 if (errno == ENOTEMPTY) {
1255 wpa_printf(MSG_DEBUG, "Control interface "
1256 "directory not empty - leaving it "
1257 "behind");
1258 } else {
1259 perror("rmdir[ctrl_interface]");
1260 }
1261 }
1262 }
1263
1264 dst = hapd->ctrl_dst;
1265 while (dst) {
1266 prev = dst;
1267 dst = dst->next;
1268 os_free(prev);
1269 }
1270}
1271
1272
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001273static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
1274 char *buf)
1275{
1276 if (hostapd_add_iface(interfaces, buf) < 0) {
1277 wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
1278 return -1;
1279 }
1280 return 0;
1281}
1282
1283
1284static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
1285 char *buf)
1286{
1287 if (hostapd_remove_iface(interfaces, buf) < 0) {
1288 wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
1289 return -1;
1290 }
1291 return 0;
1292}
1293
1294
1295static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
1296 void *sock_ctx)
1297{
1298 void *interfaces = eloop_ctx;
1299 char buf[256];
1300 int res;
1301 struct sockaddr_un from;
1302 socklen_t fromlen = sizeof(from);
1303 char reply[24];
1304 int reply_len;
1305
1306 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1307 (struct sockaddr *) &from, &fromlen);
1308 if (res < 0) {
1309 perror("recvfrom(ctrl_iface)");
1310 return;
1311 }
1312 buf[res] = '\0';
1313
1314 os_memcpy(reply, "OK\n", 3);
1315 reply_len = 3;
1316
1317 if (os_strcmp(buf, "PING") == 0) {
1318 os_memcpy(reply, "PONG\n", 5);
1319 reply_len = 5;
1320 } else if (os_strncmp(buf, "ADD ", 4) == 0) {
1321 if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
1322 reply_len = -1;
1323 } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
1324 if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
1325 reply_len = -1;
1326 } else {
1327 wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
1328 "ignored");
1329 reply_len = -1;
1330 }
1331
1332 if (reply_len < 0) {
1333 os_memcpy(reply, "FAIL\n", 5);
1334 reply_len = 5;
1335 }
1336
1337 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1338}
1339
1340
1341static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
1342{
1343 char *buf;
1344 size_t len;
1345
1346 if (interface->global_iface_path == NULL)
1347 return NULL;
1348
1349 len = os_strlen(interface->global_iface_path) +
1350 os_strlen(interface->global_iface_name) + 2;
1351 buf = os_malloc(len);
1352 if (buf == NULL)
1353 return NULL;
1354
1355 os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
1356 interface->global_iface_name);
1357 buf[len - 1] = '\0';
1358 return buf;
1359}
1360
1361
1362int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
1363{
1364 struct sockaddr_un addr;
1365 int s = -1;
1366 char *fname = NULL;
1367
1368 if (interface->global_iface_path == NULL) {
1369 wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
1370 return 0;
1371 }
1372
1373 if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
1374 if (errno == EEXIST) {
1375 wpa_printf(MSG_DEBUG, "Using existing control "
1376 "interface directory.");
1377 } else {
1378 perror("mkdir[ctrl_interface]");
1379 goto fail;
1380 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07001381 } else if (interface->ctrl_iface_group &&
1382 chown(interface->global_iface_path, -1,
1383 interface->ctrl_iface_group) < 0) {
1384 perror("chown[ctrl_interface]");
1385 goto fail;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001386 }
1387
1388 if (os_strlen(interface->global_iface_path) + 1 +
1389 os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
1390 goto fail;
1391
1392 s = socket(PF_UNIX, SOCK_DGRAM, 0);
1393 if (s < 0) {
1394 perror("socket(PF_UNIX)");
1395 goto fail;
1396 }
1397
1398 os_memset(&addr, 0, sizeof(addr));
1399#ifdef __FreeBSD__
1400 addr.sun_len = sizeof(addr);
1401#endif /* __FreeBSD__ */
1402 addr.sun_family = AF_UNIX;
1403 fname = hostapd_global_ctrl_iface_path(interface);
1404 if (fname == NULL)
1405 goto fail;
1406 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1407 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1408 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1409 strerror(errno));
1410 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1411 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1412 " allow connections - assuming it was left"
1413 "over from forced program termination");
1414 if (unlink(fname) < 0) {
1415 perror("unlink[ctrl_iface]");
1416 wpa_printf(MSG_ERROR, "Could not unlink "
1417 "existing ctrl_iface socket '%s'",
1418 fname);
1419 goto fail;
1420 }
1421 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1422 0) {
1423 perror("bind(PF_UNIX)");
1424 goto fail;
1425 }
1426 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1427 "ctrl_iface socket '%s'", fname);
1428 } else {
1429 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1430 "be in use - cannot override it");
1431 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1432 "not used anymore", fname);
1433 os_free(fname);
1434 fname = NULL;
1435 goto fail;
1436 }
1437 }
1438
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07001439 if (interface->ctrl_iface_group &&
1440 chown(fname, -1, interface->ctrl_iface_group) < 0) {
1441 perror("chown[ctrl_interface]");
1442 goto fail;
1443 }
1444
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001445 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1446 perror("chmod[ctrl_interface/ifname]");
1447 goto fail;
1448 }
1449 os_free(fname);
1450
1451 interface->global_ctrl_sock = s;
1452 eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
1453 interface, NULL);
1454
1455 return 0;
1456
1457fail:
1458 if (s >= 0)
1459 close(s);
1460 if (fname) {
1461 unlink(fname);
1462 os_free(fname);
1463 }
1464 return -1;
1465}
1466
1467
1468void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
1469{
1470 char *fname = NULL;
1471
1472 if (interfaces->global_ctrl_sock > -1) {
1473 eloop_unregister_read_sock(interfaces->global_ctrl_sock);
1474 close(interfaces->global_ctrl_sock);
1475 interfaces->global_ctrl_sock = -1;
1476 fname = hostapd_global_ctrl_iface_path(interfaces);
1477 if (fname) {
1478 unlink(fname);
1479 os_free(fname);
1480 }
1481
1482 if (interfaces->global_iface_path &&
1483 rmdir(interfaces->global_iface_path) < 0) {
1484 if (errno == ENOTEMPTY) {
1485 wpa_printf(MSG_DEBUG, "Control interface "
1486 "directory not empty - leaving it "
1487 "behind");
1488 } else {
1489 perror("rmdir[ctrl_interface]");
1490 }
1491 }
1492 os_free(interfaces->global_iface_path);
1493 interfaces->global_iface_path = NULL;
1494 }
1495}
1496
1497
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001498static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1499 const char *buf, size_t len)
1500{
1501 struct wpa_ctrl_dst *dst, *next;
1502 struct msghdr msg;
1503 int idx;
1504 struct iovec io[2];
1505 char levelstr[10];
1506
1507 dst = hapd->ctrl_dst;
1508 if (hapd->ctrl_sock < 0 || dst == NULL)
1509 return;
1510
1511 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1512 io[0].iov_base = levelstr;
1513 io[0].iov_len = os_strlen(levelstr);
1514 io[1].iov_base = (char *) buf;
1515 io[1].iov_len = len;
1516 os_memset(&msg, 0, sizeof(msg));
1517 msg.msg_iov = io;
1518 msg.msg_iovlen = 2;
1519
1520 idx = 0;
1521 while (dst) {
1522 next = dst->next;
1523 if (level >= dst->debug_level) {
1524 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1525 (u8 *) dst->addr.sun_path, dst->addrlen -
1526 offsetof(struct sockaddr_un, sun_path));
1527 msg.msg_name = &dst->addr;
1528 msg.msg_namelen = dst->addrlen;
1529 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1530 int _errno = errno;
1531 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1532 "%d - %s",
1533 idx, errno, strerror(errno));
1534 dst->errors++;
1535 if (dst->errors > 10 || _errno == ENOENT) {
1536 hostapd_ctrl_iface_detach(
1537 hapd, &dst->addr,
1538 dst->addrlen);
1539 }
1540 } else
1541 dst->errors = 0;
1542 }
1543 idx++;
1544 dst = next;
1545 }
1546}
1547
1548#endif /* CONFIG_NATIVE_WINDOWS */