blob: cb6fb1757708237bedc9e785684c7f623e1807ff [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / UNIX domain socket -based control interface
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003 * Copyright (c) 2004-2015, 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
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080013#ifdef CONFIG_TESTING_OPTIONS
14#include <net/ethernet.h>
15#include <netinet/ip.h>
16#endif /* CONFIG_TESTING_OPTIONS */
17
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018#include <sys/un.h>
19#include <sys/stat.h>
20#include <stddef.h>
21
22#include "utils/common.h"
23#include "utils/eloop.h"
24#include "common/version.h"
25#include "common/ieee802_11_defs.h"
Dmitry Shmidtff787d52015-01-12 13:01:47 -080026#include "crypto/tls.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027#include "drivers/driver.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080028#include "eapol_auth/eapol_auth_sm.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070029#include "radius/radius_client.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080030#include "radius/radius_server.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080031#include "l2_packet/l2_packet.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070032#include "ap/hostapd.h"
33#include "ap/ap_config.h"
34#include "ap/ieee802_1x.h"
35#include "ap/wpa_auth.h"
36#include "ap/ieee802_11.h"
37#include "ap/sta_info.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070038#include "ap/wps_hostapd.h"
39#include "ap/ctrl_iface_ap.h"
40#include "ap/ap_drv_ops.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080041#include "ap/hs20.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080042#include "ap/wnm_ap.h"
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -070043#include "ap/wpa_auth.h"
Dmitry Shmidt7f656022015-02-25 14:36:37 -080044#include "ap/beacon.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070045#include "wps/wps_defs.h"
46#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080047#include "fst/fst_ctrl_iface.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070048#include "config_file.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049#include "ctrl_iface.h"
50
51
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080052#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
53
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070054struct wpa_ctrl_dst {
55 struct wpa_ctrl_dst *next;
56 struct sockaddr_un addr;
57 socklen_t addrlen;
58 int debug_level;
59 int errors;
60};
61
62
63static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
Anton Nayshtutf715e8d2014-11-16 16:52:49 +020064 enum wpa_msg_type type,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070065 const char *buf, size_t len);
66
67
68static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
69 struct sockaddr_un *from,
70 socklen_t fromlen)
71{
72 struct wpa_ctrl_dst *dst;
73
74 dst = os_zalloc(sizeof(*dst));
75 if (dst == NULL)
76 return -1;
77 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
78 dst->addrlen = fromlen;
79 dst->debug_level = MSG_INFO;
80 dst->next = hapd->ctrl_dst;
81 hapd->ctrl_dst = dst;
82 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
83 (u8 *) from->sun_path,
84 fromlen - offsetof(struct sockaddr_un, sun_path));
85 return 0;
86}
87
88
89static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
90 struct sockaddr_un *from,
91 socklen_t fromlen)
92{
93 struct wpa_ctrl_dst *dst, *prev = NULL;
94
95 dst = hapd->ctrl_dst;
96 while (dst) {
97 if (fromlen == dst->addrlen &&
98 os_memcmp(from->sun_path, dst->addr.sun_path,
99 fromlen - offsetof(struct sockaddr_un, sun_path))
100 == 0) {
Dmitry Shmidt54605472013-11-08 11:10:19 -0800101 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
102 (u8 *) from->sun_path,
103 fromlen -
104 offsetof(struct sockaddr_un, sun_path));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700105 if (prev == NULL)
106 hapd->ctrl_dst = dst->next;
107 else
108 prev->next = dst->next;
109 os_free(dst);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700110 return 0;
111 }
112 prev = dst;
113 dst = dst->next;
114 }
115 return -1;
116}
117
118
119static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
120 struct sockaddr_un *from,
121 socklen_t fromlen,
122 char *level)
123{
124 struct wpa_ctrl_dst *dst;
125
126 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
127
128 dst = hapd->ctrl_dst;
129 while (dst) {
130 if (fromlen == dst->addrlen &&
131 os_memcmp(from->sun_path, dst->addr.sun_path,
132 fromlen - offsetof(struct sockaddr_un, sun_path))
133 == 0) {
134 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
135 "level", (u8 *) from->sun_path, fromlen -
136 offsetof(struct sockaddr_un, sun_path));
137 dst->debug_level = atoi(level);
138 return 0;
139 }
140 dst = dst->next;
141 }
142
143 return -1;
144}
145
146
147static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
148 const char *txtaddr)
149{
150 u8 addr[ETH_ALEN];
151 struct sta_info *sta;
152
153 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
154
155 if (hwaddr_aton(txtaddr, addr))
156 return -1;
157
158 sta = ap_get_sta(hapd, addr);
159 if (sta)
160 return 0;
161
162 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
163 "notification", MAC2STR(addr));
164 sta = ap_sta_add(hapd, addr);
165 if (sta == NULL)
166 return -1;
167
168 hostapd_new_assoc_sta(hapd, sta, 0);
169 return 0;
170}
171
172
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700173#ifdef CONFIG_IEEE80211W
174#ifdef NEED_AP_MLME
175static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
176 const char *txtaddr)
177{
178 u8 addr[ETH_ALEN];
179 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
180
181 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
182
183 if (hwaddr_aton(txtaddr, addr) ||
184 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
185 return -1;
186
187 ieee802_11_send_sa_query_req(hapd, addr, trans_id);
188
189 return 0;
190}
191#endif /* NEED_AP_MLME */
192#endif /* CONFIG_IEEE80211W */
193
194
195#ifdef CONFIG_WPS
196static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
197{
198 char *pin = os_strchr(txt, ' ');
199 char *timeout_txt;
200 int timeout;
201 u8 addr_buf[ETH_ALEN], *addr = NULL;
202 char *pos;
203
204 if (pin == NULL)
205 return -1;
206 *pin++ = '\0';
207
208 timeout_txt = os_strchr(pin, ' ');
209 if (timeout_txt) {
210 *timeout_txt++ = '\0';
211 timeout = atoi(timeout_txt);
212 pos = os_strchr(timeout_txt, ' ');
213 if (pos) {
214 *pos++ = '\0';
215 if (hwaddr_aton(pos, addr_buf) == 0)
216 addr = addr_buf;
217 }
218 } else
219 timeout = 0;
220
221 return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
222}
223
224
225static int hostapd_ctrl_iface_wps_check_pin(
226 struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
227{
228 char pin[9];
229 size_t len;
230 char *pos;
231 int ret;
232
233 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
234 (u8 *) cmd, os_strlen(cmd));
235 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
236 if (*pos < '0' || *pos > '9')
237 continue;
238 pin[len++] = *pos;
239 if (len == 9) {
240 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
241 return -1;
242 }
243 }
244 if (len != 4 && len != 8) {
245 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
246 return -1;
247 }
248 pin[len] = '\0';
249
250 if (len == 8) {
251 unsigned int pin_val;
252 pin_val = atoi(pin);
253 if (!wps_pin_valid(pin_val)) {
254 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
255 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800256 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700257 return -1;
258 return ret;
259 }
260 }
261
262 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800263 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700264 return -1;
265
266 return ret;
267}
268
269
Dmitry Shmidt04949592012-07-19 12:16:46 -0700270#ifdef CONFIG_WPS_NFC
271static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
272 char *pos)
273{
274 size_t len;
275 struct wpabuf *buf;
276 int ret;
277
278 len = os_strlen(pos);
279 if (len & 0x01)
280 return -1;
281 len /= 2;
282
283 buf = wpabuf_alloc(len);
284 if (buf == NULL)
285 return -1;
286 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
287 wpabuf_free(buf);
288 return -1;
289 }
290
291 ret = hostapd_wps_nfc_tag_read(hapd, buf);
292 wpabuf_free(buf);
293
294 return ret;
295}
296
297
298static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
299 char *cmd, char *reply,
300 size_t max_len)
301{
302 int ndef;
303 struct wpabuf *buf;
304 int res;
305
306 if (os_strcmp(cmd, "WPS") == 0)
307 ndef = 0;
308 else if (os_strcmp(cmd, "NDEF") == 0)
309 ndef = 1;
310 else
311 return -1;
312
313 buf = hostapd_wps_nfc_config_token(hapd, ndef);
314 if (buf == NULL)
315 return -1;
316
317 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
318 wpabuf_len(buf));
319 reply[res++] = '\n';
320 reply[res] = '\0';
321
322 wpabuf_free(buf);
323
324 return res;
325}
326
327
328static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
329 char *reply, size_t max_len,
330 int ndef)
331{
332 struct wpabuf *buf;
333 int res;
334
335 buf = hostapd_wps_nfc_token_gen(hapd, ndef);
336 if (buf == NULL)
337 return -1;
338
339 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
340 wpabuf_len(buf));
341 reply[res++] = '\n';
342 reply[res] = '\0';
343
344 wpabuf_free(buf);
345
346 return res;
347}
348
349
350static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
351 char *cmd, char *reply,
352 size_t max_len)
353{
354 if (os_strcmp(cmd, "WPS") == 0)
355 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
356 max_len, 0);
357
358 if (os_strcmp(cmd, "NDEF") == 0)
359 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
360 max_len, 1);
361
362 if (os_strcmp(cmd, "enable") == 0)
363 return hostapd_wps_nfc_token_enable(hapd);
364
365 if (os_strcmp(cmd, "disable") == 0) {
366 hostapd_wps_nfc_token_disable(hapd);
367 return 0;
368 }
369
370 return -1;
371}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800372
373
374static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
375 char *cmd, char *reply,
376 size_t max_len)
377{
378 struct wpabuf *buf;
379 int res;
380 char *pos;
381 int ndef;
382
383 pos = os_strchr(cmd, ' ');
384 if (pos == NULL)
385 return -1;
386 *pos++ = '\0';
387
388 if (os_strcmp(cmd, "WPS") == 0)
389 ndef = 0;
390 else if (os_strcmp(cmd, "NDEF") == 0)
391 ndef = 1;
392 else
393 return -1;
394
395 if (os_strcmp(pos, "WPS-CR") == 0)
396 buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
397 else
398 buf = NULL;
399 if (buf == NULL)
400 return -1;
401
402 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
403 wpabuf_len(buf));
404 reply[res++] = '\n';
405 reply[res] = '\0';
406
407 wpabuf_free(buf);
408
409 return res;
410}
411
412
413static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
414 char *cmd)
415{
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800416 size_t len;
417 struct wpabuf *req, *sel;
418 int ret;
419 char *pos, *role, *type, *pos2;
420
421 role = cmd;
422 pos = os_strchr(role, ' ');
423 if (pos == NULL)
424 return -1;
425 *pos++ = '\0';
426
427 type = pos;
428 pos = os_strchr(type, ' ');
429 if (pos == NULL)
430 return -1;
431 *pos++ = '\0';
432
433 pos2 = os_strchr(pos, ' ');
434 if (pos2 == NULL)
435 return -1;
436 *pos2++ = '\0';
437
438 len = os_strlen(pos);
439 if (len & 0x01)
440 return -1;
441 len /= 2;
442
443 req = wpabuf_alloc(len);
444 if (req == NULL)
445 return -1;
446 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
447 wpabuf_free(req);
448 return -1;
449 }
450
451 len = os_strlen(pos2);
452 if (len & 0x01) {
453 wpabuf_free(req);
454 return -1;
455 }
456 len /= 2;
457
458 sel = wpabuf_alloc(len);
459 if (sel == NULL) {
460 wpabuf_free(req);
461 return -1;
462 }
463 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
464 wpabuf_free(req);
465 wpabuf_free(sel);
466 return -1;
467 }
468
469 if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
470 ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
471 } else {
472 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
473 "reported: role=%s type=%s", role, type);
474 ret = -1;
475 }
476 wpabuf_free(req);
477 wpabuf_free(sel);
478
479 return ret;
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800480}
481
Dmitry Shmidt04949592012-07-19 12:16:46 -0700482#endif /* CONFIG_WPS_NFC */
483
484
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700485static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
486 char *buf, size_t buflen)
487{
488 int timeout = 300;
489 char *pos;
490 const char *pin_txt;
491
492 pos = os_strchr(txt, ' ');
493 if (pos)
494 *pos++ = '\0';
495
496 if (os_strcmp(txt, "disable") == 0) {
497 hostapd_wps_ap_pin_disable(hapd);
498 return os_snprintf(buf, buflen, "OK\n");
499 }
500
501 if (os_strcmp(txt, "random") == 0) {
502 if (pos)
503 timeout = atoi(pos);
504 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
505 if (pin_txt == NULL)
506 return -1;
507 return os_snprintf(buf, buflen, "%s", pin_txt);
508 }
509
510 if (os_strcmp(txt, "get") == 0) {
511 pin_txt = hostapd_wps_ap_pin_get(hapd);
512 if (pin_txt == NULL)
513 return -1;
514 return os_snprintf(buf, buflen, "%s", pin_txt);
515 }
516
517 if (os_strcmp(txt, "set") == 0) {
518 char *pin;
519 if (pos == NULL)
520 return -1;
521 pin = pos;
522 pos = os_strchr(pos, ' ');
523 if (pos) {
524 *pos++ = '\0';
525 timeout = atoi(pos);
526 }
527 if (os_strlen(pin) > buflen)
528 return -1;
529 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
530 return -1;
531 return os_snprintf(buf, buflen, "%s", pin);
532 }
533
534 return -1;
535}
536
537
538static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
539{
540 char *pos;
541 char *ssid, *auth, *encr = NULL, *key = NULL;
542
543 ssid = txt;
544 pos = os_strchr(txt, ' ');
545 if (!pos)
546 return -1;
547 *pos++ = '\0';
548
549 auth = pos;
550 pos = os_strchr(pos, ' ');
551 if (pos) {
552 *pos++ = '\0';
553 encr = pos;
554 pos = os_strchr(pos, ' ');
555 if (pos) {
556 *pos++ = '\0';
557 key = pos;
558 }
559 }
560
561 return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
562}
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700563
564
565static const char * pbc_status_str(enum pbc_status status)
566{
567 switch (status) {
568 case WPS_PBC_STATUS_DISABLE:
569 return "Disabled";
570 case WPS_PBC_STATUS_ACTIVE:
571 return "Active";
572 case WPS_PBC_STATUS_TIMEOUT:
573 return "Timed-out";
574 case WPS_PBC_STATUS_OVERLAP:
575 return "Overlap";
576 default:
577 return "Unknown";
578 }
579}
580
581
582static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
583 char *buf, size_t buflen)
584{
585 int ret;
586 char *pos, *end;
587
588 pos = buf;
589 end = buf + buflen;
590
591 ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
592 pbc_status_str(hapd->wps_stats.pbc_status));
593
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800594 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700595 return pos - buf;
596 pos += ret;
597
598 ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
599 (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
600 "Success":
601 (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
602 "Failed" : "None")));
603
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800604 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700605 return pos - buf;
606 pos += ret;
607
608 /* If status == Failure - Add possible Reasons */
609 if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
610 hapd->wps_stats.failure_reason > 0) {
611 ret = os_snprintf(pos, end - pos,
612 "Failure Reason: %s\n",
613 wps_ei_str(hapd->wps_stats.failure_reason));
614
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800615 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700616 return pos - buf;
617 pos += ret;
618 }
619
620 if (hapd->wps_stats.status) {
621 ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
622 MAC2STR(hapd->wps_stats.peer_addr));
623
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800624 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700625 return pos - buf;
626 pos += ret;
627 }
628
629 return pos - buf;
630}
631
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700632#endif /* CONFIG_WPS */
633
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800634#ifdef CONFIG_HS20
635
636static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
637 const char *cmd)
638{
639 u8 addr[ETH_ALEN];
640 const char *url;
641
642 if (hwaddr_aton(cmd, addr))
643 return -1;
644 url = cmd + 17;
645 if (*url == '\0') {
646 url = NULL;
647 } else {
648 if (*url != ' ')
649 return -1;
650 url++;
651 if (*url == '\0')
652 url = NULL;
653 }
654
655 return hs20_send_wnm_notification(hapd, addr, 1, url);
656}
657
658
659static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
660 const char *cmd)
661{
662 u8 addr[ETH_ALEN];
663 int code, reauth_delay, ret;
664 const char *pos;
665 size_t url_len;
666 struct wpabuf *req;
667
668 /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
669 if (hwaddr_aton(cmd, addr))
670 return -1;
671
672 pos = os_strchr(cmd, ' ');
673 if (pos == NULL)
674 return -1;
675 pos++;
676 code = atoi(pos);
677
678 pos = os_strchr(pos, ' ');
679 if (pos == NULL)
680 return -1;
681 pos++;
682 reauth_delay = atoi(pos);
683
684 url_len = 0;
685 pos = os_strchr(pos, ' ');
686 if (pos) {
687 pos++;
688 url_len = os_strlen(pos);
689 }
690
691 req = wpabuf_alloc(4 + url_len);
692 if (req == NULL)
693 return -1;
694 wpabuf_put_u8(req, code);
695 wpabuf_put_le16(req, reauth_delay);
696 wpabuf_put_u8(req, url_len);
697 if (pos)
698 wpabuf_put_data(req, pos, url_len);
699
700 wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
701 " to indicate imminent deauthentication (code=%d "
702 "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
703 ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
704 wpabuf_free(req);
705 return ret;
706}
707
708#endif /* CONFIG_HS20 */
709
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700710
Dmitry Shmidt051af732013-10-22 13:52:46 -0700711#ifdef CONFIG_INTERWORKING
712
713static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
714 const char *cmd)
715{
716 u8 qos_map_set[16 + 2 * 21], count = 0;
717 const char *pos = cmd;
718 int val, ret;
719
720 for (;;) {
721 if (count == sizeof(qos_map_set)) {
722 wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
723 return -1;
724 }
725
726 val = atoi(pos);
727 if (val < 0 || val > 255) {
728 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
729 return -1;
730 }
731
732 qos_map_set[count++] = val;
733 pos = os_strchr(pos, ',');
734 if (!pos)
735 break;
736 pos++;
737 }
738
739 if (count < 16 || count & 1) {
740 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
741 return -1;
742 }
743
744 ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
745 if (ret) {
746 wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
747 return -1;
748 }
749
750 os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
751 hapd->conf->qos_map_set_len = count;
752
753 return 0;
754}
755
756
757static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
758 const char *cmd)
759{
760 u8 addr[ETH_ALEN];
761 struct sta_info *sta;
762 struct wpabuf *buf;
763 u8 *qos_map_set = hapd->conf->qos_map_set;
764 u8 qos_map_set_len = hapd->conf->qos_map_set_len;
765 int ret;
766
767 if (!qos_map_set_len) {
768 wpa_printf(MSG_INFO, "QoS Map Set is not set");
769 return -1;
770 }
771
772 if (hwaddr_aton(cmd, addr))
773 return -1;
774
775 sta = ap_get_sta(hapd, addr);
776 if (sta == NULL) {
777 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
778 "for QoS Map Configuration message",
779 MAC2STR(addr));
780 return -1;
781 }
782
783 if (!sta->qos_map_enabled) {
784 wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
785 "support for QoS Map", MAC2STR(addr));
786 return -1;
787 }
788
789 buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
790 if (buf == NULL)
791 return -1;
792
793 wpabuf_put_u8(buf, WLAN_ACTION_QOS);
794 wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
795
796 /* QoS Map Set Element */
797 wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
798 wpabuf_put_u8(buf, qos_map_set_len);
799 wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
800
801 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
802 wpabuf_head(buf), wpabuf_len(buf));
803 wpabuf_free(buf);
804
805 return ret;
806}
807
808#endif /* CONFIG_INTERWORKING */
809
810
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800811#ifdef CONFIG_WNM
812
813static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
814 const char *cmd)
815{
816 u8 addr[ETH_ALEN];
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800817 int disassoc_timer;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800818 struct sta_info *sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800819
820 if (hwaddr_aton(cmd, addr))
821 return -1;
822 if (cmd[17] != ' ')
823 return -1;
824 disassoc_timer = atoi(cmd + 17);
825
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800826 sta = ap_get_sta(hapd, addr);
827 if (sta == NULL) {
828 wpa_printf(MSG_DEBUG, "Station " MACSTR
829 " not found for disassociation imminent message",
830 MAC2STR(addr));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800831 return -1;
832 }
833
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800834 return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800835}
836
837
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800838static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
839 const char *cmd)
840{
841 u8 addr[ETH_ALEN];
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700842 const char *url, *timerstr;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700843 int disassoc_timer;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800844 struct sta_info *sta;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800845
846 if (hwaddr_aton(cmd, addr))
847 return -1;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700848
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800849 sta = ap_get_sta(hapd, addr);
850 if (sta == NULL) {
851 wpa_printf(MSG_DEBUG, "Station " MACSTR
852 " not found for ESS disassociation imminent message",
853 MAC2STR(addr));
854 return -1;
855 }
856
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700857 timerstr = cmd + 17;
858 if (*timerstr != ' ')
859 return -1;
860 timerstr++;
861 disassoc_timer = atoi(timerstr);
862 if (disassoc_timer < 0 || disassoc_timer > 65535)
863 return -1;
864
865 url = os_strchr(timerstr, ' ');
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700866 if (url == NULL)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800867 return -1;
868 url++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800869
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800870 return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800871}
872
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800873
874static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
875 const char *cmd)
876{
877 u8 addr[ETH_ALEN];
878 const char *pos, *end;
879 int disassoc_timer = 0;
880 struct sta_info *sta;
881 u8 req_mode = 0, valid_int = 0x01;
882 u8 bss_term_dur[12];
883 char *url = NULL;
884 int ret;
885 u8 nei_rep[1000];
886 u8 *nei_pos = nei_rep;
887
888 if (hwaddr_aton(cmd, addr)) {
889 wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
890 return -1;
891 }
892
893 sta = ap_get_sta(hapd, addr);
894 if (sta == NULL) {
895 wpa_printf(MSG_DEBUG, "Station " MACSTR
896 " not found for BSS TM Request message",
897 MAC2STR(addr));
898 return -1;
899 }
900
901 pos = os_strstr(cmd, " disassoc_timer=");
902 if (pos) {
903 pos += 16;
904 disassoc_timer = atoi(pos);
905 if (disassoc_timer < 0 || disassoc_timer > 65535) {
906 wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
907 return -1;
908 }
909 }
910
911 pos = os_strstr(cmd, " valid_int=");
912 if (pos) {
913 pos += 11;
914 valid_int = atoi(pos);
915 }
916
917 pos = os_strstr(cmd, " bss_term=");
918 if (pos) {
919 pos += 10;
920 req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
921 /* TODO: TSF configurable/learnable */
922 bss_term_dur[0] = 4; /* Subelement ID */
923 bss_term_dur[1] = 10; /* Length */
924 os_memset(bss_term_dur, 2, 8);
925 end = os_strchr(pos, ',');
926 if (end == NULL) {
927 wpa_printf(MSG_DEBUG, "Invalid bss_term data");
928 return -1;
929 }
930 end++;
931 WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
932 }
933
934
935 /*
936 * BSS Transition Candidate List Entries - Neighbor Report elements
937 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
938 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
939 */
940 pos = cmd;
941 while (pos) {
942 u8 *nei_start;
943 long int val;
944 char *endptr, *tmp;
945
946 pos = os_strstr(pos, " neighbor=");
947 if (!pos)
948 break;
949 if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) {
950 wpa_printf(MSG_DEBUG,
951 "Not enough room for additional neighbor");
952 return -1;
953 }
954 pos += 10;
955
956 nei_start = nei_pos;
957 *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
958 nei_pos++; /* length to be filled in */
959
960 if (hwaddr_aton(pos, nei_pos)) {
961 wpa_printf(MSG_DEBUG, "Invalid BSSID");
962 return -1;
963 }
964 nei_pos += ETH_ALEN;
965 pos += 17;
966 if (*pos != ',') {
967 wpa_printf(MSG_DEBUG, "Missing BSSID Information");
968 return -1;
969 }
970 pos++;
971
972 val = strtol(pos, &endptr, 0);
973 WPA_PUT_LE32(nei_pos, val);
974 nei_pos += 4;
975 if (*endptr != ',') {
976 wpa_printf(MSG_DEBUG, "Missing Operating Class");
977 return -1;
978 }
979 pos = endptr + 1;
980
981 *nei_pos++ = atoi(pos); /* Operating Class */
982 pos = os_strchr(pos, ',');
983 if (pos == NULL) {
984 wpa_printf(MSG_DEBUG, "Missing Channel Number");
985 return -1;
986 }
987 pos++;
988
989 *nei_pos++ = atoi(pos); /* Channel Number */
990 pos = os_strchr(pos, ',');
991 if (pos == NULL) {
992 wpa_printf(MSG_DEBUG, "Missing PHY Type");
993 return -1;
994 }
995 pos++;
996
997 *nei_pos++ = atoi(pos); /* PHY Type */
998 end = os_strchr(pos, ' ');
999 tmp = os_strchr(pos, ',');
1000 if (tmp && (!end || tmp < end)) {
1001 /* Optional Subelements (hexdump) */
1002 size_t len;
1003
1004 pos = tmp + 1;
1005 end = os_strchr(pos, ' ');
1006 if (end)
1007 len = end - pos;
1008 else
1009 len = os_strlen(pos);
1010 if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) {
1011 wpa_printf(MSG_DEBUG,
1012 "Not enough room for neighbor subelements");
1013 return -1;
1014 }
1015 if (len & 0x01 ||
1016 hexstr2bin(pos, nei_pos, len / 2) < 0) {
1017 wpa_printf(MSG_DEBUG,
1018 "Invalid neighbor subelement info");
1019 return -1;
1020 }
1021 nei_pos += len / 2;
1022 pos = end;
1023 }
1024
1025 nei_start[1] = nei_pos - nei_start - 2;
1026 }
1027
1028 pos = os_strstr(cmd, " url=");
1029 if (pos) {
1030 size_t len;
1031 pos += 5;
1032 end = os_strchr(pos, ' ');
1033 if (end)
1034 len = end - pos;
1035 else
1036 len = os_strlen(pos);
1037 url = os_malloc(len + 1);
1038 if (url == NULL)
1039 return -1;
1040 os_memcpy(url, pos, len);
1041 url[len] = '\0';
1042 req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
1043 }
1044
1045 if (os_strstr(cmd, " pref=1"))
1046 req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
1047 if (os_strstr(cmd, " abridged=1"))
1048 req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1049 if (os_strstr(cmd, " disassoc_imminent=1"))
1050 req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
1051
1052 ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
1053 valid_int, bss_term_dur, url,
1054 nei_pos > nei_rep ? nei_rep : NULL,
1055 nei_pos - nei_rep);
1056 os_free(url);
1057 return ret;
1058}
1059
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001060#endif /* CONFIG_WNM */
1061
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001062
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001063static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
1064 char *buf, size_t buflen)
1065{
1066 int ret = 0;
1067 char *pos, *end;
1068
1069 pos = buf;
1070 end = buf + buflen;
1071
1072 WPA_ASSERT(hapd->conf->wpa_key_mgmt);
1073
1074 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
1075 ret = os_snprintf(pos, end - pos, "WPA-PSK ");
1076 if (os_snprintf_error(end - pos, ret))
1077 return pos - buf;
1078 pos += ret;
1079 }
1080 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1081 ret = os_snprintf(pos, end - pos, "WPA-EAP ");
1082 if (os_snprintf_error(end - pos, ret))
1083 return pos - buf;
1084 pos += ret;
1085 }
1086#ifdef CONFIG_IEEE80211R
1087 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1088 ret = os_snprintf(pos, end - pos, "FT-PSK ");
1089 if (os_snprintf_error(end - pos, ret))
1090 return pos - buf;
1091 pos += ret;
1092 }
1093 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1094 ret = os_snprintf(pos, end - pos, "FT-EAP ");
1095 if (os_snprintf_error(end - pos, ret))
1096 return pos - buf;
1097 pos += ret;
1098 }
1099#ifdef CONFIG_SAE
1100 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
1101 ret = os_snprintf(pos, end - pos, "FT-SAE ");
1102 if (os_snprintf_error(end - pos, ret))
1103 return pos - buf;
1104 pos += ret;
1105 }
1106#endif /* CONFIG_SAE */
1107#endif /* CONFIG_IEEE80211R */
1108#ifdef CONFIG_IEEE80211W
1109 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1110 ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
1111 if (os_snprintf_error(end - pos, ret))
1112 return pos - buf;
1113 pos += ret;
1114 }
1115 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1116 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
1117 if (os_snprintf_error(end - pos, ret))
1118 return pos - buf;
1119 pos += ret;
1120 }
1121#endif /* CONFIG_IEEE80211W */
1122#ifdef CONFIG_SAE
1123 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
1124 ret = os_snprintf(pos, end - pos, "SAE ");
1125 if (os_snprintf_error(end - pos, ret))
1126 return pos - buf;
1127 pos += ret;
1128 }
1129#endif /* CONFIG_SAE */
1130 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
1131 ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
1132 if (os_snprintf_error(end - pos, ret))
1133 return pos - buf;
1134 pos += ret;
1135 }
1136 if (hapd->conf->wpa_key_mgmt &
1137 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
1138 ret = os_snprintf(pos, end - pos,
1139 "WPA-EAP-SUITE-B-192 ");
1140 if (os_snprintf_error(end - pos, ret))
1141 return pos - buf;
1142 pos += ret;
1143 }
1144
1145 if (pos > buf && *(pos - 1) == ' ') {
1146 *(pos - 1) = '\0';
1147 pos--;
1148 }
1149
1150 return pos - buf;
1151}
1152
1153
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001154static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
1155 char *buf, size_t buflen)
1156{
1157 int ret;
1158 char *pos, *end;
1159
1160 pos = buf;
1161 end = buf + buflen;
1162
1163 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
1164 "ssid=%s\n",
1165 MAC2STR(hapd->own_addr),
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001166 wpa_ssid_txt(hapd->conf->ssid.ssid,
1167 hapd->conf->ssid.ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001168 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001169 return pos - buf;
1170 pos += ret;
1171
1172#ifdef CONFIG_WPS
1173 ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
1174 hapd->conf->wps_state == 0 ? "disabled" :
1175 (hapd->conf->wps_state == 1 ? "not configured" :
1176 "configured"));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001177 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001178 return pos - buf;
1179 pos += ret;
1180
1181 if (hapd->conf->wps_state && hapd->conf->wpa &&
1182 hapd->conf->ssid.wpa_passphrase) {
1183 ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
1184 hapd->conf->ssid.wpa_passphrase);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001185 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001186 return pos - buf;
1187 pos += ret;
1188 }
1189
1190 if (hapd->conf->wps_state && hapd->conf->wpa &&
1191 hapd->conf->ssid.wpa_psk &&
1192 hapd->conf->ssid.wpa_psk->group) {
1193 char hex[PMK_LEN * 2 + 1];
1194 wpa_snprintf_hex(hex, sizeof(hex),
1195 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
1196 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001197 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001198 return pos - buf;
1199 pos += ret;
1200 }
1201#endif /* CONFIG_WPS */
1202
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001203 if (hapd->conf->wpa) {
1204 ret = os_snprintf(pos, end - pos, "wpa=%d\n", hapd->conf->wpa);
1205 if (os_snprintf_error(end - pos, ret))
1206 return pos - buf;
1207 pos += ret;
1208 }
1209
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001210 if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
1211 ret = os_snprintf(pos, end - pos, "key_mgmt=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001212 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001213 return pos - buf;
1214 pos += ret;
1215
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001216 pos += hostapd_ctrl_iface_get_key_mgmt(hapd, pos, end - pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001217
1218 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001219 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001220 return pos - buf;
1221 pos += ret;
1222 }
1223
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001224 if (hapd->conf->wpa) {
1225 ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
1226 wpa_cipher_txt(hapd->conf->wpa_group));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001227 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001228 return pos - buf;
1229 pos += ret;
1230 }
1231
1232 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
1233 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001234 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001235 return pos - buf;
1236 pos += ret;
1237
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001238 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
1239 " ");
1240 if (ret < 0)
1241 return pos - buf;
1242 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001243
1244 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001245 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001246 return pos - buf;
1247 pos += ret;
1248 }
1249
1250 if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
1251 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001252 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001253 return pos - buf;
1254 pos += ret;
1255
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001256 ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001257 " ");
1258 if (ret < 0)
1259 return pos - buf;
1260 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001261
1262 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001263 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264 return pos - buf;
1265 pos += ret;
1266 }
1267
1268 return pos - buf;
1269}
1270
1271
1272static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1273{
1274 char *value;
1275 int ret = 0;
1276
1277 value = os_strchr(cmd, ' ');
1278 if (value == NULL)
1279 return -1;
1280 *value++ = '\0';
1281
1282 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
1283 if (0) {
1284#ifdef CONFIG_WPS_TESTING
1285 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
1286 long int val;
1287 val = strtol(value, NULL, 0);
1288 if (val < 0 || val > 0xff) {
1289 ret = -1;
1290 wpa_printf(MSG_DEBUG, "WPS: Invalid "
1291 "wps_version_number %ld", val);
1292 } else {
1293 wps_version_number = val;
1294 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
1295 "version %u.%u",
1296 (wps_version_number & 0xf0) >> 4,
1297 wps_version_number & 0x0f);
1298 hostapd_wps_update_ie(hapd);
1299 }
1300 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
1301 wps_testing_dummy_cred = atoi(value);
1302 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
1303 wps_testing_dummy_cred);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001304 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
1305 wps_corrupt_pkhash = atoi(value);
1306 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
1307 wps_corrupt_pkhash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001308#endif /* CONFIG_WPS_TESTING */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001309#ifdef CONFIG_INTERWORKING
1310 } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
1311 int val = atoi(value);
1312 if (val <= 0)
1313 ret = -1;
1314 else
1315 hapd->gas_frag_limit = val;
1316#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001317#ifdef CONFIG_TESTING_OPTIONS
1318 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
1319 hapd->ext_mgmt_frame_handling = atoi(value);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001320 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
1321 hapd->ext_eapol_frame_io = atoi(value);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001322#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001323 } else {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001324 struct sta_info *sta;
1325 int vlan_id;
1326
Dmitry Shmidt04949592012-07-19 12:16:46 -07001327 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001328 if (ret)
1329 return ret;
1330
1331 if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
1332 for (sta = hapd->sta_list; sta; sta = sta->next) {
1333 if (hostapd_maclist_found(
1334 hapd->conf->deny_mac,
1335 hapd->conf->num_deny_mac, sta->addr,
1336 &vlan_id) &&
1337 (!vlan_id || vlan_id == sta->vlan_id))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001338 ap_sta_disconnect(
1339 hapd, sta, sta->addr,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001340 WLAN_REASON_UNSPECIFIED);
1341 }
1342 } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED &&
1343 os_strcasecmp(cmd, "accept_mac_file") == 0) {
1344 for (sta = hapd->sta_list; sta; sta = sta->next) {
1345 if (!hostapd_maclist_found(
1346 hapd->conf->accept_mac,
1347 hapd->conf->num_accept_mac,
1348 sta->addr, &vlan_id) ||
1349 (vlan_id && vlan_id != sta->vlan_id))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001350 ap_sta_disconnect(
1351 hapd, sta, sta->addr,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001352 WLAN_REASON_UNSPECIFIED);
1353 }
1354 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001355 }
1356
1357 return ret;
1358}
1359
1360
1361static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1362 char *buf, size_t buflen)
1363{
1364 int res;
1365
1366 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1367
1368 if (os_strcmp(cmd, "version") == 0) {
1369 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001370 if (os_snprintf_error(buflen, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001371 return -1;
1372 return res;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001373 } else if (os_strcmp(cmd, "tls_library") == 0) {
1374 res = tls_get_library_version(buf, buflen);
1375 if (os_snprintf_error(buflen, res))
1376 return -1;
1377 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001378 }
1379
1380 return -1;
1381}
1382
1383
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001384static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1385{
1386 if (hostapd_enable_iface(iface) < 0) {
1387 wpa_printf(MSG_ERROR, "Enabling of interface failed");
1388 return -1;
1389 }
1390 return 0;
1391}
1392
1393
1394static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1395{
1396 if (hostapd_reload_iface(iface) < 0) {
1397 wpa_printf(MSG_ERROR, "Reloading of interface failed");
1398 return -1;
1399 }
1400 return 0;
1401}
1402
1403
1404static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1405{
1406 if (hostapd_disable_iface(iface) < 0) {
1407 wpa_printf(MSG_ERROR, "Disabling of interface failed");
1408 return -1;
1409 }
1410 return 0;
1411}
1412
1413
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001414#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001415
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001416static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
1417{
1418 union wpa_event_data data;
1419 char *pos, *param;
1420 enum wpa_event_type event;
1421
1422 wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
1423
1424 os_memset(&data, 0, sizeof(data));
1425
1426 param = os_strchr(cmd, ' ');
1427 if (param == NULL)
1428 return -1;
1429 *param++ = '\0';
1430
1431 if (os_strcmp(cmd, "DETECTED") == 0)
1432 event = EVENT_DFS_RADAR_DETECTED;
1433 else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
1434 event = EVENT_DFS_CAC_FINISHED;
1435 else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
1436 event = EVENT_DFS_CAC_ABORTED;
1437 else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
1438 event = EVENT_DFS_NOP_FINISHED;
1439 else {
1440 wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
1441 cmd);
1442 return -1;
1443 }
1444
1445 pos = os_strstr(param, "freq=");
1446 if (pos)
1447 data.dfs_event.freq = atoi(pos + 5);
1448
1449 pos = os_strstr(param, "ht_enabled=1");
1450 if (pos)
1451 data.dfs_event.ht_enabled = 1;
1452
1453 pos = os_strstr(param, "chan_offset=");
1454 if (pos)
1455 data.dfs_event.chan_offset = atoi(pos + 12);
1456
1457 pos = os_strstr(param, "chan_width=");
1458 if (pos)
1459 data.dfs_event.chan_width = atoi(pos + 11);
1460
1461 pos = os_strstr(param, "cf1=");
1462 if (pos)
1463 data.dfs_event.cf1 = atoi(pos + 4);
1464
1465 pos = os_strstr(param, "cf2=");
1466 if (pos)
1467 data.dfs_event.cf2 = atoi(pos + 4);
1468
1469 wpa_supplicant_event(hapd, event, &data);
1470
1471 return 0;
1472}
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001473
1474
1475static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
1476{
1477 size_t len;
1478 u8 *buf;
1479 int res;
1480
1481 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
1482
1483 len = os_strlen(cmd);
1484 if (len & 1)
1485 return -1;
1486 len /= 2;
1487
1488 buf = os_malloc(len);
1489 if (buf == NULL)
1490 return -1;
1491
1492 if (hexstr2bin(cmd, buf, len) < 0) {
1493 os_free(buf);
1494 return -1;
1495 }
1496
1497 res = hostapd_drv_send_mlme(hapd, buf, len, 0);
1498 os_free(buf);
1499 return res;
1500}
1501
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001502
1503static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
1504{
1505 char *pos;
1506 u8 src[ETH_ALEN], *buf;
1507 int used;
1508 size_t len;
1509
1510 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
1511
1512 pos = cmd;
1513 used = hwaddr_aton2(pos, src);
1514 if (used < 0)
1515 return -1;
1516 pos += used;
1517 while (*pos == ' ')
1518 pos++;
1519
1520 len = os_strlen(pos);
1521 if (len & 1)
1522 return -1;
1523 len /= 2;
1524
1525 buf = os_malloc(len);
1526 if (buf == NULL)
1527 return -1;
1528
1529 if (hexstr2bin(pos, buf, len) < 0) {
1530 os_free(buf);
1531 return -1;
1532 }
1533
1534 ieee802_1x_receive(hapd, src, buf, len);
1535 os_free(buf);
1536
1537 return 0;
1538}
1539
1540
1541static u16 ipv4_hdr_checksum(const void *buf, size_t len)
1542{
1543 size_t i;
1544 u32 sum = 0;
1545 const u16 *pos = buf;
1546
1547 for (i = 0; i < len / 2; i++)
1548 sum += *pos++;
1549
1550 while (sum >> 16)
1551 sum = (sum & 0xffff) + (sum >> 16);
1552
1553 return sum ^ 0xffff;
1554}
1555
1556
1557#define HWSIM_PACKETLEN 1500
1558#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
1559
1560void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
1561 size_t len)
1562{
1563 struct hostapd_data *hapd = ctx;
1564 const struct ether_header *eth;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001565 struct iphdr ip;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001566 const u8 *pos;
1567 unsigned int i;
1568
1569 if (len != HWSIM_PACKETLEN)
1570 return;
1571
1572 eth = (const struct ether_header *) buf;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001573 os_memcpy(&ip, eth + 1, sizeof(ip));
1574 pos = &buf[sizeof(*eth) + sizeof(ip)];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001575
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001576 if (ip.ihl != 5 || ip.version != 4 ||
1577 ntohs(ip.tot_len) != HWSIM_IP_LEN)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001578 return;
1579
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001580 for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001581 if (*pos != (u8) i)
1582 return;
1583 pos++;
1584 }
1585
1586 wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
1587 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
1588}
1589
1590
1591static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
1592 char *cmd)
1593{
1594 int enabled = atoi(cmd);
1595 char *pos;
1596 const char *ifname;
1597
1598 if (!enabled) {
1599 if (hapd->l2_test) {
1600 l2_packet_deinit(hapd->l2_test);
1601 hapd->l2_test = NULL;
1602 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1603 "test data: Disabled");
1604 }
1605 return 0;
1606 }
1607
1608 if (hapd->l2_test)
1609 return 0;
1610
1611 pos = os_strstr(cmd, " ifname=");
1612 if (pos)
1613 ifname = pos + 8;
1614 else
1615 ifname = hapd->conf->iface;
1616
1617 hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
1618 ETHERTYPE_IP, hostapd_data_test_rx,
1619 hapd, 1);
1620 if (hapd->l2_test == NULL)
1621 return -1;
1622
1623 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
1624
1625 return 0;
1626}
1627
1628
1629static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
1630{
1631 u8 dst[ETH_ALEN], src[ETH_ALEN];
1632 char *pos;
1633 int used;
1634 long int val;
1635 u8 tos;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001636 u8 buf[2 + HWSIM_PACKETLEN];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001637 struct ether_header *eth;
1638 struct iphdr *ip;
1639 u8 *dpos;
1640 unsigned int i;
1641
1642 if (hapd->l2_test == NULL)
1643 return -1;
1644
1645 /* format: <dst> <src> <tos> */
1646
1647 pos = cmd;
1648 used = hwaddr_aton2(pos, dst);
1649 if (used < 0)
1650 return -1;
1651 pos += used;
1652 while (*pos == ' ')
1653 pos++;
1654 used = hwaddr_aton2(pos, src);
1655 if (used < 0)
1656 return -1;
1657 pos += used;
1658
1659 val = strtol(pos, NULL, 0);
1660 if (val < 0 || val > 0xff)
1661 return -1;
1662 tos = val;
1663
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001664 eth = (struct ether_header *) &buf[2];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001665 os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
1666 os_memcpy(eth->ether_shost, src, ETH_ALEN);
1667 eth->ether_type = htons(ETHERTYPE_IP);
1668 ip = (struct iphdr *) (eth + 1);
1669 os_memset(ip, 0, sizeof(*ip));
1670 ip->ihl = 5;
1671 ip->version = 4;
1672 ip->ttl = 64;
1673 ip->tos = tos;
1674 ip->tot_len = htons(HWSIM_IP_LEN);
1675 ip->protocol = 1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001676 ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
1677 ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001678 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
1679 dpos = (u8 *) (ip + 1);
1680 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
1681 *dpos++ = i;
1682
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001683 if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001684 HWSIM_PACKETLEN) < 0)
1685 return -1;
1686
1687 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
1688 " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
1689
1690 return 0;
1691}
1692
1693
1694static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
1695 char *cmd)
1696{
1697 u8 *buf;
1698 struct ether_header *eth;
1699 struct l2_packet_data *l2 = NULL;
1700 size_t len;
1701 u16 ethertype;
1702 int res = -1;
1703 const char *ifname = hapd->conf->iface;
1704
1705 if (os_strncmp(cmd, "ifname=", 7) == 0) {
1706 cmd += 7;
1707 ifname = cmd;
1708 cmd = os_strchr(cmd, ' ');
1709 if (cmd == NULL)
1710 return -1;
1711 *cmd++ = '\0';
1712 }
1713
1714 len = os_strlen(cmd);
1715 if (len & 1 || len < ETH_HLEN * 2)
1716 return -1;
1717 len /= 2;
1718
1719 buf = os_malloc(len);
1720 if (buf == NULL)
1721 return -1;
1722
1723 if (hexstr2bin(cmd, buf, len) < 0)
1724 goto done;
1725
1726 eth = (struct ether_header *) buf;
1727 ethertype = ntohs(eth->ether_type);
1728
1729 l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
1730 hostapd_data_test_rx, hapd, 1);
1731 if (l2 == NULL)
1732 goto done;
1733
1734 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
1735 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
1736done:
1737 if (l2)
1738 l2_packet_deinit(l2);
1739 os_free(buf);
1740
1741 return res < 0 ? -1 : 0;
1742}
1743
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001744
1745static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
1746{
1747#ifdef WPA_TRACE_BFD
1748 extern char wpa_trace_fail_func[256];
1749 extern unsigned int wpa_trace_fail_after;
1750 char *pos;
1751
1752 wpa_trace_fail_after = atoi(cmd);
1753 pos = os_strchr(cmd, ':');
1754 if (pos) {
1755 pos++;
1756 os_strlcpy(wpa_trace_fail_func, pos,
1757 sizeof(wpa_trace_fail_func));
1758 } else {
1759 wpa_trace_fail_after = 0;
1760 }
1761
1762 return 0;
1763#else /* WPA_TRACE_BFD */
1764 return -1;
1765#endif /* WPA_TRACE_BFD */
1766}
1767
1768
1769static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
1770 char *buf, size_t buflen)
1771{
1772#ifdef WPA_TRACE_BFD
1773 extern char wpa_trace_fail_func[256];
1774 extern unsigned int wpa_trace_fail_after;
1775
1776 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
1777 wpa_trace_fail_func);
1778#else /* WPA_TRACE_BFD */
1779 return -1;
1780#endif /* WPA_TRACE_BFD */
1781}
1782
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001783
1784static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
1785{
1786#ifdef WPA_TRACE_BFD
1787 extern char wpa_trace_test_fail_func[256];
1788 extern unsigned int wpa_trace_test_fail_after;
1789 char *pos;
1790
1791 wpa_trace_test_fail_after = atoi(cmd);
1792 pos = os_strchr(cmd, ':');
1793 if (pos) {
1794 pos++;
1795 os_strlcpy(wpa_trace_test_fail_func, pos,
1796 sizeof(wpa_trace_test_fail_func));
1797 } else {
1798 wpa_trace_test_fail_after = 0;
1799 }
1800
1801 return 0;
1802#else /* WPA_TRACE_BFD */
1803 return -1;
1804#endif /* WPA_TRACE_BFD */
1805}
1806
1807
1808static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
1809 char *buf, size_t buflen)
1810{
1811#ifdef WPA_TRACE_BFD
1812 extern char wpa_trace_test_fail_func[256];
1813 extern unsigned int wpa_trace_test_fail_after;
1814
1815 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
1816 wpa_trace_test_fail_func);
1817#else /* WPA_TRACE_BFD */
1818 return -1;
1819#endif /* WPA_TRACE_BFD */
1820}
1821
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001822#endif /* CONFIG_TESTING_OPTIONS */
1823
1824
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001825static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
1826 char *pos)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001827{
1828#ifdef NEED_AP_MLME
1829 struct csa_settings settings;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001830 int ret;
1831 unsigned int i;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001832
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001833 ret = hostapd_parse_csa_settings(pos, &settings);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001834 if (ret)
1835 return ret;
1836
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001837 for (i = 0; i < iface->num_bss; i++) {
1838 ret = hostapd_switch_channel(iface->bss[i], &settings);
1839 if (ret) {
1840 /* FIX: What do we do if CSA fails in the middle of
1841 * submitting multi-BSS CSA requests? */
1842 return ret;
1843 }
1844 }
1845
1846 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001847#else /* NEED_AP_MLME */
1848 return -1;
1849#endif /* NEED_AP_MLME */
1850}
1851
1852
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001853static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
1854 int reply_size, const char *param)
1855{
1856#ifdef RADIUS_SERVER
1857 if (os_strcmp(param, "radius_server") == 0) {
1858 return radius_server_get_mib(hapd->radius_srv, reply,
1859 reply_size);
1860 }
1861#endif /* RADIUS_SERVER */
1862 return -1;
1863}
1864
1865
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001866static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
1867 char *buf, size_t buflen)
1868{
1869 int ret;
1870 char *pos;
1871 u8 *data = NULL;
1872 unsigned int vendor_id, subcmd;
1873 struct wpabuf *reply;
1874 size_t data_len = 0;
1875
1876 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
1877 vendor_id = strtoul(cmd, &pos, 16);
1878 if (!isblank(*pos))
1879 return -EINVAL;
1880
1881 subcmd = strtoul(pos, &pos, 10);
1882
1883 if (*pos != '\0') {
1884 if (!isblank(*pos++))
1885 return -EINVAL;
1886 data_len = os_strlen(pos);
1887 }
1888
1889 if (data_len) {
1890 data_len /= 2;
1891 data = os_malloc(data_len);
1892 if (!data)
1893 return -ENOBUFS;
1894
1895 if (hexstr2bin(pos, data, data_len)) {
1896 wpa_printf(MSG_DEBUG,
1897 "Vendor command: wrong parameter format");
1898 os_free(data);
1899 return -EINVAL;
1900 }
1901 }
1902
1903 reply = wpabuf_alloc((buflen - 1) / 2);
1904 if (!reply) {
1905 os_free(data);
1906 return -ENOBUFS;
1907 }
1908
1909 ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
1910 reply);
1911
1912 if (ret == 0)
1913 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
1914 wpabuf_len(reply));
1915
1916 wpabuf_free(reply);
1917 os_free(data);
1918
1919 return ret;
1920}
1921
1922
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001923static int hostapd_ctrl_iface_eapol_reauth(struct hostapd_data *hapd,
1924 const char *cmd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001925{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001926 u8 addr[ETH_ALEN];
1927 struct sta_info *sta;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001928
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001929 if (hwaddr_aton(cmd, addr))
1930 return -1;
1931
1932 sta = ap_get_sta(hapd, addr);
1933 if (!sta || !sta->eapol_sm)
1934 return -1;
1935
1936 eapol_auth_reauthenticate(sta->eapol_sm);
1937 return 0;
1938}
1939
1940
1941static int hostapd_ctrl_iface_eapol_set(struct hostapd_data *hapd, char *cmd)
1942{
1943 u8 addr[ETH_ALEN];
1944 struct sta_info *sta;
1945 char *pos = cmd, *param;
1946
1947 if (hwaddr_aton(pos, addr) || pos[17] != ' ')
1948 return -1;
1949 pos += 18;
1950 param = pos;
1951 pos = os_strchr(pos, ' ');
1952 if (!pos)
1953 return -1;
1954 *pos++ = '\0';
1955
1956 sta = ap_get_sta(hapd, addr);
1957 if (!sta || !sta->eapol_sm)
1958 return -1;
1959
1960 return eapol_auth_set_conf(sta->eapol_sm, param, pos);
1961}
1962
1963
1964static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
1965 char *buf, size_t buflen)
1966{
1967 char *pos, *end, *stamp;
1968 int ret;
1969
1970 /* cmd: "LOG_LEVEL [<level>]" */
1971 if (*cmd == '\0') {
1972 pos = buf;
1973 end = buf + buflen;
1974 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
1975 "Timestamp: %d\n",
1976 debug_level_str(wpa_debug_level),
1977 wpa_debug_timestamp);
1978 if (os_snprintf_error(end - pos, ret))
1979 ret = 0;
1980
1981 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001982 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001983
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001984 while (*cmd == ' ')
1985 cmd++;
1986
1987 stamp = os_strchr(cmd, ' ');
1988 if (stamp) {
1989 *stamp++ = '\0';
1990 while (*stamp == ' ') {
1991 stamp++;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001992 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001993 }
1994
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001995 if (os_strlen(cmd)) {
1996 int level = str_to_debug_level(cmd);
1997 if (level < 0)
1998 return -1;
1999 wpa_debug_level = level;
2000 }
2001
2002 if (stamp && os_strlen(stamp))
2003 wpa_debug_timestamp = atoi(stamp);
2004
2005 os_memcpy(buf, "OK\n", 3);
2006 return 3;
2007}
2008
2009
2010#ifdef NEED_AP_MLME
2011static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
2012 char *buf, size_t buflen)
2013{
2014 struct hostapd_iface *iface = hapd->iface;
2015 char *pos, *end;
2016 struct hostapd_sta_info *info;
2017 struct os_reltime now;
2018
2019 sta_track_expire(iface, 0);
2020
2021 pos = buf;
2022 end = buf + buflen;
2023
2024 os_get_reltime(&now);
2025 dl_list_for_each_reverse(info, &iface->sta_seen,
2026 struct hostapd_sta_info, list) {
2027 struct os_reltime age;
2028 int ret;
2029
2030 os_reltime_sub(&now, &info->last_seen, &age);
2031 ret = os_snprintf(pos, end - pos, MACSTR " %u\n",
2032 MAC2STR(info->addr), (unsigned int) age.sec);
2033 if (os_snprintf_error(end - pos, ret))
2034 break;
2035 pos += ret;
2036 }
2037
2038 return pos - buf;
2039}
2040#endif /* NEED_AP_MLME */
2041
2042
2043static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
2044 char *buf, char *reply,
2045 int reply_size,
2046 struct sockaddr_un *from,
2047 socklen_t fromlen)
2048{
2049 int reply_len, res;
2050
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002051 os_memcpy(reply, "OK\n", 3);
2052 reply_len = 3;
2053
2054 if (os_strcmp(buf, "PING") == 0) {
2055 os_memcpy(reply, "PONG\n", 5);
2056 reply_len = 5;
2057 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
2058 if (wpa_debug_reopen_file() < 0)
2059 reply_len = -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002060 } else if (os_strcmp(buf, "STATUS") == 0) {
2061 reply_len = hostapd_ctrl_iface_status(hapd, reply,
2062 reply_size);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002063 } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
2064 reply_len = hostapd_drv_status(hapd, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002065 } else if (os_strcmp(buf, "MIB") == 0) {
2066 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
2067 if (reply_len >= 0) {
2068 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
2069 reply_size - reply_len);
2070 if (res < 0)
2071 reply_len = -1;
2072 else
2073 reply_len += res;
2074 }
2075 if (reply_len >= 0) {
2076 res = ieee802_1x_get_mib(hapd, reply + reply_len,
2077 reply_size - reply_len);
2078 if (res < 0)
2079 reply_len = -1;
2080 else
2081 reply_len += res;
2082 }
2083#ifndef CONFIG_NO_RADIUS
2084 if (reply_len >= 0) {
2085 res = radius_client_get_mib(hapd->radius,
2086 reply + reply_len,
2087 reply_size - reply_len);
2088 if (res < 0)
2089 reply_len = -1;
2090 else
2091 reply_len += res;
2092 }
2093#endif /* CONFIG_NO_RADIUS */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002094 } else if (os_strncmp(buf, "MIB ", 4) == 0) {
2095 reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
2096 buf + 4);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002097 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
2098 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
2099 reply_size);
2100 } else if (os_strncmp(buf, "STA ", 4) == 0) {
2101 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
2102 reply_size);
2103 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
2104 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
2105 reply_size);
2106 } else if (os_strcmp(buf, "ATTACH") == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002107 if (hostapd_ctrl_iface_attach(hapd, from, fromlen))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002108 reply_len = -1;
2109 } else if (os_strcmp(buf, "DETACH") == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002110 if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002111 reply_len = -1;
2112 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002113 if (hostapd_ctrl_iface_level(hapd, from, fromlen,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002114 buf + 6))
2115 reply_len = -1;
2116 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
2117 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
2118 reply_len = -1;
2119 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
2120 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
2121 reply_len = -1;
2122 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
2123 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
2124 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002125 } else if (os_strcmp(buf, "STOP_AP") == 0) {
2126 if (hostapd_ctrl_iface_stop_ap(hapd))
2127 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002128#ifdef CONFIG_IEEE80211W
2129#ifdef NEED_AP_MLME
2130 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
2131 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
2132 reply_len = -1;
2133#endif /* NEED_AP_MLME */
2134#endif /* CONFIG_IEEE80211W */
2135#ifdef CONFIG_WPS
2136 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
2137 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
2138 reply_len = -1;
2139 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
2140 reply_len = hostapd_ctrl_iface_wps_check_pin(
2141 hapd, buf + 14, reply, reply_size);
2142 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
2143 if (hostapd_wps_button_pushed(hapd, NULL))
2144 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002145 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
2146 if (hostapd_wps_cancel(hapd))
2147 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002148 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
2149 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
2150 reply, reply_size);
2151 } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
2152 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
2153 reply_len = -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002154 } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
2155 reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
2156 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002157#ifdef CONFIG_WPS_NFC
2158 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
2159 if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
2160 reply_len = -1;
2161 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
2162 reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
2163 hapd, buf + 21, reply, reply_size);
2164 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
2165 reply_len = hostapd_ctrl_iface_wps_nfc_token(
2166 hapd, buf + 14, reply, reply_size);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002167 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
2168 reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
2169 hapd, buf + 21, reply, reply_size);
2170 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
2171 if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
2172 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002173#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002174#endif /* CONFIG_WPS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002175#ifdef CONFIG_INTERWORKING
2176 } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
2177 if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
2178 reply_len = -1;
2179 } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
2180 if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
2181 reply_len = -1;
2182#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002183#ifdef CONFIG_HS20
2184 } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
2185 if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
2186 reply_len = -1;
2187 } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
2188 if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
2189 reply_len = -1;
2190#endif /* CONFIG_HS20 */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002191#ifdef CONFIG_WNM
2192 } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
2193 if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
2194 reply_len = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002195 } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
2196 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
2197 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002198 } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
2199 if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
2200 reply_len = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002201#endif /* CONFIG_WNM */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002202 } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
2203 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
2204 reply_size);
2205 } else if (os_strncmp(buf, "SET ", 4) == 0) {
2206 if (hostapd_ctrl_iface_set(hapd, buf + 4))
2207 reply_len = -1;
2208 } else if (os_strncmp(buf, "GET ", 4) == 0) {
2209 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
2210 reply_size);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002211 } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
2212 if (hostapd_ctrl_iface_enable(hapd->iface))
2213 reply_len = -1;
2214 } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
2215 if (hostapd_ctrl_iface_reload(hapd->iface))
2216 reply_len = -1;
2217 } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
2218 if (hostapd_ctrl_iface_disable(hapd->iface))
2219 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002220 } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
2221 if (ieee802_11_set_beacon(hapd))
2222 reply_len = -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002223#ifdef CONFIG_TESTING_OPTIONS
2224 } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
2225 if (hostapd_ctrl_iface_radar(hapd, buf + 6))
2226 reply_len = -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002227 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
2228 if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
2229 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002230 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
2231 if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
2232 reply_len = -1;
2233 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
2234 if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
2235 reply_len = -1;
2236 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
2237 if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
2238 reply_len = -1;
2239 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
2240 if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
2241 reply_len = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002242 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
2243 if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
2244 reply_len = -1;
2245 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
2246 reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
2247 reply_size);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002248 } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
2249 if (hostapd_ctrl_test_fail(hapd, buf + 10) < 0)
2250 reply_len = -1;
2251 } else if (os_strcmp(buf, "GET_FAIL") == 0) {
2252 reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002253#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002254 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002255 if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002256 reply_len = -1;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07002257 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
2258 reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
2259 reply_size);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002260 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
2261 ieee802_1x_erp_flush(hapd);
2262#ifdef RADIUS_SERVER
2263 radius_server_erp_flush(hapd->radius_srv);
2264#endif /* RADIUS_SERVER */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002265 } else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
2266 if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
2267 reply_len = -1;
2268 } else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
2269 if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
2270 reply_len = -1;
2271 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
2272 reply_len = hostapd_ctrl_iface_log_level(
2273 hapd, buf + 9, reply, reply_size);
2274#ifdef NEED_AP_MLME
2275 } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
2276 reply_len = hostapd_ctrl_iface_track_sta_list(
2277 hapd, reply, reply_size);
2278#endif /* NEED_AP_MLME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002279 } else {
2280 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
2281 reply_len = 16;
2282 }
2283
2284 if (reply_len < 0) {
2285 os_memcpy(reply, "FAIL\n", 5);
2286 reply_len = 5;
2287 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002288
2289 return reply_len;
2290}
2291
2292
2293static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
2294 void *sock_ctx)
2295{
2296 struct hostapd_data *hapd = eloop_ctx;
2297 char buf[4096];
2298 int res;
2299 struct sockaddr_un from;
2300 socklen_t fromlen = sizeof(from);
2301 char *reply;
2302 const int reply_size = 4096;
2303 int reply_len;
2304 int level = MSG_DEBUG;
2305
2306 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
2307 (struct sockaddr *) &from, &fromlen);
2308 if (res < 0) {
2309 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
2310 strerror(errno));
2311 return;
2312 }
2313 buf[res] = '\0';
2314 if (os_strcmp(buf, "PING") == 0)
2315 level = MSG_EXCESSIVE;
2316 wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
2317
2318 reply = os_malloc(reply_size);
2319 if (reply == NULL) {
2320 if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
2321 fromlen) < 0) {
2322 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2323 strerror(errno));
2324 }
2325 return;
2326 }
2327
2328 reply_len = hostapd_ctrl_iface_receive_process(hapd, buf,
2329 reply, reply_size,
2330 &from, fromlen);
2331
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002332 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
2333 fromlen) < 0) {
2334 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2335 strerror(errno));
2336 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002337 os_free(reply);
2338}
2339
2340
2341static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
2342{
2343 char *buf;
2344 size_t len;
2345
2346 if (hapd->conf->ctrl_interface == NULL)
2347 return NULL;
2348
2349 len = os_strlen(hapd->conf->ctrl_interface) +
2350 os_strlen(hapd->conf->iface) + 2;
2351 buf = os_malloc(len);
2352 if (buf == NULL)
2353 return NULL;
2354
2355 os_snprintf(buf, len, "%s/%s",
2356 hapd->conf->ctrl_interface, hapd->conf->iface);
2357 buf[len - 1] = '\0';
2358 return buf;
2359}
2360
2361
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07002362static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
2363 enum wpa_msg_type type,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002364 const char *txt, size_t len)
2365{
2366 struct hostapd_data *hapd = ctx;
2367 if (hapd == NULL)
2368 return;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02002369 hostapd_ctrl_iface_send(hapd, level, type, txt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002370}
2371
2372
2373int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
2374{
2375 struct sockaddr_un addr;
2376 int s = -1;
2377 char *fname = NULL;
2378
Dmitry Shmidt04949592012-07-19 12:16:46 -07002379 if (hapd->ctrl_sock > -1) {
2380 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
2381 return 0;
2382 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002383
2384 if (hapd->conf->ctrl_interface == NULL)
2385 return 0;
2386
2387 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2388 if (errno == EEXIST) {
2389 wpa_printf(MSG_DEBUG, "Using existing control "
2390 "interface directory.");
2391 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002392 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
2393 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002394 goto fail;
2395 }
2396 }
2397
2398 if (hapd->conf->ctrl_interface_gid_set &&
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002399 chown(hapd->conf->ctrl_interface, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002400 hapd->conf->ctrl_interface_gid) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002401 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2402 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002403 return -1;
2404 }
2405
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002406 if (!hapd->conf->ctrl_interface_gid_set &&
2407 hapd->iface->interfaces->ctrl_iface_group &&
2408 chown(hapd->conf->ctrl_interface, -1,
2409 hapd->iface->interfaces->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002410 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2411 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002412 return -1;
2413 }
2414
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002415#ifdef ANDROID
2416 /*
2417 * Android is using umask 0077 which would leave the control interface
2418 * directory without group access. This breaks things since Wi-Fi
2419 * framework assumes that this directory can be accessed by other
2420 * applications in the wifi group. Fix this by adding group access even
2421 * if umask value would prevent this.
2422 */
2423 if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2424 wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
2425 strerror(errno));
2426 /* Try to continue anyway */
2427 }
2428#endif /* ANDROID */
2429
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002430 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
2431 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
2432 goto fail;
2433
2434 s = socket(PF_UNIX, SOCK_DGRAM, 0);
2435 if (s < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002436 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002437 goto fail;
2438 }
2439
2440 os_memset(&addr, 0, sizeof(addr));
2441#ifdef __FreeBSD__
2442 addr.sun_len = sizeof(addr);
2443#endif /* __FreeBSD__ */
2444 addr.sun_family = AF_UNIX;
2445 fname = hostapd_ctrl_iface_path(hapd);
2446 if (fname == NULL)
2447 goto fail;
2448 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
2449 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2450 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
2451 strerror(errno));
2452 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2453 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
2454 " allow connections - assuming it was left"
2455 "over from forced program termination");
2456 if (unlink(fname) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002457 wpa_printf(MSG_ERROR,
2458 "Could not unlink existing ctrl_iface socket '%s': %s",
2459 fname, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002460 goto fail;
2461 }
2462 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
2463 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002464 wpa_printf(MSG_ERROR,
2465 "hostapd-ctrl-iface: bind(PF_UNIX): %s",
2466 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002467 goto fail;
2468 }
2469 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
2470 "ctrl_iface socket '%s'", fname);
2471 } else {
2472 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
2473 "be in use - cannot override it");
2474 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
2475 "not used anymore", fname);
2476 os_free(fname);
2477 fname = NULL;
2478 goto fail;
2479 }
2480 }
2481
2482 if (hapd->conf->ctrl_interface_gid_set &&
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002483 chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002484 wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2485 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002486 goto fail;
2487 }
2488
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002489 if (!hapd->conf->ctrl_interface_gid_set &&
2490 hapd->iface->interfaces->ctrl_iface_group &&
2491 chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002492 wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2493 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002494 goto fail;
2495 }
2496
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002497 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002498 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
2499 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002500 goto fail;
2501 }
2502 os_free(fname);
2503
2504 hapd->ctrl_sock = s;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002505 if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
2506 NULL) < 0) {
2507 hostapd_ctrl_iface_deinit(hapd);
2508 return -1;
2509 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002510 hapd->msg_ctx = hapd;
2511 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
2512
2513 return 0;
2514
2515fail:
2516 if (s >= 0)
2517 close(s);
2518 if (fname) {
2519 unlink(fname);
2520 os_free(fname);
2521 }
2522 return -1;
2523}
2524
2525
2526void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
2527{
2528 struct wpa_ctrl_dst *dst, *prev;
2529
2530 if (hapd->ctrl_sock > -1) {
2531 char *fname;
2532 eloop_unregister_read_sock(hapd->ctrl_sock);
2533 close(hapd->ctrl_sock);
2534 hapd->ctrl_sock = -1;
2535 fname = hostapd_ctrl_iface_path(hapd);
2536 if (fname)
2537 unlink(fname);
2538 os_free(fname);
2539
2540 if (hapd->conf->ctrl_interface &&
2541 rmdir(hapd->conf->ctrl_interface) < 0) {
2542 if (errno == ENOTEMPTY) {
2543 wpa_printf(MSG_DEBUG, "Control interface "
2544 "directory not empty - leaving it "
2545 "behind");
2546 } else {
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002547 wpa_printf(MSG_ERROR,
2548 "rmdir[ctrl_interface=%s]: %s",
2549 hapd->conf->ctrl_interface,
2550 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002551 }
2552 }
2553 }
2554
2555 dst = hapd->ctrl_dst;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002556 hapd->ctrl_dst = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002557 while (dst) {
2558 prev = dst;
2559 dst = dst->next;
2560 os_free(prev);
2561 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002562
2563#ifdef CONFIG_TESTING_OPTIONS
2564 l2_packet_deinit(hapd->l2_test);
2565 hapd->l2_test = NULL;
2566#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002567}
2568
2569
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002570static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
2571 char *buf)
2572{
2573 if (hostapd_add_iface(interfaces, buf) < 0) {
2574 wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
2575 return -1;
2576 }
2577 return 0;
2578}
2579
2580
2581static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
2582 char *buf)
2583{
2584 if (hostapd_remove_iface(interfaces, buf) < 0) {
2585 wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
2586 return -1;
2587 }
2588 return 0;
2589}
2590
2591
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02002592static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
2593 struct sockaddr_un *from,
2594 socklen_t fromlen)
2595{
2596 struct wpa_ctrl_dst *dst;
2597
2598 dst = os_zalloc(sizeof(*dst));
2599 if (dst == NULL)
2600 return -1;
2601 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
2602 dst->addrlen = fromlen;
2603 dst->debug_level = MSG_INFO;
2604 dst->next = interfaces->global_ctrl_dst;
2605 interfaces->global_ctrl_dst = dst;
2606 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)",
2607 from->sun_path,
2608 fromlen - offsetof(struct sockaddr_un, sun_path));
2609 return 0;
2610}
2611
2612
2613static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
2614 struct sockaddr_un *from,
2615 socklen_t fromlen)
2616{
2617 struct wpa_ctrl_dst *dst, *prev = NULL;
2618
2619 dst = interfaces->global_ctrl_dst;
2620 while (dst) {
2621 if (fromlen == dst->addrlen &&
2622 os_memcmp(from->sun_path, dst->addr.sun_path,
2623 fromlen - offsetof(struct sockaddr_un, sun_path))
2624 == 0) {
2625 wpa_hexdump(MSG_DEBUG,
2626 "CTRL_IFACE monitor detached (global)",
2627 from->sun_path,
2628 fromlen -
2629 offsetof(struct sockaddr_un, sun_path));
2630 if (prev == NULL)
2631 interfaces->global_ctrl_dst = dst->next;
2632 else
2633 prev->next = dst->next;
2634 os_free(dst);
2635 return 0;
2636 }
2637 prev = dst;
2638 dst = dst->next;
2639 }
2640 return -1;
2641}
2642
2643
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002644static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
2645{
2646#ifdef CONFIG_WPS_TESTING
2647 wps_version_number = 0x20;
2648 wps_testing_dummy_cred = 0;
2649 wps_corrupt_pkhash = 0;
2650#endif /* CONFIG_WPS_TESTING */
2651}
2652
2653
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002654#ifdef CONFIG_FST
2655
2656static int
2657hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
2658 const char *cmd)
2659{
2660 char ifname[IFNAMSIZ + 1];
2661 struct fst_iface_cfg cfg;
2662 struct hostapd_data *hapd;
2663 struct fst_wpa_obj iface_obj;
2664
2665 if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
2666 hapd = hostapd_get_iface(interfaces, ifname);
2667 if (hapd) {
2668 if (hapd->iface->fst) {
2669 wpa_printf(MSG_INFO, "FST: Already attached");
2670 return -1;
2671 }
2672 fst_hostapd_fill_iface_obj(hapd, &iface_obj);
2673 hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
2674 &iface_obj, &cfg);
2675 if (hapd->iface->fst)
2676 return 0;
2677 }
2678 }
2679
2680 return -EINVAL;
2681}
2682
2683
2684static int
2685hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
2686 const char *cmd)
2687{
2688 char ifname[IFNAMSIZ + 1];
2689 struct hostapd_data * hapd;
2690
2691 if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
2692 hapd = hostapd_get_iface(interfaces, ifname);
2693 if (hapd) {
2694 if (!fst_iface_detach(ifname)) {
2695 hapd->iface->fst = NULL;
2696 hapd->iface->fst_ies = NULL;
2697 return 0;
2698 }
2699 }
2700 }
2701
2702 return -EINVAL;
2703}
2704
2705#endif /* CONFIG_FST */
2706
2707
2708static struct hostapd_data *
2709hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
2710 const char *ifname)
2711{
2712 size_t i, j;
2713
2714 for (i = 0; i < interfaces->count; i++) {
2715 struct hostapd_iface *iface = interfaces->iface[i];
2716
2717 for (j = 0; j < iface->num_bss; j++) {
2718 struct hostapd_data *hapd;
2719
2720 hapd = iface->bss[j];
2721 if (os_strcmp(ifname, hapd->conf->iface) == 0)
2722 return hapd;
2723 }
2724 }
2725
2726 return NULL;
2727}
2728
2729
2730static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
2731 struct hostapd_data *dst_hapd,
2732 const char *param)
2733{
2734 int res;
2735 char *value;
2736
2737 value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
2738 if (!value) {
2739 wpa_printf(MSG_ERROR,
2740 "DUP: cannot allocate buffer to stringify %s",
2741 param);
2742 goto error_return;
2743 }
2744
2745 if (os_strcmp(param, "wpa") == 0) {
2746 os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
2747 src_hapd->conf->wpa);
2748 } else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
2749 src_hapd->conf->wpa_key_mgmt) {
2750 res = hostapd_ctrl_iface_get_key_mgmt(
2751 src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
2752 if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
2753 goto error_stringify;
2754 } else if (os_strcmp(param, "wpa_pairwise") == 0 &&
2755 src_hapd->conf->wpa_pairwise) {
2756 res = wpa_write_ciphers(value,
2757 value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
2758 src_hapd->conf->wpa_pairwise, " ");
2759 if (res < 0)
2760 goto error_stringify;
2761 } else if (os_strcmp(param, "rsn_pairwise") == 0 &&
2762 src_hapd->conf->rsn_pairwise) {
2763 res = wpa_write_ciphers(value,
2764 value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
2765 src_hapd->conf->rsn_pairwise, " ");
2766 if (res < 0)
2767 goto error_stringify;
2768 } else if (os_strcmp(param, "wpa_passphrase") == 0 &&
2769 src_hapd->conf->ssid.wpa_passphrase) {
2770 os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
2771 src_hapd->conf->ssid.wpa_passphrase);
2772 } else if (os_strcmp(param, "wpa_psk") == 0 &&
2773 src_hapd->conf->ssid.wpa_psk_set) {
2774 wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
2775 src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
2776 } else {
2777 wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
2778 goto error_return;
2779 }
2780
2781 res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
2782 os_free(value);
2783 return res;
2784
2785error_stringify:
2786 wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
2787error_return:
2788 os_free(value);
2789 return -1;
2790}
2791
2792
2793static int
2794hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
2795 char *cmd)
2796{
2797 char *p_start = cmd, *p_end;
2798 struct hostapd_data *src_hapd, *dst_hapd;
2799
2800 /* cmd: "<src ifname> <dst ifname> <variable name> */
2801
2802 p_end = os_strchr(p_start, ' ');
2803 if (!p_end) {
2804 wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
2805 cmd);
2806 return -1;
2807 }
2808
2809 *p_end = '\0';
2810 src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
2811 if (!src_hapd) {
2812 wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
2813 p_start);
2814 return -1;
2815 }
2816
2817 p_start = p_end + 1;
2818 p_end = os_strchr(p_start, ' ');
2819 if (!p_end) {
2820 wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
2821 cmd);
2822 return -1;
2823 }
2824
2825 *p_end = '\0';
2826 dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
2827 if (!dst_hapd) {
2828 wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
2829 p_start);
2830 return -1;
2831 }
2832
2833 p_start = p_end + 1;
2834 return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
2835}
2836
2837
2838static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
2839 const char *ifname,
2840 char *buf, char *reply,
2841 int reply_size,
2842 struct sockaddr_un *from,
2843 socklen_t fromlen)
2844{
2845 struct hostapd_data *hapd;
2846
2847 hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
2848 if (hapd == NULL) {
2849 int res;
2850
2851 res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
2852 if (os_snprintf_error(reply_size, res))
2853 return -1;
2854 return res;
2855 }
2856
2857 return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
2858 from, fromlen);
2859}
2860
2861
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002862static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
2863 void *sock_ctx)
2864{
2865 void *interfaces = eloop_ctx;
2866 char buf[256];
2867 int res;
2868 struct sockaddr_un from;
2869 socklen_t fromlen = sizeof(from);
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02002870 char *reply;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002871 int reply_len;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02002872 const int reply_size = 4096;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002873
2874 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
2875 (struct sockaddr *) &from, &fromlen);
2876 if (res < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002877 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
2878 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002879 return;
2880 }
2881 buf[res] = '\0';
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002882 wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002883
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02002884 reply = os_malloc(reply_size);
2885 if (reply == NULL) {
2886 if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
2887 fromlen) < 0) {
2888 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2889 strerror(errno));
2890 }
2891 return;
2892 }
2893
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002894 os_memcpy(reply, "OK\n", 3);
2895 reply_len = 3;
2896
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002897 if (os_strncmp(buf, "IFNAME=", 7) == 0) {
2898 char *pos = os_strchr(buf + 7, ' ');
2899
2900 if (pos) {
2901 *pos++ = '\0';
2902 reply_len = hostapd_global_ctrl_iface_ifname(
2903 interfaces, buf + 7, pos, reply, reply_size,
2904 &from, fromlen);
2905 goto send_reply;
2906 }
2907 }
2908
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002909 if (os_strcmp(buf, "PING") == 0) {
2910 os_memcpy(reply, "PONG\n", 5);
2911 reply_len = 5;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002912 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
2913 if (wpa_debug_reopen_file() < 0)
2914 reply_len = -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002915 } else if (os_strcmp(buf, "FLUSH") == 0) {
2916 hostapd_ctrl_iface_flush(interfaces);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002917 } else if (os_strncmp(buf, "ADD ", 4) == 0) {
2918 if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
2919 reply_len = -1;
2920 } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
2921 if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
2922 reply_len = -1;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02002923 } else if (os_strcmp(buf, "ATTACH") == 0) {
2924 if (hostapd_global_ctrl_iface_attach(interfaces, &from,
2925 fromlen))
2926 reply_len = -1;
2927 } else if (os_strcmp(buf, "DETACH") == 0) {
2928 if (hostapd_global_ctrl_iface_detach(interfaces, &from,
2929 fromlen))
2930 reply_len = -1;
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -08002931#ifdef CONFIG_MODULE_TESTS
2932 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
2933 int hapd_module_tests(void);
2934 if (hapd_module_tests() < 0)
2935 reply_len = -1;
2936#endif /* CONFIG_MODULE_TESTS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002937#ifdef CONFIG_FST
2938 } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
2939 if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
2940 reply_len = os_snprintf(reply, reply_size, "OK\n");
2941 else
2942 reply_len = -1;
2943 } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
2944 if (!hostapd_global_ctrl_iface_fst_detach(interfaces, buf + 11))
2945 reply_len = os_snprintf(reply, reply_size, "OK\n");
2946 else
2947 reply_len = -1;
2948 } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
2949 reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
2950#endif /* CONFIG_FST */
2951 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
2952 if (!hostapd_global_ctrl_iface_dup_network(interfaces,
2953 buf + 12))
2954 reply_len = os_snprintf(reply, reply_size, "OK\n");
2955 else
2956 reply_len = -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002957 } else {
2958 wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
2959 "ignored");
2960 reply_len = -1;
2961 }
2962
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002963send_reply:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002964 if (reply_len < 0) {
2965 os_memcpy(reply, "FAIL\n", 5);
2966 reply_len = 5;
2967 }
2968
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002969 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
2970 fromlen) < 0) {
2971 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2972 strerror(errno));
2973 }
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02002974 os_free(reply);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002975}
2976
2977
2978static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
2979{
2980 char *buf;
2981 size_t len;
2982
2983 if (interface->global_iface_path == NULL)
2984 return NULL;
2985
2986 len = os_strlen(interface->global_iface_path) +
2987 os_strlen(interface->global_iface_name) + 2;
2988 buf = os_malloc(len);
2989 if (buf == NULL)
2990 return NULL;
2991
2992 os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
2993 interface->global_iface_name);
2994 buf[len - 1] = '\0';
2995 return buf;
2996}
2997
2998
2999int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
3000{
3001 struct sockaddr_un addr;
3002 int s = -1;
3003 char *fname = NULL;
3004
3005 if (interface->global_iface_path == NULL) {
3006 wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
3007 return 0;
3008 }
3009
3010 if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
3011 if (errno == EEXIST) {
3012 wpa_printf(MSG_DEBUG, "Using existing control "
3013 "interface directory.");
3014 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003015 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
3016 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003017 goto fail;
3018 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07003019 } else if (interface->ctrl_iface_group &&
3020 chown(interface->global_iface_path, -1,
3021 interface->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003022 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
3023 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07003024 goto fail;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003025 }
3026
3027 if (os_strlen(interface->global_iface_path) + 1 +
3028 os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
3029 goto fail;
3030
3031 s = socket(PF_UNIX, SOCK_DGRAM, 0);
3032 if (s < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003033 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003034 goto fail;
3035 }
3036
3037 os_memset(&addr, 0, sizeof(addr));
3038#ifdef __FreeBSD__
3039 addr.sun_len = sizeof(addr);
3040#endif /* __FreeBSD__ */
3041 addr.sun_family = AF_UNIX;
3042 fname = hostapd_global_ctrl_iface_path(interface);
3043 if (fname == NULL)
3044 goto fail;
3045 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
3046 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3047 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
3048 strerror(errno));
3049 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3050 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
3051 " allow connections - assuming it was left"
3052 "over from forced program termination");
3053 if (unlink(fname) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003054 wpa_printf(MSG_ERROR,
3055 "Could not unlink existing ctrl_iface socket '%s': %s",
3056 fname, strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003057 goto fail;
3058 }
3059 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
3060 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003061 wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
3062 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003063 goto fail;
3064 }
3065 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
3066 "ctrl_iface socket '%s'", fname);
3067 } else {
3068 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
3069 "be in use - cannot override it");
3070 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
3071 "not used anymore", fname);
3072 os_free(fname);
3073 fname = NULL;
3074 goto fail;
3075 }
3076 }
3077
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07003078 if (interface->ctrl_iface_group &&
3079 chown(fname, -1, interface->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003080 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
3081 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07003082 goto fail;
3083 }
3084
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003085 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003086 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
3087 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003088 goto fail;
3089 }
3090 os_free(fname);
3091
3092 interface->global_ctrl_sock = s;
3093 eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
3094 interface, NULL);
3095
3096 return 0;
3097
3098fail:
3099 if (s >= 0)
3100 close(s);
3101 if (fname) {
3102 unlink(fname);
3103 os_free(fname);
3104 }
3105 return -1;
3106}
3107
3108
3109void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
3110{
3111 char *fname = NULL;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02003112 struct wpa_ctrl_dst *dst, *prev;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003113
3114 if (interfaces->global_ctrl_sock > -1) {
3115 eloop_unregister_read_sock(interfaces->global_ctrl_sock);
3116 close(interfaces->global_ctrl_sock);
3117 interfaces->global_ctrl_sock = -1;
3118 fname = hostapd_global_ctrl_iface_path(interfaces);
3119 if (fname) {
3120 unlink(fname);
3121 os_free(fname);
3122 }
3123
3124 if (interfaces->global_iface_path &&
3125 rmdir(interfaces->global_iface_path) < 0) {
3126 if (errno == ENOTEMPTY) {
3127 wpa_printf(MSG_DEBUG, "Control interface "
3128 "directory not empty - leaving it "
3129 "behind");
3130 } else {
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07003131 wpa_printf(MSG_ERROR,
3132 "rmdir[ctrl_interface=%s]: %s",
3133 interfaces->global_iface_path,
3134 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003135 }
3136 }
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02003137 }
3138
3139 os_free(interfaces->global_iface_path);
3140 interfaces->global_iface_path = NULL;
3141
3142 dst = interfaces->global_ctrl_dst;
3143 interfaces->global_ctrl_dst = NULL;
3144 while (dst) {
3145 prev = dst;
3146 dst = dst->next;
3147 os_free(prev);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003148 }
3149}
3150
3151
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003152static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02003153 enum wpa_msg_type type,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003154 const char *buf, size_t len)
3155{
3156 struct wpa_ctrl_dst *dst, *next;
3157 struct msghdr msg;
3158 int idx;
3159 struct iovec io[2];
3160 char levelstr[10];
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02003161 int s;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003162
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02003163 if (type != WPA_MSG_ONLY_GLOBAL) {
3164 s = hapd->ctrl_sock;
3165 dst = hapd->ctrl_dst;
3166 } else {
3167 s = hapd->iface->interfaces->global_ctrl_sock;
3168 dst = hapd->iface->interfaces->global_ctrl_dst;
3169 }
3170
3171 if (s < 0 || dst == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003172 return;
3173
3174 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
3175 io[0].iov_base = levelstr;
3176 io[0].iov_len = os_strlen(levelstr);
3177 io[1].iov_base = (char *) buf;
3178 io[1].iov_len = len;
3179 os_memset(&msg, 0, sizeof(msg));
3180 msg.msg_iov = io;
3181 msg.msg_iovlen = 2;
3182
3183 idx = 0;
3184 while (dst) {
3185 next = dst->next;
3186 if (level >= dst->debug_level) {
3187 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
3188 (u8 *) dst->addr.sun_path, dst->addrlen -
3189 offsetof(struct sockaddr_un, sun_path));
3190 msg.msg_name = &dst->addr;
3191 msg.msg_namelen = dst->addrlen;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02003192 if (sendmsg(s, &msg, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003193 int _errno = errno;
3194 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
3195 "%d - %s",
3196 idx, errno, strerror(errno));
3197 dst->errors++;
3198 if (dst->errors > 10 || _errno == ENOENT) {
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02003199 if (type != WPA_MSG_ONLY_GLOBAL)
3200 hostapd_ctrl_iface_detach(
3201 hapd, &dst->addr,
3202 dst->addrlen);
3203 else
3204 hostapd_global_ctrl_iface_detach(
3205 hapd->iface->interfaces,
3206 &dst->addr,
3207 dst->addrlen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003208 }
3209 } else
3210 dst->errors = 0;
3211 }
3212 idx++;
3213 dst = next;
3214 }
3215}
3216
3217#endif /* CONFIG_NATIVE_WINDOWS */