]> git.ipfire.org Git - thirdparty/hostap.git/blame - hostapd/ctrl_iface.c
tests: Add a GAS comeback delay test case
[thirdparty/hostap.git] / hostapd / ctrl_iface.c
CommitLineData
6fc6879b
JM
1/*
2 * hostapd / UNIX domain socket -based control interface
3f134b43 3 * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
6226e38d 9#include "utils/includes.h"
6fc6879b
JM
10
11#ifndef CONFIG_NATIVE_WINDOWS
12
13#include <sys/un.h>
14#include <sys/stat.h>
75864b7f 15#include <stddef.h>
6fc6879b 16
6226e38d
JM
17#include "utils/common.h"
18#include "utils/eloop.h"
acec8d32 19#include "common/version.h"
81f4f619 20#include "common/ieee802_11_defs.h"
1057d78e 21#include "drivers/driver.h"
6fc6879b 22#include "radius/radius_client.h"
1057d78e 23#include "ap/hostapd.h"
6226e38d 24#include "ap/ap_config.h"
1057d78e 25#include "ap/ieee802_1x.h"
6226e38d 26#include "ap/wpa_auth.h"
1057d78e
JM
27#include "ap/ieee802_11.h"
28#include "ap/sta_info.h"
32da61d9 29#include "ap/wps_hostapd.h"
0e2d35c6 30#include "ap/ctrl_iface_ap.h"
51e2a27a 31#include "ap/ap_drv_ops.h"
901d1fe1 32#include "ap/wpa_auth.h"
b4e34f2f 33#include "wps/wps_defs.h"
3981cb3c 34#include "wps/wps.h"
31b79e11 35#include "config_file.h"
6fc6879b 36#include "ctrl_iface.h"
6fc6879b
JM
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
42d16805
JM
48static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
49 const char *buf, size_t len);
50
51
6fc6879b
JM
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",
75864b7f
JM
67 (u8 *) from->sun_path,
68 fromlen - offsetof(struct sockaddr_un, sun_path));
6fc6879b
JM
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 &&
75864b7f
JM
82 os_memcmp(from->sun_path, dst->addr.sun_path,
83 fromlen - offsetof(struct sockaddr_un, sun_path))
84 == 0) {
8540e0b5
JM
85 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
86 (u8 *) from->sun_path,
87 fromlen -
88 offsetof(struct sockaddr_un, sun_path));
6fc6879b
JM
89 if (prev == NULL)
90 hapd->ctrl_dst = dst->next;
91 else
92 prev->next = dst->next;
93 os_free(dst);
6fc6879b
JM
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 &&
75864b7f
JM
115 os_memcmp(from->sun_path, dst->addr.sun_path,
116 fromlen - offsetof(struct sockaddr_un, sun_path))
117 == 0) {
6fc6879b 118 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
75864b7f
JM
119 "level", (u8 *) from->sun_path, fromlen -
120 offsetof(struct sockaddr_un, sun_path));
6fc6879b
JM
121 dst->debug_level = atoi(level);
122 return 0;
123 }
124 dst = dst->next;
125 }
126
127 return -1;
128}
129
130
6fc6879b
JM
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);
6fc6879b
JM
153 return 0;
154}
155
156
88b4b424 157#ifdef CONFIG_IEEE80211W
fe6bdb77 158#ifdef NEED_AP_MLME
88b4b424
JM
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
f5455a2d
JM
167 if (hwaddr_aton(txtaddr, addr) ||
168 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
88b4b424
JM
169 return -1;
170
88b4b424
JM
171 ieee802_11_send_sa_query_req(hapd, addr, trans_id);
172
173 return 0;
174}
fe6bdb77 175#endif /* NEED_AP_MLME */
88b4b424
JM
176#endif /* CONFIG_IEEE80211W */
177
178
ad08c363
JM
179#ifdef CONFIG_WPS
180static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
181{
182 char *pin = os_strchr(txt, ' ');
077a781f
JM
183 char *timeout_txt;
184 int timeout;
31fcea93
JM
185 u8 addr_buf[ETH_ALEN], *addr = NULL;
186 char *pos;
077a781f 187
ad08c363
JM
188 if (pin == NULL)
189 return -1;
190 *pin++ = '\0';
077a781f
JM
191
192 timeout_txt = os_strchr(pin, ' ');
193 if (timeout_txt) {
194 *timeout_txt++ = '\0';
195 timeout = atoi(timeout_txt);
31fcea93
JM
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 }
077a781f
JM
202 } else
203 timeout = 0;
204
31fcea93 205 return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
ad08c363 206}
46bdb83a
MH
207
208
3981cb3c
JM
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
bb45b6d7
JM
254#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}
3cf7a59d
JM
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}
ffdaa05a
JM
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}
6772a90a
JM
356
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
e4758827
JM
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
bb45b6d7
JM
409#endif /* CONFIG_WPS_NFC */
410
411
5a1cc30f
JM
412static 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}
450eddcf
JM
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}
3351a384
JM
490
491
492static const char * pbc_status_str(enum pbc_status status)
493{
494 switch (status) {
495 case WPS_PBC_STATUS_DISABLE:
496 return "Disabled";
497 case WPS_PBC_STATUS_ACTIVE:
498 return "Active";
499 case WPS_PBC_STATUS_TIMEOUT:
500 return "Timed-out";
501 case WPS_PBC_STATUS_OVERLAP:
502 return "Overlap";
503 default:
504 return "Unknown";
505 }
506}
507
508
509static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
510 char *buf, size_t buflen)
511{
512 int ret;
513 char *pos, *end;
514
515 pos = buf;
516 end = buf + buflen;
517
518 ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
519 pbc_status_str(hapd->wps_stats.pbc_status));
520
521 if (ret < 0 || ret >= end - pos)
522 return pos - buf;
523 pos += ret;
524
525 ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
526 (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
527 "Success":
528 (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
529 "Failed" : "None")));
530
531 if (ret < 0 || ret >= end - pos)
532 return pos - buf;
533 pos += ret;
534
535 /* If status == Failure - Add possible Reasons */
536 if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
537 hapd->wps_stats.failure_reason > 0) {
538 ret = os_snprintf(pos, end - pos,
539 "Failure Reason: %s\n",
540 wps_ei_str(hapd->wps_stats.failure_reason));
541
542 if (ret < 0 || ret >= end - pos)
543 return pos - buf;
544 pos += ret;
545 }
546
547 if (hapd->wps_stats.status) {
548 ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
549 MAC2STR(hapd->wps_stats.peer_addr));
550
551 if (ret < 0 || ret >= end - pos)
552 return pos - buf;
553 pos += ret;
554 }
555
556 return pos - buf;
557}
558
ad08c363
JM
559#endif /* CONFIG_WPS */
560
561
c551700f
KP
562#ifdef CONFIG_INTERWORKING
563
564static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
565 const char *cmd)
566{
567 u8 qos_map_set[16 + 2 * 21], count = 0;
568 const char *pos = cmd;
569 int val, ret;
570
571 for (;;) {
572 if (count == sizeof(qos_map_set)) {
573 wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
574 return -1;
575 }
576
577 val = atoi(pos);
578 if (val < 0 || val > 255) {
579 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
580 return -1;
581 }
582
583 qos_map_set[count++] = val;
584 pos = os_strchr(pos, ',');
585 if (!pos)
586 break;
587 pos++;
588 }
589
590 if (count < 16 || count & 1) {
591 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
592 return -1;
593 }
594
595 ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
596 if (ret) {
597 wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
598 return -1;
599 }
600
601 os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
602 hapd->conf->qos_map_set_len = count;
603
604 return 0;
605}
606
607
608static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
609 const char *cmd)
610{
611 u8 addr[ETH_ALEN];
612 struct sta_info *sta;
613 struct wpabuf *buf;
614 u8 *qos_map_set = hapd->conf->qos_map_set;
615 u8 qos_map_set_len = hapd->conf->qos_map_set_len;
616 int ret;
617
618 if (!qos_map_set_len) {
619 wpa_printf(MSG_INFO, "QoS Map Set is not set");
620 return -1;
621 }
622
623 if (hwaddr_aton(cmd, addr))
624 return -1;
625
626 sta = ap_get_sta(hapd, addr);
627 if (sta == NULL) {
628 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
629 "for QoS Map Configuration message",
630 MAC2STR(addr));
631 return -1;
632 }
633
634 if (!sta->qos_map_enabled) {
635 wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
636 "support for QoS Map", MAC2STR(addr));
637 return -1;
638 }
639
640 buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
641 if (buf == NULL)
642 return -1;
643
644 wpabuf_put_u8(buf, WLAN_ACTION_QOS);
645 wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
646
647 /* QoS Map Set Element */
648 wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
649 wpabuf_put_u8(buf, qos_map_set_len);
650 wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
651
652 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
653 wpabuf_head(buf), wpabuf_len(buf));
654 wpabuf_free(buf);
655
656 return ret;
657}
658
659#endif /* CONFIG_INTERWORKING */
660
661
2049a875
JM
662#ifdef CONFIG_WNM
663
664static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
665 const char *cmd)
666{
667 u8 addr[ETH_ALEN];
668 u8 buf[1000], *pos;
669 struct ieee80211_mgmt *mgmt;
670 int disassoc_timer;
671
672 if (hwaddr_aton(cmd, addr))
673 return -1;
674 if (cmd[17] != ' ')
675 return -1;
676 disassoc_timer = atoi(cmd + 17);
677
678 os_memset(buf, 0, sizeof(buf));
679 mgmt = (struct ieee80211_mgmt *) buf;
680 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
681 WLAN_FC_STYPE_ACTION);
682 os_memcpy(mgmt->da, addr, ETH_ALEN);
683 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
684 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
685 mgmt->u.action.category = WLAN_ACTION_WNM;
686 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
687 mgmt->u.action.u.bss_tm_req.dialog_token = 1;
688 mgmt->u.action.u.bss_tm_req.req_mode =
689 WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
690 mgmt->u.action.u.bss_tm_req.disassoc_timer =
691 host_to_le16(disassoc_timer);
692 mgmt->u.action.u.bss_tm_req.validity_interval = 0;
693
694 pos = mgmt->u.action.u.bss_tm_req.variable;
695
696 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
697 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
698 "Management Request frame");
699 return -1;
700 }
701
702 return 0;
703}
704
705
71269b37
JM
706static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
707 const char *cmd)
708{
709 u8 addr[ETH_ALEN];
d5b559b6 710 const char *url, *timerstr;
71269b37
JM
711 u8 buf[1000], *pos;
712 struct ieee80211_mgmt *mgmt;
713 size_t url_len;
d5b559b6 714 int disassoc_timer;
71269b37
JM
715
716 if (hwaddr_aton(cmd, addr))
717 return -1;
d5b559b6
KP
718
719 timerstr = cmd + 17;
720 if (*timerstr != ' ')
721 return -1;
722 timerstr++;
723 disassoc_timer = atoi(timerstr);
724 if (disassoc_timer < 0 || disassoc_timer > 65535)
725 return -1;
726
727 url = os_strchr(timerstr, ' ');
eb4737f6 728 if (url == NULL)
71269b37
JM
729 return -1;
730 url++;
731 url_len = os_strlen(url);
732 if (url_len > 255)
733 return -1;
734
735 os_memset(buf, 0, sizeof(buf));
736 mgmt = (struct ieee80211_mgmt *) buf;
737 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
738 WLAN_FC_STYPE_ACTION);
739 os_memcpy(mgmt->da, addr, ETH_ALEN);
740 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
741 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
742 mgmt->u.action.category = WLAN_ACTION_WNM;
743 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
744 mgmt->u.action.u.bss_tm_req.dialog_token = 1;
745 mgmt->u.action.u.bss_tm_req.req_mode =
0cf0af2e 746 WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
71269b37 747 WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
d5b559b6
KP
748 mgmt->u.action.u.bss_tm_req.disassoc_timer =
749 host_to_le16(disassoc_timer);
750 mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
71269b37
JM
751
752 pos = mgmt->u.action.u.bss_tm_req.variable;
753
754 /* Session Information URL */
755 *pos++ = url_len;
756 os_memcpy(pos, url, url_len);
757 pos += url_len;
758
8cfa3527 759 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
71269b37
JM
760 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
761 "Management Request frame");
762 return -1;
763 }
764
d5b559b6
KP
765 /* send disassociation frame after time-out */
766 if (disassoc_timer) {
767 struct sta_info *sta;
8e1bc702 768 int timeout, beacon_int;
d5b559b6 769
901d1fe1
JM
770 /*
771 * Prevent STA from reconnecting using cached PMKSA to force
772 * full authentication with the authentication server (which may
773 * decide to reject the connection),
774 */
775 wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
776
d5b559b6
KP
777 sta = ap_get_sta(hapd, addr);
778 if (sta == NULL) {
779 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
780 "for ESS disassociation imminent message",
781 MAC2STR(addr));
782 return -1;
783 }
784
8e1bc702
JM
785 beacon_int = hapd->iconf->beacon_int;
786 if (beacon_int < 1)
787 beacon_int = 100; /* best guess */
788 /* Calculate timeout in ms based on beacon_int in TU */
789 timeout = disassoc_timer * beacon_int * 128 / 125;
790 wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
791 " set to %d ms", MAC2STR(addr), timeout);
792
d5b559b6
KP
793 sta->timeout_next = STA_DISASSOC_FROM_CLI;
794 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
8e1bc702
JM
795 eloop_register_timeout(timeout / 1000,
796 timeout % 1000 * 1000,
d5b559b6
KP
797 ap_handle_timer, hapd, sta);
798 }
799
71269b37
JM
800 return 0;
801}
802
2049a875
JM
803#endif /* CONFIG_WNM */
804
71269b37 805
403b96fe
JM
806static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
807 char *buf, size_t buflen)
808{
809 int ret;
810 char *pos, *end;
811
812 pos = buf;
813 end = buf + buflen;
814
815 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
816 "ssid=%s\n",
817 MAC2STR(hapd->own_addr),
986de33d
JM
818 wpa_ssid_txt(hapd->conf->ssid.ssid,
819 hapd->conf->ssid.ssid_len));
403b96fe
JM
820 if (ret < 0 || ret >= end - pos)
821 return pos - buf;
822 pos += ret;
823
824#ifdef CONFIG_WPS
825 ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
826 hapd->conf->wps_state == 0 ? "disabled" :
827 (hapd->conf->wps_state == 1 ? "not configured" :
828 "configured"));
829 if (ret < 0 || ret >= end - pos)
830 return pos - buf;
831 pos += ret;
832
088a2255 833 if (hapd->conf->wps_state && hapd->conf->wpa &&
403b96fe
JM
834 hapd->conf->ssid.wpa_passphrase) {
835 ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
836 hapd->conf->ssid.wpa_passphrase);
837 if (ret < 0 || ret >= end - pos)
838 return pos - buf;
839 pos += ret;
840 }
841
088a2255
JM
842 if (hapd->conf->wps_state && hapd->conf->wpa &&
843 hapd->conf->ssid.wpa_psk &&
403b96fe
JM
844 hapd->conf->ssid.wpa_psk->group) {
845 char hex[PMK_LEN * 2 + 1];
846 wpa_snprintf_hex(hex, sizeof(hex),
847 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
848 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
849 if (ret < 0 || ret >= end - pos)
850 return pos - buf;
851 pos += ret;
852 }
853#endif /* CONFIG_WPS */
854
855 if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
856 ret = os_snprintf(pos, end - pos, "key_mgmt=");
857 if (ret < 0 || ret >= end - pos)
858 return pos - buf;
859 pos += ret;
860
861 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
862 ret = os_snprintf(pos, end - pos, "WPA-PSK ");
863 if (ret < 0 || ret >= end - pos)
864 return pos - buf;
865 pos += ret;
866 }
867 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
868 ret = os_snprintf(pos, end - pos, "WPA-EAP ");
869 if (ret < 0 || ret >= end - pos)
870 return pos - buf;
871 pos += ret;
872 }
873#ifdef CONFIG_IEEE80211R
874 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
875 ret = os_snprintf(pos, end - pos, "FT-PSK ");
876 if (ret < 0 || ret >= end - pos)
877 return pos - buf;
878 pos += ret;
879 }
880 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
881 ret = os_snprintf(pos, end - pos, "FT-EAP ");
882 if (ret < 0 || ret >= end - pos)
883 return pos - buf;
884 pos += ret;
885 }
886#endif /* CONFIG_IEEE80211R */
887#ifdef CONFIG_IEEE80211W
888 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
889 ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
890 if (ret < 0 || ret >= end - pos)
891 return pos - buf;
892 pos += ret;
893 }
894 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
895 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
896 if (ret < 0 || ret >= end - pos)
897 return pos - buf;
898 pos += ret;
899 }
900#endif /* CONFIG_IEEE80211W */
901
902 ret = os_snprintf(pos, end - pos, "\n");
903 if (ret < 0 || ret >= end - pos)
904 return pos - buf;
905 pos += ret;
906 }
907
0282a8c4
JM
908 if (hapd->conf->wpa) {
909 ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
910 wpa_cipher_txt(hapd->conf->wpa_group));
403b96fe
JM
911 if (ret < 0 || ret >= end - pos)
912 return pos - buf;
913 pos += ret;
914 }
915
916 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
917 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
918 if (ret < 0 || ret >= end - pos)
919 return pos - buf;
920 pos += ret;
921
0282a8c4
JM
922 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
923 " ");
924 if (ret < 0)
925 return pos - buf;
926 pos += ret;
403b96fe
JM
927
928 ret = os_snprintf(pos, end - pos, "\n");
929 if (ret < 0 || ret >= end - pos)
930 return pos - buf;
931 pos += ret;
932 }
933
934 if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
935 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
936 if (ret < 0 || ret >= end - pos)
937 return pos - buf;
938 pos += ret;
939
0282a8c4
JM
940 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
941 " ");
942 if (ret < 0)
943 return pos - buf;
944 pos += ret;
403b96fe
JM
945
946 ret = os_snprintf(pos, end - pos, "\n");
947 if (ret < 0 || ret >= end - pos)
948 return pos - buf;
949 pos += ret;
950 }
951
952 return pos - buf;
953}
954
955
2c8a4eef 956static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
b4e34f2f
JM
957{
958 char *value;
959 int ret = 0;
960
961 value = os_strchr(cmd, ' ');
962 if (value == NULL)
963 return -1;
964 *value++ = '\0';
965
966 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
967 if (0) {
968#ifdef CONFIG_WPS_TESTING
969 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
970 long int val;
971 val = strtol(value, NULL, 0);
972 if (val < 0 || val > 0xff) {
973 ret = -1;
974 wpa_printf(MSG_DEBUG, "WPS: Invalid "
975 "wps_version_number %ld", val);
976 } else {
977 wps_version_number = val;
978 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
979 "version %u.%u",
980 (wps_version_number & 0xf0) >> 4,
981 wps_version_number & 0x0f);
2c8a4eef 982 hostapd_wps_update_ie(hapd);
b4e34f2f
JM
983 }
984 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
985 wps_testing_dummy_cred = atoi(value);
986 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
987 wps_testing_dummy_cred);
988#endif /* CONFIG_WPS_TESTING */
dca30c3f
JK
989#ifdef CONFIG_INTERWORKING
990 } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
991 int val = atoi(value);
992 if (val <= 0)
993 ret = -1;
994 else
995 hapd->gas_frag_limit = val;
996#endif /* CONFIG_INTERWORKING */
b4e34f2f 997 } else {
31b79e11 998 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
b4e34f2f
JM
999 }
1000
1001 return ret;
1002}
1003
1004
acec8d32
JM
1005static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1006 char *buf, size_t buflen)
1007{
1008 int res;
1009
1010 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1011
1012 if (os_strcmp(cmd, "version") == 0) {
1013 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
1014 if (res < 0 || (unsigned int) res >= buflen)
1015 return -1;
1016 return res;
1017 }
1018
1019 return -1;
1020}
1021
1022
75545652
SP
1023static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1024{
1025 if (hostapd_enable_iface(iface) < 0) {
1026 wpa_printf(MSG_ERROR, "Enabling of interface failed");
1027 return -1;
1028 }
1029 return 0;
1030}
1031
1032
1033static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1034{
1035 if (hostapd_reload_iface(iface) < 0) {
1036 wpa_printf(MSG_ERROR, "Reloading of interface failed");
1037 return -1;
1038 }
1039 return 0;
1040}
1041
1042
1043static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1044{
1045 if (hostapd_disable_iface(iface) < 0) {
1046 wpa_printf(MSG_ERROR, "Disabling of interface failed");
1047 return -1;
1048 }
1049 return 0;
1050}
1051
1052
ddf55174
JM
1053#ifdef CONFIG_TESTING_OPTIONS
1054static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
1055{
1056 union wpa_event_data data;
1057 char *pos, *param;
1058 enum wpa_event_type event;
1059
1060 wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
1061
1062 os_memset(&data, 0, sizeof(data));
1063
1064 param = os_strchr(cmd, ' ');
1065 if (param == NULL)
1066 return -1;
1067 *param++ = '\0';
1068
1069 if (os_strcmp(cmd, "DETECTED") == 0)
1070 event = EVENT_DFS_RADAR_DETECTED;
1071 else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
1072 event = EVENT_DFS_CAC_FINISHED;
1073 else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
1074 event = EVENT_DFS_CAC_ABORTED;
1075 else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
1076 event = EVENT_DFS_NOP_FINISHED;
1077 else {
1078 wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
1079 cmd);
1080 return -1;
1081 }
1082
1083 pos = os_strstr(param, "freq=");
1084 if (pos)
1085 data.dfs_event.freq = atoi(pos + 5);
1086
1087 pos = os_strstr(param, "ht_enabled=1");
1088 if (pos)
1089 data.dfs_event.ht_enabled = 1;
1090
1091 pos = os_strstr(param, "chan_offset=");
1092 if (pos)
1093 data.dfs_event.chan_offset = atoi(pos + 12);
1094
1095 pos = os_strstr(param, "chan_width=");
1096 if (pos)
1097 data.dfs_event.chan_width = atoi(pos + 11);
1098
1099 pos = os_strstr(param, "cf1=");
1100 if (pos)
1101 data.dfs_event.cf1 = atoi(pos + 4);
1102
1103 pos = os_strstr(param, "cf2=");
1104 if (pos)
1105 data.dfs_event.cf2 = atoi(pos + 4);
1106
1107 wpa_supplicant_event(hapd, event, &data);
1108
1109 return 0;
1110}
1111#endif /* CONFIG_TESTING_OPTIONS */
1112
1113
334bf36a
AO
1114static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos)
1115{
1116#ifdef NEED_AP_MLME
1117 struct csa_settings settings;
1118 int ret = hostapd_parse_csa_settings(pos, &settings);
1119
1120 if (ret)
1121 return ret;
1122
1123 return hostapd_switch_channel(hapd, &settings);
1124#else /* NEED_AP_MLME */
1125 return -1;
1126#endif /* NEED_AP_MLME */
1127}
1128
1129
6fc6879b
JM
1130static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
1131 void *sock_ctx)
1132{
1133 struct hostapd_data *hapd = eloop_ctx;
1134 char buf[256];
1135 int res;
1136 struct sockaddr_un from;
1137 socklen_t fromlen = sizeof(from);
1138 char *reply;
1139 const int reply_size = 4096;
1140 int reply_len;
235f69fc 1141 int level = MSG_DEBUG;
6fc6879b
JM
1142
1143 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1144 (struct sockaddr *) &from, &fromlen);
1145 if (res < 0) {
1146 perror("recvfrom(ctrl_iface)");
1147 return;
1148 }
1149 buf[res] = '\0';
235f69fc
JM
1150 if (os_strcmp(buf, "PING") == 0)
1151 level = MSG_EXCESSIVE;
1152 wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
6fc6879b
JM
1153
1154 reply = os_malloc(reply_size);
1155 if (reply == NULL) {
1156 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
1157 fromlen);
1158 return;
1159 }
1160
1161 os_memcpy(reply, "OK\n", 3);
1162 reply_len = 3;
1163
1164 if (os_strcmp(buf, "PING") == 0) {
1165 os_memcpy(reply, "PONG\n", 5);
1166 reply_len = 5;
b41a47c0
BG
1167 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
1168 if (wpa_debug_reopen_file() < 0)
1169 reply_len = -1;
5ae6449c
JM
1170 } else if (os_strcmp(buf, "STATUS") == 0) {
1171 reply_len = hostapd_ctrl_iface_status(hapd, reply,
1172 reply_size);
6fc6879b
JM
1173 } else if (os_strcmp(buf, "MIB") == 0) {
1174 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
1175 if (reply_len >= 0) {
1176 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
1177 reply_size - reply_len);
1178 if (res < 0)
1179 reply_len = -1;
1180 else
1181 reply_len += res;
1182 }
1183 if (reply_len >= 0) {
1184 res = ieee802_1x_get_mib(hapd, reply + reply_len,
1185 reply_size - reply_len);
1186 if (res < 0)
1187 reply_len = -1;
1188 else
1189 reply_len += res;
1190 }
74784010 1191#ifndef CONFIG_NO_RADIUS
6fc6879b
JM
1192 if (reply_len >= 0) {
1193 res = radius_client_get_mib(hapd->radius,
1194 reply + reply_len,
1195 reply_size - reply_len);
1196 if (res < 0)
1197 reply_len = -1;
1198 else
1199 reply_len += res;
1200 }
74784010 1201#endif /* CONFIG_NO_RADIUS */
6fc6879b
JM
1202 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
1203 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
1204 reply_size);
1205 } else if (os_strncmp(buf, "STA ", 4) == 0) {
1206 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
1207 reply_size);
1208 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
1209 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
1210 reply_size);
1211 } else if (os_strcmp(buf, "ATTACH") == 0) {
1212 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
1213 reply_len = -1;
1214 } else if (os_strcmp(buf, "DETACH") == 0) {
1215 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
1216 reply_len = -1;
1217 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
1218 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
1219 buf + 6))
1220 reply_len = -1;
1221 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
1222 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
1223 reply_len = -1;
90a3206a
JM
1224 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
1225 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
1226 reply_len = -1;
1227 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
1228 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
1229 reply_len = -1;
88b4b424 1230#ifdef CONFIG_IEEE80211W
fe6bdb77 1231#ifdef NEED_AP_MLME
88b4b424
JM
1232 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
1233 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
1234 reply_len = -1;
fe6bdb77 1235#endif /* NEED_AP_MLME */
88b4b424 1236#endif /* CONFIG_IEEE80211W */
ad08c363
JM
1237#ifdef CONFIG_WPS
1238 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
1239 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
1240 reply_len = -1;
3981cb3c
JM
1241 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
1242 reply_len = hostapd_ctrl_iface_wps_check_pin(
1243 hapd, buf + 14, reply, reply_size);
ad08c363 1244 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
d601247c 1245 if (hostapd_wps_button_pushed(hapd, NULL))
ad08c363 1246 reply_len = -1;
4c374cde
AS
1247 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
1248 if (hostapd_wps_cancel(hapd))
1249 reply_len = -1;
5a1cc30f
JM
1250 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
1251 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
1252 reply, reply_size);
450eddcf
JM
1253 } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
1254 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
1255 reply_len = -1;
3351a384
JM
1256 } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
1257 reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
1258 reply_size);
bb45b6d7
JM
1259#ifdef CONFIG_WPS_NFC
1260 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
1261 if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
1262 reply_len = -1;
3cf7a59d
JM
1263 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
1264 reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
1265 hapd, buf + 21, reply, reply_size);
ffdaa05a
JM
1266 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
1267 reply_len = hostapd_ctrl_iface_wps_nfc_token(
1268 hapd, buf + 14, reply, reply_size);
6772a90a
JM
1269 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
1270 reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
1271 hapd, buf + 21, reply, reply_size);
e4758827
JM
1272 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
1273 if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
1274 reply_len = -1;
bb45b6d7 1275#endif /* CONFIG_WPS_NFC */
ad08c363 1276#endif /* CONFIG_WPS */
c551700f
KP
1277#ifdef CONFIG_INTERWORKING
1278 } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
1279 if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
1280 reply_len = -1;
1281 } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
1282 if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
1283 reply_len = -1;
1284#endif /* CONFIG_INTERWORKING */
2049a875
JM
1285#ifdef CONFIG_WNM
1286 } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
1287 if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
1288 reply_len = -1;
71269b37
JM
1289 } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
1290 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
1291 reply_len = -1;
2049a875 1292#endif /* CONFIG_WNM */
403b96fe
JM
1293 } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
1294 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
1295 reply_size);
b4e34f2f
JM
1296 } else if (os_strncmp(buf, "SET ", 4) == 0) {
1297 if (hostapd_ctrl_iface_set(hapd, buf + 4))
1298 reply_len = -1;
acec8d32
JM
1299 } else if (os_strncmp(buf, "GET ", 4) == 0) {
1300 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
1301 reply_size);
75545652
SP
1302 } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
1303 if (hostapd_ctrl_iface_enable(hapd->iface))
1304 reply_len = -1;
1305 } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
1306 if (hostapd_ctrl_iface_reload(hapd->iface))
1307 reply_len = -1;
1308 } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
1309 if (hostapd_ctrl_iface_disable(hapd->iface))
1310 reply_len = -1;
ddf55174
JM
1311#ifdef CONFIG_TESTING_OPTIONS
1312 } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
1313 if (hostapd_ctrl_iface_radar(hapd, buf + 6))
1314 reply_len = -1;
1315#endif /* CONFIG_TESTING_OPTIONS */
334bf36a
AO
1316 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
1317 if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12))
1318 reply_len = -1;
6fc6879b
JM
1319 } else {
1320 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1321 reply_len = 16;
1322 }
1323
1324 if (reply_len < 0) {
1325 os_memcpy(reply, "FAIL\n", 5);
1326 reply_len = 5;
1327 }
1328 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1329 os_free(reply);
1330}
1331
1332
1333static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
1334{
1335 char *buf;
1336 size_t len;
1337
1338 if (hapd->conf->ctrl_interface == NULL)
1339 return NULL;
1340
1341 len = os_strlen(hapd->conf->ctrl_interface) +
1342 os_strlen(hapd->conf->iface) + 2;
1343 buf = os_malloc(len);
1344 if (buf == NULL)
1345 return NULL;
1346
1347 os_snprintf(buf, len, "%s/%s",
1348 hapd->conf->ctrl_interface, hapd->conf->iface);
1349 buf[len - 1] = '\0';
1350 return buf;
1351}
1352
1353
47bfe49c 1354static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
42d16805
JM
1355 const char *txt, size_t len)
1356{
1357 struct hostapd_data *hapd = ctx;
1358 if (hapd == NULL)
1359 return;
1360 hostapd_ctrl_iface_send(hapd, level, txt, len);
1361}
1362
1363
6fc6879b
JM
1364int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
1365{
1366 struct sockaddr_un addr;
1367 int s = -1;
1368 char *fname = NULL;
1369
9e7d033e
SP
1370 if (hapd->ctrl_sock > -1) {
1371 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
1372 return 0;
1373 }
6fc6879b
JM
1374
1375 if (hapd->conf->ctrl_interface == NULL)
1376 return 0;
1377
1378 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1379 if (errno == EEXIST) {
1380 wpa_printf(MSG_DEBUG, "Using existing control "
1381 "interface directory.");
1382 } else {
1383 perror("mkdir[ctrl_interface]");
1384 goto fail;
1385 }
1386 }
1387
1388 if (hapd->conf->ctrl_interface_gid_set &&
9cbd5845 1389 chown(hapd->conf->ctrl_interface, -1,
6fc6879b
JM
1390 hapd->conf->ctrl_interface_gid) < 0) {
1391 perror("chown[ctrl_interface]");
1392 return -1;
1393 }
1394
187f87f0
JM
1395 if (!hapd->conf->ctrl_interface_gid_set &&
1396 hapd->iface->interfaces->ctrl_iface_group &&
1397 chown(hapd->conf->ctrl_interface, -1,
1398 hapd->iface->interfaces->ctrl_iface_group) < 0) {
1399 perror("chown[ctrl_interface]");
1400 return -1;
1401 }
1402
5bbf590a
PF
1403#ifdef ANDROID
1404 /*
1405 * Android is using umask 0077 which would leave the control interface
1406 * directory without group access. This breaks things since Wi-Fi
1407 * framework assumes that this directory can be accessed by other
1408 * applications in the wifi group. Fix this by adding group access even
1409 * if umask value would prevent this.
1410 */
1411 if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1412 wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
1413 strerror(errno));
1414 /* Try to continue anyway */
1415 }
1416#endif /* ANDROID */
1417
6fc6879b
JM
1418 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
1419 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
1420 goto fail;
1421
1422 s = socket(PF_UNIX, SOCK_DGRAM, 0);
1423 if (s < 0) {
1424 perror("socket(PF_UNIX)");
1425 goto fail;
1426 }
1427
1428 os_memset(&addr, 0, sizeof(addr));
75864b7f
JM
1429#ifdef __FreeBSD__
1430 addr.sun_len = sizeof(addr);
1431#endif /* __FreeBSD__ */
6fc6879b
JM
1432 addr.sun_family = AF_UNIX;
1433 fname = hostapd_ctrl_iface_path(hapd);
1434 if (fname == NULL)
1435 goto fail;
1436 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1437 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
617d1555
JM
1438 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1439 strerror(errno));
1440 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1441 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1442 " allow connections - assuming it was left"
1443 "over from forced program termination");
1444 if (unlink(fname) < 0) {
1445 perror("unlink[ctrl_iface]");
1446 wpa_printf(MSG_ERROR, "Could not unlink "
1447 "existing ctrl_iface socket '%s'",
1448 fname);
1449 goto fail;
1450 }
1451 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1452 0) {
9d053747 1453 perror("hostapd-ctrl-iface: bind(PF_UNIX)");
617d1555
JM
1454 goto fail;
1455 }
1456 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1457 "ctrl_iface socket '%s'", fname);
1458 } else {
1459 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1460 "be in use - cannot override it");
1461 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1462 "not used anymore", fname);
1463 os_free(fname);
1464 fname = NULL;
1465 goto fail;
1466 }
6fc6879b
JM
1467 }
1468
1469 if (hapd->conf->ctrl_interface_gid_set &&
9cbd5845 1470 chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
6fc6879b
JM
1471 perror("chown[ctrl_interface/ifname]");
1472 goto fail;
1473 }
1474
187f87f0
JM
1475 if (!hapd->conf->ctrl_interface_gid_set &&
1476 hapd->iface->interfaces->ctrl_iface_group &&
1477 chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
1478 perror("chown[ctrl_interface/ifname]");
1479 goto fail;
1480 }
1481
6fc6879b
JM
1482 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1483 perror("chmod[ctrl_interface/ifname]");
1484 goto fail;
1485 }
1486 os_free(fname);
1487
1488 hapd->ctrl_sock = s;
1489 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
1490 NULL);
4f760fcc 1491 hapd->msg_ctx = hapd;
42d16805 1492 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
6fc6879b
JM
1493
1494 return 0;
1495
1496fail:
1497 if (s >= 0)
1498 close(s);
1499 if (fname) {
1500 unlink(fname);
1501 os_free(fname);
1502 }
1503 return -1;
1504}
1505
1506
1507void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
1508{
1509 struct wpa_ctrl_dst *dst, *prev;
1510
1511 if (hapd->ctrl_sock > -1) {
1512 char *fname;
1513 eloop_unregister_read_sock(hapd->ctrl_sock);
1514 close(hapd->ctrl_sock);
1515 hapd->ctrl_sock = -1;
1516 fname = hostapd_ctrl_iface_path(hapd);
1517 if (fname)
1518 unlink(fname);
1519 os_free(fname);
1520
1521 if (hapd->conf->ctrl_interface &&
1522 rmdir(hapd->conf->ctrl_interface) < 0) {
1523 if (errno == ENOTEMPTY) {
1524 wpa_printf(MSG_DEBUG, "Control interface "
1525 "directory not empty - leaving it "
1526 "behind");
1527 } else {
2c6f8cf6
JM
1528 wpa_printf(MSG_ERROR,
1529 "rmdir[ctrl_interface=%s]: %s",
1530 hapd->conf->ctrl_interface,
1531 strerror(errno));
6fc6879b
JM
1532 }
1533 }
1534 }
1535
1536 dst = hapd->ctrl_dst;
1537 while (dst) {
1538 prev = dst;
1539 dst = dst->next;
1540 os_free(prev);
1541 }
1542}
1543
1544
06bb8c62
SP
1545static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
1546 char *buf)
1547{
1548 if (hostapd_add_iface(interfaces, buf) < 0) {
1549 wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
1550 return -1;
1551 }
1552 return 0;
1553}
1554
1555
1556static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
1557 char *buf)
1558{
1559 if (hostapd_remove_iface(interfaces, buf) < 0) {
1560 wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
1561 return -1;
1562 }
1563 return 0;
1564}
1565
1566
c90fd485
SP
1567static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
1568 void *sock_ctx)
1569{
06bb8c62 1570 void *interfaces = eloop_ctx;
c90fd485
SP
1571 char buf[256];
1572 int res;
1573 struct sockaddr_un from;
1574 socklen_t fromlen = sizeof(from);
1575 char reply[24];
1576 int reply_len;
1577
1578 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1579 (struct sockaddr *) &from, &fromlen);
1580 if (res < 0) {
1581 perror("recvfrom(ctrl_iface)");
1582 return;
1583 }
1584 buf[res] = '\0';
3f134b43 1585 wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
c90fd485
SP
1586
1587 os_memcpy(reply, "OK\n", 3);
1588 reply_len = 3;
1589
1590 if (os_strcmp(buf, "PING") == 0) {
1591 os_memcpy(reply, "PONG\n", 5);
1592 reply_len = 5;
3f134b43
JM
1593 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
1594 if (wpa_debug_reopen_file() < 0)
1595 reply_len = -1;
06bb8c62
SP
1596 } else if (os_strncmp(buf, "ADD ", 4) == 0) {
1597 if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
1598 reply_len = -1;
1599 } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
1600 if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
1601 reply_len = -1;
c90fd485
SP
1602 } else {
1603 wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
1604 "ignored");
1605 reply_len = -1;
1606 }
1607
1608 if (reply_len < 0) {
1609 os_memcpy(reply, "FAIL\n", 5);
1610 reply_len = 5;
1611 }
1612
1613 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1614}
1615
1616
1617static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
1618{
1619 char *buf;
1620 size_t len;
1621
1622 if (interface->global_iface_path == NULL)
1623 return NULL;
1624
1625 len = os_strlen(interface->global_iface_path) +
1626 os_strlen(interface->global_iface_name) + 2;
1627 buf = os_malloc(len);
1628 if (buf == NULL)
1629 return NULL;
1630
1631 os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
1632 interface->global_iface_name);
1633 buf[len - 1] = '\0';
1634 return buf;
1635}
1636
1637
1638int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
1639{
1640 struct sockaddr_un addr;
1641 int s = -1;
1642 char *fname = NULL;
1643
1644 if (interface->global_iface_path == NULL) {
1645 wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
1646 return 0;
1647 }
1648
1649 if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
1650 if (errno == EEXIST) {
1651 wpa_printf(MSG_DEBUG, "Using existing control "
1652 "interface directory.");
1653 } else {
1654 perror("mkdir[ctrl_interface]");
1655 goto fail;
1656 }
187f87f0
JM
1657 } else if (interface->ctrl_iface_group &&
1658 chown(interface->global_iface_path, -1,
1659 interface->ctrl_iface_group) < 0) {
1660 perror("chown[ctrl_interface]");
1661 goto fail;
c90fd485
SP
1662 }
1663
1664 if (os_strlen(interface->global_iface_path) + 1 +
1665 os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
1666 goto fail;
1667
1668 s = socket(PF_UNIX, SOCK_DGRAM, 0);
1669 if (s < 0) {
1670 perror("socket(PF_UNIX)");
1671 goto fail;
1672 }
1673
1674 os_memset(&addr, 0, sizeof(addr));
1675#ifdef __FreeBSD__
1676 addr.sun_len = sizeof(addr);
1677#endif /* __FreeBSD__ */
1678 addr.sun_family = AF_UNIX;
1679 fname = hostapd_global_ctrl_iface_path(interface);
1680 if (fname == NULL)
1681 goto fail;
1682 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1683 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1684 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1685 strerror(errno));
1686 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1687 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1688 " allow connections - assuming it was left"
1689 "over from forced program termination");
1690 if (unlink(fname) < 0) {
1691 perror("unlink[ctrl_iface]");
1692 wpa_printf(MSG_ERROR, "Could not unlink "
1693 "existing ctrl_iface socket '%s'",
1694 fname);
1695 goto fail;
1696 }
1697 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1698 0) {
1699 perror("bind(PF_UNIX)");
1700 goto fail;
1701 }
1702 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1703 "ctrl_iface socket '%s'", fname);
1704 } else {
1705 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1706 "be in use - cannot override it");
1707 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1708 "not used anymore", fname);
1709 os_free(fname);
1710 fname = NULL;
1711 goto fail;
1712 }
1713 }
1714
187f87f0
JM
1715 if (interface->ctrl_iface_group &&
1716 chown(fname, -1, interface->ctrl_iface_group) < 0) {
1717 perror("chown[ctrl_interface]");
1718 goto fail;
1719 }
1720
c90fd485
SP
1721 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1722 perror("chmod[ctrl_interface/ifname]");
1723 goto fail;
1724 }
1725 os_free(fname);
1726
1727 interface->global_ctrl_sock = s;
1728 eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
1729 interface, NULL);
1730
1731 return 0;
1732
1733fail:
1734 if (s >= 0)
1735 close(s);
1736 if (fname) {
1737 unlink(fname);
1738 os_free(fname);
1739 }
1740 return -1;
1741}
1742
1743
1744void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
1745{
1746 char *fname = NULL;
1747
1748 if (interfaces->global_ctrl_sock > -1) {
1749 eloop_unregister_read_sock(interfaces->global_ctrl_sock);
1750 close(interfaces->global_ctrl_sock);
1751 interfaces->global_ctrl_sock = -1;
1752 fname = hostapd_global_ctrl_iface_path(interfaces);
1753 if (fname) {
1754 unlink(fname);
1755 os_free(fname);
1756 }
1757
1758 if (interfaces->global_iface_path &&
1759 rmdir(interfaces->global_iface_path) < 0) {
1760 if (errno == ENOTEMPTY) {
1761 wpa_printf(MSG_DEBUG, "Control interface "
1762 "directory not empty - leaving it "
1763 "behind");
1764 } else {
2c6f8cf6
JM
1765 wpa_printf(MSG_ERROR,
1766 "rmdir[ctrl_interface=%s]: %s",
1767 interfaces->global_iface_path,
1768 strerror(errno));
c90fd485
SP
1769 }
1770 }
1771 os_free(interfaces->global_iface_path);
1772 interfaces->global_iface_path = NULL;
1773 }
1774}
1775
1776
42d16805
JM
1777static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1778 const char *buf, size_t len)
6fc6879b
JM
1779{
1780 struct wpa_ctrl_dst *dst, *next;
1781 struct msghdr msg;
1782 int idx;
1783 struct iovec io[2];
1784 char levelstr[10];
1785
1786 dst = hapd->ctrl_dst;
1787 if (hapd->ctrl_sock < 0 || dst == NULL)
1788 return;
1789
1790 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1791 io[0].iov_base = levelstr;
1792 io[0].iov_len = os_strlen(levelstr);
42d16805 1793 io[1].iov_base = (char *) buf;
6fc6879b
JM
1794 io[1].iov_len = len;
1795 os_memset(&msg, 0, sizeof(msg));
1796 msg.msg_iov = io;
1797 msg.msg_iovlen = 2;
1798
1799 idx = 0;
1800 while (dst) {
1801 next = dst->next;
1802 if (level >= dst->debug_level) {
1803 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
75864b7f
JM
1804 (u8 *) dst->addr.sun_path, dst->addrlen -
1805 offsetof(struct sockaddr_un, sun_path));
6fc6879b
JM
1806 msg.msg_name = &dst->addr;
1807 msg.msg_namelen = dst->addrlen;
1808 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
c5aaa015
JM
1809 int _errno = errno;
1810 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1811 "%d - %s",
1812 idx, errno, strerror(errno));
6fc6879b 1813 dst->errors++;
c5aaa015 1814 if (dst->errors > 10 || _errno == ENOENT) {
6fc6879b
JM
1815 hostapd_ctrl_iface_detach(
1816 hapd, &dst->addr,
1817 dst->addrlen);
1818 }
1819 } else
1820 dst->errors = 0;
1821 }
1822 idx++;
1823 dst = next;
1824 }
1825}
1826
1827#endif /* CONFIG_NATIVE_WINDOWS */