blob: 54b17dc93b3aa1cf067e9913f8a7216cee0dc218 [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"
28#include "radius/radius_client.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080029#include "radius/radius_server.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080030#include "l2_packet/l2_packet.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070031#include "ap/hostapd.h"
32#include "ap/ap_config.h"
33#include "ap/ieee802_1x.h"
34#include "ap/wpa_auth.h"
35#include "ap/ieee802_11.h"
36#include "ap/sta_info.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070037#include "ap/wps_hostapd.h"
38#include "ap/ctrl_iface_ap.h"
39#include "ap/ap_drv_ops.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080040#include "ap/hs20.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080041#include "ap/wnm_ap.h"
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -070042#include "ap/wpa_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070043#include "wps/wps_defs.h"
44#include "wps/wps.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070045#include "config_file.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070046#include "ctrl_iface.h"
47
48
49struct wpa_ctrl_dst {
50 struct wpa_ctrl_dst *next;
51 struct sockaddr_un addr;
52 socklen_t addrlen;
53 int debug_level;
54 int errors;
55};
56
57
58static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
59 const char *buf, size_t len);
60
61
62static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
63 struct sockaddr_un *from,
64 socklen_t fromlen)
65{
66 struct wpa_ctrl_dst *dst;
67
68 dst = os_zalloc(sizeof(*dst));
69 if (dst == NULL)
70 return -1;
71 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
72 dst->addrlen = fromlen;
73 dst->debug_level = MSG_INFO;
74 dst->next = hapd->ctrl_dst;
75 hapd->ctrl_dst = dst;
76 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
77 (u8 *) from->sun_path,
78 fromlen - offsetof(struct sockaddr_un, sun_path));
79 return 0;
80}
81
82
83static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
84 struct sockaddr_un *from,
85 socklen_t fromlen)
86{
87 struct wpa_ctrl_dst *dst, *prev = NULL;
88
89 dst = hapd->ctrl_dst;
90 while (dst) {
91 if (fromlen == dst->addrlen &&
92 os_memcmp(from->sun_path, dst->addr.sun_path,
93 fromlen - offsetof(struct sockaddr_un, sun_path))
94 == 0) {
Dmitry Shmidt54605472013-11-08 11:10:19 -080095 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
96 (u8 *) from->sun_path,
97 fromlen -
98 offsetof(struct sockaddr_un, sun_path));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070099 if (prev == NULL)
100 hapd->ctrl_dst = dst->next;
101 else
102 prev->next = dst->next;
103 os_free(dst);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700104 return 0;
105 }
106 prev = dst;
107 dst = dst->next;
108 }
109 return -1;
110}
111
112
113static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
114 struct sockaddr_un *from,
115 socklen_t fromlen,
116 char *level)
117{
118 struct wpa_ctrl_dst *dst;
119
120 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
121
122 dst = hapd->ctrl_dst;
123 while (dst) {
124 if (fromlen == dst->addrlen &&
125 os_memcmp(from->sun_path, dst->addr.sun_path,
126 fromlen - offsetof(struct sockaddr_un, sun_path))
127 == 0) {
128 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
129 "level", (u8 *) from->sun_path, fromlen -
130 offsetof(struct sockaddr_un, sun_path));
131 dst->debug_level = atoi(level);
132 return 0;
133 }
134 dst = dst->next;
135 }
136
137 return -1;
138}
139
140
141static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
142 const char *txtaddr)
143{
144 u8 addr[ETH_ALEN];
145 struct sta_info *sta;
146
147 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
148
149 if (hwaddr_aton(txtaddr, addr))
150 return -1;
151
152 sta = ap_get_sta(hapd, addr);
153 if (sta)
154 return 0;
155
156 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
157 "notification", MAC2STR(addr));
158 sta = ap_sta_add(hapd, addr);
159 if (sta == NULL)
160 return -1;
161
162 hostapd_new_assoc_sta(hapd, sta, 0);
163 return 0;
164}
165
166
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700167#ifdef CONFIG_IEEE80211W
168#ifdef NEED_AP_MLME
169static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
170 const char *txtaddr)
171{
172 u8 addr[ETH_ALEN];
173 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
174
175 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
176
177 if (hwaddr_aton(txtaddr, addr) ||
178 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
179 return -1;
180
181 ieee802_11_send_sa_query_req(hapd, addr, trans_id);
182
183 return 0;
184}
185#endif /* NEED_AP_MLME */
186#endif /* CONFIG_IEEE80211W */
187
188
189#ifdef CONFIG_WPS
190static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
191{
192 char *pin = os_strchr(txt, ' ');
193 char *timeout_txt;
194 int timeout;
195 u8 addr_buf[ETH_ALEN], *addr = NULL;
196 char *pos;
197
198 if (pin == NULL)
199 return -1;
200 *pin++ = '\0';
201
202 timeout_txt = os_strchr(pin, ' ');
203 if (timeout_txt) {
204 *timeout_txt++ = '\0';
205 timeout = atoi(timeout_txt);
206 pos = os_strchr(timeout_txt, ' ');
207 if (pos) {
208 *pos++ = '\0';
209 if (hwaddr_aton(pos, addr_buf) == 0)
210 addr = addr_buf;
211 }
212 } else
213 timeout = 0;
214
215 return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
216}
217
218
219static int hostapd_ctrl_iface_wps_check_pin(
220 struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
221{
222 char pin[9];
223 size_t len;
224 char *pos;
225 int ret;
226
227 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
228 (u8 *) cmd, os_strlen(cmd));
229 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
230 if (*pos < '0' || *pos > '9')
231 continue;
232 pin[len++] = *pos;
233 if (len == 9) {
234 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
235 return -1;
236 }
237 }
238 if (len != 4 && len != 8) {
239 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
240 return -1;
241 }
242 pin[len] = '\0';
243
244 if (len == 8) {
245 unsigned int pin_val;
246 pin_val = atoi(pin);
247 if (!wps_pin_valid(pin_val)) {
248 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
249 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800250 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700251 return -1;
252 return ret;
253 }
254 }
255
256 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800257 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700258 return -1;
259
260 return ret;
261}
262
263
Dmitry Shmidt04949592012-07-19 12:16:46 -0700264#ifdef CONFIG_WPS_NFC
265static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
266 char *pos)
267{
268 size_t len;
269 struct wpabuf *buf;
270 int ret;
271
272 len = os_strlen(pos);
273 if (len & 0x01)
274 return -1;
275 len /= 2;
276
277 buf = wpabuf_alloc(len);
278 if (buf == NULL)
279 return -1;
280 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
281 wpabuf_free(buf);
282 return -1;
283 }
284
285 ret = hostapd_wps_nfc_tag_read(hapd, buf);
286 wpabuf_free(buf);
287
288 return ret;
289}
290
291
292static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
293 char *cmd, char *reply,
294 size_t max_len)
295{
296 int ndef;
297 struct wpabuf *buf;
298 int res;
299
300 if (os_strcmp(cmd, "WPS") == 0)
301 ndef = 0;
302 else if (os_strcmp(cmd, "NDEF") == 0)
303 ndef = 1;
304 else
305 return -1;
306
307 buf = hostapd_wps_nfc_config_token(hapd, ndef);
308 if (buf == NULL)
309 return -1;
310
311 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
312 wpabuf_len(buf));
313 reply[res++] = '\n';
314 reply[res] = '\0';
315
316 wpabuf_free(buf);
317
318 return res;
319}
320
321
322static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
323 char *reply, size_t max_len,
324 int ndef)
325{
326 struct wpabuf *buf;
327 int res;
328
329 buf = hostapd_wps_nfc_token_gen(hapd, ndef);
330 if (buf == NULL)
331 return -1;
332
333 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
334 wpabuf_len(buf));
335 reply[res++] = '\n';
336 reply[res] = '\0';
337
338 wpabuf_free(buf);
339
340 return res;
341}
342
343
344static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
345 char *cmd, char *reply,
346 size_t max_len)
347{
348 if (os_strcmp(cmd, "WPS") == 0)
349 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
350 max_len, 0);
351
352 if (os_strcmp(cmd, "NDEF") == 0)
353 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
354 max_len, 1);
355
356 if (os_strcmp(cmd, "enable") == 0)
357 return hostapd_wps_nfc_token_enable(hapd);
358
359 if (os_strcmp(cmd, "disable") == 0) {
360 hostapd_wps_nfc_token_disable(hapd);
361 return 0;
362 }
363
364 return -1;
365}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800366
367
368static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
369 char *cmd, char *reply,
370 size_t max_len)
371{
372 struct wpabuf *buf;
373 int res;
374 char *pos;
375 int ndef;
376
377 pos = os_strchr(cmd, ' ');
378 if (pos == NULL)
379 return -1;
380 *pos++ = '\0';
381
382 if (os_strcmp(cmd, "WPS") == 0)
383 ndef = 0;
384 else if (os_strcmp(cmd, "NDEF") == 0)
385 ndef = 1;
386 else
387 return -1;
388
389 if (os_strcmp(pos, "WPS-CR") == 0)
390 buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
391 else
392 buf = NULL;
393 if (buf == NULL)
394 return -1;
395
396 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
397 wpabuf_len(buf));
398 reply[res++] = '\n';
399 reply[res] = '\0';
400
401 wpabuf_free(buf);
402
403 return res;
404}
405
406
407static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
408 char *cmd)
409{
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800410 size_t len;
411 struct wpabuf *req, *sel;
412 int ret;
413 char *pos, *role, *type, *pos2;
414
415 role = cmd;
416 pos = os_strchr(role, ' ');
417 if (pos == NULL)
418 return -1;
419 *pos++ = '\0';
420
421 type = pos;
422 pos = os_strchr(type, ' ');
423 if (pos == NULL)
424 return -1;
425 *pos++ = '\0';
426
427 pos2 = os_strchr(pos, ' ');
428 if (pos2 == NULL)
429 return -1;
430 *pos2++ = '\0';
431
432 len = os_strlen(pos);
433 if (len & 0x01)
434 return -1;
435 len /= 2;
436
437 req = wpabuf_alloc(len);
438 if (req == NULL)
439 return -1;
440 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
441 wpabuf_free(req);
442 return -1;
443 }
444
445 len = os_strlen(pos2);
446 if (len & 0x01) {
447 wpabuf_free(req);
448 return -1;
449 }
450 len /= 2;
451
452 sel = wpabuf_alloc(len);
453 if (sel == NULL) {
454 wpabuf_free(req);
455 return -1;
456 }
457 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
458 wpabuf_free(req);
459 wpabuf_free(sel);
460 return -1;
461 }
462
463 if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
464 ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
465 } else {
466 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
467 "reported: role=%s type=%s", role, type);
468 ret = -1;
469 }
470 wpabuf_free(req);
471 wpabuf_free(sel);
472
473 return ret;
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800474}
475
Dmitry Shmidt04949592012-07-19 12:16:46 -0700476#endif /* CONFIG_WPS_NFC */
477
478
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700479static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
480 char *buf, size_t buflen)
481{
482 int timeout = 300;
483 char *pos;
484 const char *pin_txt;
485
486 pos = os_strchr(txt, ' ');
487 if (pos)
488 *pos++ = '\0';
489
490 if (os_strcmp(txt, "disable") == 0) {
491 hostapd_wps_ap_pin_disable(hapd);
492 return os_snprintf(buf, buflen, "OK\n");
493 }
494
495 if (os_strcmp(txt, "random") == 0) {
496 if (pos)
497 timeout = atoi(pos);
498 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
499 if (pin_txt == NULL)
500 return -1;
501 return os_snprintf(buf, buflen, "%s", pin_txt);
502 }
503
504 if (os_strcmp(txt, "get") == 0) {
505 pin_txt = hostapd_wps_ap_pin_get(hapd);
506 if (pin_txt == NULL)
507 return -1;
508 return os_snprintf(buf, buflen, "%s", pin_txt);
509 }
510
511 if (os_strcmp(txt, "set") == 0) {
512 char *pin;
513 if (pos == NULL)
514 return -1;
515 pin = pos;
516 pos = os_strchr(pos, ' ');
517 if (pos) {
518 *pos++ = '\0';
519 timeout = atoi(pos);
520 }
521 if (os_strlen(pin) > buflen)
522 return -1;
523 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
524 return -1;
525 return os_snprintf(buf, buflen, "%s", pin);
526 }
527
528 return -1;
529}
530
531
532static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
533{
534 char *pos;
535 char *ssid, *auth, *encr = NULL, *key = NULL;
536
537 ssid = txt;
538 pos = os_strchr(txt, ' ');
539 if (!pos)
540 return -1;
541 *pos++ = '\0';
542
543 auth = pos;
544 pos = os_strchr(pos, ' ');
545 if (pos) {
546 *pos++ = '\0';
547 encr = pos;
548 pos = os_strchr(pos, ' ');
549 if (pos) {
550 *pos++ = '\0';
551 key = pos;
552 }
553 }
554
555 return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
556}
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700557
558
559static const char * pbc_status_str(enum pbc_status status)
560{
561 switch (status) {
562 case WPS_PBC_STATUS_DISABLE:
563 return "Disabled";
564 case WPS_PBC_STATUS_ACTIVE:
565 return "Active";
566 case WPS_PBC_STATUS_TIMEOUT:
567 return "Timed-out";
568 case WPS_PBC_STATUS_OVERLAP:
569 return "Overlap";
570 default:
571 return "Unknown";
572 }
573}
574
575
576static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
577 char *buf, size_t buflen)
578{
579 int ret;
580 char *pos, *end;
581
582 pos = buf;
583 end = buf + buflen;
584
585 ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
586 pbc_status_str(hapd->wps_stats.pbc_status));
587
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800588 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700589 return pos - buf;
590 pos += ret;
591
592 ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
593 (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
594 "Success":
595 (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
596 "Failed" : "None")));
597
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800598 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700599 return pos - buf;
600 pos += ret;
601
602 /* If status == Failure - Add possible Reasons */
603 if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
604 hapd->wps_stats.failure_reason > 0) {
605 ret = os_snprintf(pos, end - pos,
606 "Failure Reason: %s\n",
607 wps_ei_str(hapd->wps_stats.failure_reason));
608
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800609 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700610 return pos - buf;
611 pos += ret;
612 }
613
614 if (hapd->wps_stats.status) {
615 ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
616 MAC2STR(hapd->wps_stats.peer_addr));
617
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800618 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700619 return pos - buf;
620 pos += ret;
621 }
622
623 return pos - buf;
624}
625
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700626#endif /* CONFIG_WPS */
627
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800628#ifdef CONFIG_HS20
629
630static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
631 const char *cmd)
632{
633 u8 addr[ETH_ALEN];
634 const char *url;
635
636 if (hwaddr_aton(cmd, addr))
637 return -1;
638 url = cmd + 17;
639 if (*url == '\0') {
640 url = NULL;
641 } else {
642 if (*url != ' ')
643 return -1;
644 url++;
645 if (*url == '\0')
646 url = NULL;
647 }
648
649 return hs20_send_wnm_notification(hapd, addr, 1, url);
650}
651
652
653static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
654 const char *cmd)
655{
656 u8 addr[ETH_ALEN];
657 int code, reauth_delay, ret;
658 const char *pos;
659 size_t url_len;
660 struct wpabuf *req;
661
662 /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
663 if (hwaddr_aton(cmd, addr))
664 return -1;
665
666 pos = os_strchr(cmd, ' ');
667 if (pos == NULL)
668 return -1;
669 pos++;
670 code = atoi(pos);
671
672 pos = os_strchr(pos, ' ');
673 if (pos == NULL)
674 return -1;
675 pos++;
676 reauth_delay = atoi(pos);
677
678 url_len = 0;
679 pos = os_strchr(pos, ' ');
680 if (pos) {
681 pos++;
682 url_len = os_strlen(pos);
683 }
684
685 req = wpabuf_alloc(4 + url_len);
686 if (req == NULL)
687 return -1;
688 wpabuf_put_u8(req, code);
689 wpabuf_put_le16(req, reauth_delay);
690 wpabuf_put_u8(req, url_len);
691 if (pos)
692 wpabuf_put_data(req, pos, url_len);
693
694 wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
695 " to indicate imminent deauthentication (code=%d "
696 "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
697 ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
698 wpabuf_free(req);
699 return ret;
700}
701
702#endif /* CONFIG_HS20 */
703
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700704
Dmitry Shmidt051af732013-10-22 13:52:46 -0700705#ifdef CONFIG_INTERWORKING
706
707static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
708 const char *cmd)
709{
710 u8 qos_map_set[16 + 2 * 21], count = 0;
711 const char *pos = cmd;
712 int val, ret;
713
714 for (;;) {
715 if (count == sizeof(qos_map_set)) {
716 wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
717 return -1;
718 }
719
720 val = atoi(pos);
721 if (val < 0 || val > 255) {
722 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
723 return -1;
724 }
725
726 qos_map_set[count++] = val;
727 pos = os_strchr(pos, ',');
728 if (!pos)
729 break;
730 pos++;
731 }
732
733 if (count < 16 || count & 1) {
734 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
735 return -1;
736 }
737
738 ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
739 if (ret) {
740 wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
741 return -1;
742 }
743
744 os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
745 hapd->conf->qos_map_set_len = count;
746
747 return 0;
748}
749
750
751static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
752 const char *cmd)
753{
754 u8 addr[ETH_ALEN];
755 struct sta_info *sta;
756 struct wpabuf *buf;
757 u8 *qos_map_set = hapd->conf->qos_map_set;
758 u8 qos_map_set_len = hapd->conf->qos_map_set_len;
759 int ret;
760
761 if (!qos_map_set_len) {
762 wpa_printf(MSG_INFO, "QoS Map Set is not set");
763 return -1;
764 }
765
766 if (hwaddr_aton(cmd, addr))
767 return -1;
768
769 sta = ap_get_sta(hapd, addr);
770 if (sta == NULL) {
771 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
772 "for QoS Map Configuration message",
773 MAC2STR(addr));
774 return -1;
775 }
776
777 if (!sta->qos_map_enabled) {
778 wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
779 "support for QoS Map", MAC2STR(addr));
780 return -1;
781 }
782
783 buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
784 if (buf == NULL)
785 return -1;
786
787 wpabuf_put_u8(buf, WLAN_ACTION_QOS);
788 wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
789
790 /* QoS Map Set Element */
791 wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
792 wpabuf_put_u8(buf, qos_map_set_len);
793 wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
794
795 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
796 wpabuf_head(buf), wpabuf_len(buf));
797 wpabuf_free(buf);
798
799 return ret;
800}
801
802#endif /* CONFIG_INTERWORKING */
803
804
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800805#ifdef CONFIG_WNM
806
807static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
808 const char *cmd)
809{
810 u8 addr[ETH_ALEN];
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800811 int disassoc_timer;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800812 struct sta_info *sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800813
814 if (hwaddr_aton(cmd, addr))
815 return -1;
816 if (cmd[17] != ' ')
817 return -1;
818 disassoc_timer = atoi(cmd + 17);
819
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800820 sta = ap_get_sta(hapd, addr);
821 if (sta == NULL) {
822 wpa_printf(MSG_DEBUG, "Station " MACSTR
823 " not found for disassociation imminent message",
824 MAC2STR(addr));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800825 return -1;
826 }
827
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800828 return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800829}
830
831
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800832static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
833 const char *cmd)
834{
835 u8 addr[ETH_ALEN];
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700836 const char *url, *timerstr;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700837 int disassoc_timer;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800838 struct sta_info *sta;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800839
840 if (hwaddr_aton(cmd, addr))
841 return -1;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700842
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800843 sta = ap_get_sta(hapd, addr);
844 if (sta == NULL) {
845 wpa_printf(MSG_DEBUG, "Station " MACSTR
846 " not found for ESS disassociation imminent message",
847 MAC2STR(addr));
848 return -1;
849 }
850
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700851 timerstr = cmd + 17;
852 if (*timerstr != ' ')
853 return -1;
854 timerstr++;
855 disassoc_timer = atoi(timerstr);
856 if (disassoc_timer < 0 || disassoc_timer > 65535)
857 return -1;
858
859 url = os_strchr(timerstr, ' ');
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700860 if (url == NULL)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800861 return -1;
862 url++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800863
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800864 return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800865}
866
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800867
868static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
869 const char *cmd)
870{
871 u8 addr[ETH_ALEN];
872 const char *pos, *end;
873 int disassoc_timer = 0;
874 struct sta_info *sta;
875 u8 req_mode = 0, valid_int = 0x01;
876 u8 bss_term_dur[12];
877 char *url = NULL;
878 int ret;
879 u8 nei_rep[1000];
880 u8 *nei_pos = nei_rep;
881
882 if (hwaddr_aton(cmd, addr)) {
883 wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
884 return -1;
885 }
886
887 sta = ap_get_sta(hapd, addr);
888 if (sta == NULL) {
889 wpa_printf(MSG_DEBUG, "Station " MACSTR
890 " not found for BSS TM Request message",
891 MAC2STR(addr));
892 return -1;
893 }
894
895 pos = os_strstr(cmd, " disassoc_timer=");
896 if (pos) {
897 pos += 16;
898 disassoc_timer = atoi(pos);
899 if (disassoc_timer < 0 || disassoc_timer > 65535) {
900 wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
901 return -1;
902 }
903 }
904
905 pos = os_strstr(cmd, " valid_int=");
906 if (pos) {
907 pos += 11;
908 valid_int = atoi(pos);
909 }
910
911 pos = os_strstr(cmd, " bss_term=");
912 if (pos) {
913 pos += 10;
914 req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
915 /* TODO: TSF configurable/learnable */
916 bss_term_dur[0] = 4; /* Subelement ID */
917 bss_term_dur[1] = 10; /* Length */
918 os_memset(bss_term_dur, 2, 8);
919 end = os_strchr(pos, ',');
920 if (end == NULL) {
921 wpa_printf(MSG_DEBUG, "Invalid bss_term data");
922 return -1;
923 }
924 end++;
925 WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
926 }
927
928
929 /*
930 * BSS Transition Candidate List Entries - Neighbor Report elements
931 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
932 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
933 */
934 pos = cmd;
935 while (pos) {
936 u8 *nei_start;
937 long int val;
938 char *endptr, *tmp;
939
940 pos = os_strstr(pos, " neighbor=");
941 if (!pos)
942 break;
943 if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) {
944 wpa_printf(MSG_DEBUG,
945 "Not enough room for additional neighbor");
946 return -1;
947 }
948 pos += 10;
949
950 nei_start = nei_pos;
951 *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
952 nei_pos++; /* length to be filled in */
953
954 if (hwaddr_aton(pos, nei_pos)) {
955 wpa_printf(MSG_DEBUG, "Invalid BSSID");
956 return -1;
957 }
958 nei_pos += ETH_ALEN;
959 pos += 17;
960 if (*pos != ',') {
961 wpa_printf(MSG_DEBUG, "Missing BSSID Information");
962 return -1;
963 }
964 pos++;
965
966 val = strtol(pos, &endptr, 0);
967 WPA_PUT_LE32(nei_pos, val);
968 nei_pos += 4;
969 if (*endptr != ',') {
970 wpa_printf(MSG_DEBUG, "Missing Operating Class");
971 return -1;
972 }
973 pos = endptr + 1;
974
975 *nei_pos++ = atoi(pos); /* Operating Class */
976 pos = os_strchr(pos, ',');
977 if (pos == NULL) {
978 wpa_printf(MSG_DEBUG, "Missing Channel Number");
979 return -1;
980 }
981 pos++;
982
983 *nei_pos++ = atoi(pos); /* Channel Number */
984 pos = os_strchr(pos, ',');
985 if (pos == NULL) {
986 wpa_printf(MSG_DEBUG, "Missing PHY Type");
987 return -1;
988 }
989 pos++;
990
991 *nei_pos++ = atoi(pos); /* PHY Type */
992 end = os_strchr(pos, ' ');
993 tmp = os_strchr(pos, ',');
994 if (tmp && (!end || tmp < end)) {
995 /* Optional Subelements (hexdump) */
996 size_t len;
997
998 pos = tmp + 1;
999 end = os_strchr(pos, ' ');
1000 if (end)
1001 len = end - pos;
1002 else
1003 len = os_strlen(pos);
1004 if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) {
1005 wpa_printf(MSG_DEBUG,
1006 "Not enough room for neighbor subelements");
1007 return -1;
1008 }
1009 if (len & 0x01 ||
1010 hexstr2bin(pos, nei_pos, len / 2) < 0) {
1011 wpa_printf(MSG_DEBUG,
1012 "Invalid neighbor subelement info");
1013 return -1;
1014 }
1015 nei_pos += len / 2;
1016 pos = end;
1017 }
1018
1019 nei_start[1] = nei_pos - nei_start - 2;
1020 }
1021
1022 pos = os_strstr(cmd, " url=");
1023 if (pos) {
1024 size_t len;
1025 pos += 5;
1026 end = os_strchr(pos, ' ');
1027 if (end)
1028 len = end - pos;
1029 else
1030 len = os_strlen(pos);
1031 url = os_malloc(len + 1);
1032 if (url == NULL)
1033 return -1;
1034 os_memcpy(url, pos, len);
1035 url[len] = '\0';
1036 req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
1037 }
1038
1039 if (os_strstr(cmd, " pref=1"))
1040 req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
1041 if (os_strstr(cmd, " abridged=1"))
1042 req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1043 if (os_strstr(cmd, " disassoc_imminent=1"))
1044 req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
1045
1046 ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
1047 valid_int, bss_term_dur, url,
1048 nei_pos > nei_rep ? nei_rep : NULL,
1049 nei_pos - nei_rep);
1050 os_free(url);
1051 return ret;
1052}
1053
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001054#endif /* CONFIG_WNM */
1055
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001056
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001057static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
1058 char *buf, size_t buflen)
1059{
1060 int ret;
1061 char *pos, *end;
1062
1063 pos = buf;
1064 end = buf + buflen;
1065
1066 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
1067 "ssid=%s\n",
1068 MAC2STR(hapd->own_addr),
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001069 wpa_ssid_txt(hapd->conf->ssid.ssid,
1070 hapd->conf->ssid.ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001071 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001072 return pos - buf;
1073 pos += ret;
1074
1075#ifdef CONFIG_WPS
1076 ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
1077 hapd->conf->wps_state == 0 ? "disabled" :
1078 (hapd->conf->wps_state == 1 ? "not configured" :
1079 "configured"));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001080 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001081 return pos - buf;
1082 pos += ret;
1083
1084 if (hapd->conf->wps_state && hapd->conf->wpa &&
1085 hapd->conf->ssid.wpa_passphrase) {
1086 ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
1087 hapd->conf->ssid.wpa_passphrase);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001088 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001089 return pos - buf;
1090 pos += ret;
1091 }
1092
1093 if (hapd->conf->wps_state && hapd->conf->wpa &&
1094 hapd->conf->ssid.wpa_psk &&
1095 hapd->conf->ssid.wpa_psk->group) {
1096 char hex[PMK_LEN * 2 + 1];
1097 wpa_snprintf_hex(hex, sizeof(hex),
1098 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
1099 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001100 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001101 return pos - buf;
1102 pos += ret;
1103 }
1104#endif /* CONFIG_WPS */
1105
1106 if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
1107 ret = os_snprintf(pos, end - pos, "key_mgmt=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001108 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001109 return pos - buf;
1110 pos += ret;
1111
1112 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
1113 ret = os_snprintf(pos, end - pos, "WPA-PSK ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001114 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001115 return pos - buf;
1116 pos += ret;
1117 }
1118 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1119 ret = os_snprintf(pos, end - pos, "WPA-EAP ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001120 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001121 return pos - buf;
1122 pos += ret;
1123 }
1124#ifdef CONFIG_IEEE80211R
1125 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1126 ret = os_snprintf(pos, end - pos, "FT-PSK ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001127 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001128 return pos - buf;
1129 pos += ret;
1130 }
1131 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1132 ret = os_snprintf(pos, end - pos, "FT-EAP ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001133 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001134 return pos - buf;
1135 pos += ret;
1136 }
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07001137#ifdef CONFIG_SAE
1138 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
1139 ret = os_snprintf(pos, end - pos, "FT-SAE ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001140 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07001141 return pos - buf;
1142 pos += ret;
1143 }
1144#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001145#endif /* CONFIG_IEEE80211R */
1146#ifdef CONFIG_IEEE80211W
1147 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1148 ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001149 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001150 return pos - buf;
1151 pos += ret;
1152 }
1153 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1154 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001155 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001156 return pos - buf;
1157 pos += ret;
1158 }
1159#endif /* CONFIG_IEEE80211W */
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07001160#ifdef CONFIG_SAE
1161 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
1162 ret = os_snprintf(pos, end - pos, "SAE ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001163 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07001164 return pos - buf;
1165 pos += ret;
1166 }
1167#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001168 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
1169 ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
1170 if (os_snprintf_error(end - pos, ret))
1171 return pos - buf;
1172 pos += ret;
1173 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001174 if (hapd->conf->wpa_key_mgmt &
1175 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
1176 ret = os_snprintf(pos, end - pos,
1177 "WPA-EAP-SUITE-B-192 ");
1178 if (os_snprintf_error(end - pos, ret))
1179 return pos - buf;
1180 pos += ret;
1181 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001182
1183 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001184 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001185 return pos - buf;
1186 pos += ret;
1187 }
1188
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001189 if (hapd->conf->wpa) {
1190 ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
1191 wpa_cipher_txt(hapd->conf->wpa_group));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001192 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001193 return pos - buf;
1194 pos += ret;
1195 }
1196
1197 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
1198 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001199 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001200 return pos - buf;
1201 pos += ret;
1202
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001203 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
1204 " ");
1205 if (ret < 0)
1206 return pos - buf;
1207 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001208
1209 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001210 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001211 return pos - buf;
1212 pos += ret;
1213 }
1214
1215 if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
1216 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001217 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001218 return pos - buf;
1219 pos += ret;
1220
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001221 ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001222 " ");
1223 if (ret < 0)
1224 return pos - buf;
1225 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001226
1227 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001228 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001229 return pos - buf;
1230 pos += ret;
1231 }
1232
1233 return pos - buf;
1234}
1235
1236
1237static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1238{
1239 char *value;
1240 int ret = 0;
1241
1242 value = os_strchr(cmd, ' ');
1243 if (value == NULL)
1244 return -1;
1245 *value++ = '\0';
1246
1247 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
1248 if (0) {
1249#ifdef CONFIG_WPS_TESTING
1250 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
1251 long int val;
1252 val = strtol(value, NULL, 0);
1253 if (val < 0 || val > 0xff) {
1254 ret = -1;
1255 wpa_printf(MSG_DEBUG, "WPS: Invalid "
1256 "wps_version_number %ld", val);
1257 } else {
1258 wps_version_number = val;
1259 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
1260 "version %u.%u",
1261 (wps_version_number & 0xf0) >> 4,
1262 wps_version_number & 0x0f);
1263 hostapd_wps_update_ie(hapd);
1264 }
1265 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
1266 wps_testing_dummy_cred = atoi(value);
1267 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
1268 wps_testing_dummy_cred);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001269 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
1270 wps_corrupt_pkhash = atoi(value);
1271 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
1272 wps_corrupt_pkhash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001273#endif /* CONFIG_WPS_TESTING */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001274#ifdef CONFIG_INTERWORKING
1275 } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
1276 int val = atoi(value);
1277 if (val <= 0)
1278 ret = -1;
1279 else
1280 hapd->gas_frag_limit = val;
1281#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001282#ifdef CONFIG_TESTING_OPTIONS
1283 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
1284 hapd->ext_mgmt_frame_handling = atoi(value);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001285 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
1286 hapd->ext_eapol_frame_io = atoi(value);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001287#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001288 } else {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001289 struct sta_info *sta;
1290 int vlan_id;
1291
Dmitry Shmidt04949592012-07-19 12:16:46 -07001292 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001293 if (ret)
1294 return ret;
1295
1296 if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
1297 for (sta = hapd->sta_list; sta; sta = sta->next) {
1298 if (hostapd_maclist_found(
1299 hapd->conf->deny_mac,
1300 hapd->conf->num_deny_mac, sta->addr,
1301 &vlan_id) &&
1302 (!vlan_id || vlan_id == sta->vlan_id))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001303 ap_sta_disconnect(
1304 hapd, sta, sta->addr,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001305 WLAN_REASON_UNSPECIFIED);
1306 }
1307 } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED &&
1308 os_strcasecmp(cmd, "accept_mac_file") == 0) {
1309 for (sta = hapd->sta_list; sta; sta = sta->next) {
1310 if (!hostapd_maclist_found(
1311 hapd->conf->accept_mac,
1312 hapd->conf->num_accept_mac,
1313 sta->addr, &vlan_id) ||
1314 (vlan_id && vlan_id != sta->vlan_id))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001315 ap_sta_disconnect(
1316 hapd, sta, sta->addr,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001317 WLAN_REASON_UNSPECIFIED);
1318 }
1319 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001320 }
1321
1322 return ret;
1323}
1324
1325
1326static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1327 char *buf, size_t buflen)
1328{
1329 int res;
1330
1331 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1332
1333 if (os_strcmp(cmd, "version") == 0) {
1334 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001335 if (os_snprintf_error(buflen, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001336 return -1;
1337 return res;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001338 } else if (os_strcmp(cmd, "tls_library") == 0) {
1339 res = tls_get_library_version(buf, buflen);
1340 if (os_snprintf_error(buflen, res))
1341 return -1;
1342 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001343 }
1344
1345 return -1;
1346}
1347
1348
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001349static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1350{
1351 if (hostapd_enable_iface(iface) < 0) {
1352 wpa_printf(MSG_ERROR, "Enabling of interface failed");
1353 return -1;
1354 }
1355 return 0;
1356}
1357
1358
1359static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1360{
1361 if (hostapd_reload_iface(iface) < 0) {
1362 wpa_printf(MSG_ERROR, "Reloading of interface failed");
1363 return -1;
1364 }
1365 return 0;
1366}
1367
1368
1369static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1370{
1371 if (hostapd_disable_iface(iface) < 0) {
1372 wpa_printf(MSG_ERROR, "Disabling of interface failed");
1373 return -1;
1374 }
1375 return 0;
1376}
1377
1378
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001379#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001380
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001381static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
1382{
1383 union wpa_event_data data;
1384 char *pos, *param;
1385 enum wpa_event_type event;
1386
1387 wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
1388
1389 os_memset(&data, 0, sizeof(data));
1390
1391 param = os_strchr(cmd, ' ');
1392 if (param == NULL)
1393 return -1;
1394 *param++ = '\0';
1395
1396 if (os_strcmp(cmd, "DETECTED") == 0)
1397 event = EVENT_DFS_RADAR_DETECTED;
1398 else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
1399 event = EVENT_DFS_CAC_FINISHED;
1400 else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
1401 event = EVENT_DFS_CAC_ABORTED;
1402 else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
1403 event = EVENT_DFS_NOP_FINISHED;
1404 else {
1405 wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
1406 cmd);
1407 return -1;
1408 }
1409
1410 pos = os_strstr(param, "freq=");
1411 if (pos)
1412 data.dfs_event.freq = atoi(pos + 5);
1413
1414 pos = os_strstr(param, "ht_enabled=1");
1415 if (pos)
1416 data.dfs_event.ht_enabled = 1;
1417
1418 pos = os_strstr(param, "chan_offset=");
1419 if (pos)
1420 data.dfs_event.chan_offset = atoi(pos + 12);
1421
1422 pos = os_strstr(param, "chan_width=");
1423 if (pos)
1424 data.dfs_event.chan_width = atoi(pos + 11);
1425
1426 pos = os_strstr(param, "cf1=");
1427 if (pos)
1428 data.dfs_event.cf1 = atoi(pos + 4);
1429
1430 pos = os_strstr(param, "cf2=");
1431 if (pos)
1432 data.dfs_event.cf2 = atoi(pos + 4);
1433
1434 wpa_supplicant_event(hapd, event, &data);
1435
1436 return 0;
1437}
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001438
1439
1440static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
1441{
1442 size_t len;
1443 u8 *buf;
1444 int res;
1445
1446 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
1447
1448 len = os_strlen(cmd);
1449 if (len & 1)
1450 return -1;
1451 len /= 2;
1452
1453 buf = os_malloc(len);
1454 if (buf == NULL)
1455 return -1;
1456
1457 if (hexstr2bin(cmd, buf, len) < 0) {
1458 os_free(buf);
1459 return -1;
1460 }
1461
1462 res = hostapd_drv_send_mlme(hapd, buf, len, 0);
1463 os_free(buf);
1464 return res;
1465}
1466
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001467
1468static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
1469{
1470 char *pos;
1471 u8 src[ETH_ALEN], *buf;
1472 int used;
1473 size_t len;
1474
1475 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
1476
1477 pos = cmd;
1478 used = hwaddr_aton2(pos, src);
1479 if (used < 0)
1480 return -1;
1481 pos += used;
1482 while (*pos == ' ')
1483 pos++;
1484
1485 len = os_strlen(pos);
1486 if (len & 1)
1487 return -1;
1488 len /= 2;
1489
1490 buf = os_malloc(len);
1491 if (buf == NULL)
1492 return -1;
1493
1494 if (hexstr2bin(pos, buf, len) < 0) {
1495 os_free(buf);
1496 return -1;
1497 }
1498
1499 ieee802_1x_receive(hapd, src, buf, len);
1500 os_free(buf);
1501
1502 return 0;
1503}
1504
1505
1506static u16 ipv4_hdr_checksum(const void *buf, size_t len)
1507{
1508 size_t i;
1509 u32 sum = 0;
1510 const u16 *pos = buf;
1511
1512 for (i = 0; i < len / 2; i++)
1513 sum += *pos++;
1514
1515 while (sum >> 16)
1516 sum = (sum & 0xffff) + (sum >> 16);
1517
1518 return sum ^ 0xffff;
1519}
1520
1521
1522#define HWSIM_PACKETLEN 1500
1523#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
1524
1525void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
1526 size_t len)
1527{
1528 struct hostapd_data *hapd = ctx;
1529 const struct ether_header *eth;
1530 const struct iphdr *ip;
1531 const u8 *pos;
1532 unsigned int i;
1533
1534 if (len != HWSIM_PACKETLEN)
1535 return;
1536
1537 eth = (const struct ether_header *) buf;
1538 ip = (const struct iphdr *) (eth + 1);
1539 pos = (const u8 *) (ip + 1);
1540
1541 if (ip->ihl != 5 || ip->version != 4 ||
1542 ntohs(ip->tot_len) != HWSIM_IP_LEN)
1543 return;
1544
1545 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
1546 if (*pos != (u8) i)
1547 return;
1548 pos++;
1549 }
1550
1551 wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
1552 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
1553}
1554
1555
1556static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
1557 char *cmd)
1558{
1559 int enabled = atoi(cmd);
1560 char *pos;
1561 const char *ifname;
1562
1563 if (!enabled) {
1564 if (hapd->l2_test) {
1565 l2_packet_deinit(hapd->l2_test);
1566 hapd->l2_test = NULL;
1567 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1568 "test data: Disabled");
1569 }
1570 return 0;
1571 }
1572
1573 if (hapd->l2_test)
1574 return 0;
1575
1576 pos = os_strstr(cmd, " ifname=");
1577 if (pos)
1578 ifname = pos + 8;
1579 else
1580 ifname = hapd->conf->iface;
1581
1582 hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
1583 ETHERTYPE_IP, hostapd_data_test_rx,
1584 hapd, 1);
1585 if (hapd->l2_test == NULL)
1586 return -1;
1587
1588 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
1589
1590 return 0;
1591}
1592
1593
1594static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
1595{
1596 u8 dst[ETH_ALEN], src[ETH_ALEN];
1597 char *pos;
1598 int used;
1599 long int val;
1600 u8 tos;
1601 u8 buf[HWSIM_PACKETLEN];
1602 struct ether_header *eth;
1603 struct iphdr *ip;
1604 u8 *dpos;
1605 unsigned int i;
1606
1607 if (hapd->l2_test == NULL)
1608 return -1;
1609
1610 /* format: <dst> <src> <tos> */
1611
1612 pos = cmd;
1613 used = hwaddr_aton2(pos, dst);
1614 if (used < 0)
1615 return -1;
1616 pos += used;
1617 while (*pos == ' ')
1618 pos++;
1619 used = hwaddr_aton2(pos, src);
1620 if (used < 0)
1621 return -1;
1622 pos += used;
1623
1624 val = strtol(pos, NULL, 0);
1625 if (val < 0 || val > 0xff)
1626 return -1;
1627 tos = val;
1628
1629 eth = (struct ether_header *) buf;
1630 os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
1631 os_memcpy(eth->ether_shost, src, ETH_ALEN);
1632 eth->ether_type = htons(ETHERTYPE_IP);
1633 ip = (struct iphdr *) (eth + 1);
1634 os_memset(ip, 0, sizeof(*ip));
1635 ip->ihl = 5;
1636 ip->version = 4;
1637 ip->ttl = 64;
1638 ip->tos = tos;
1639 ip->tot_len = htons(HWSIM_IP_LEN);
1640 ip->protocol = 1;
1641 ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
1642 ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
1643 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
1644 dpos = (u8 *) (ip + 1);
1645 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
1646 *dpos++ = i;
1647
1648 if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, buf,
1649 HWSIM_PACKETLEN) < 0)
1650 return -1;
1651
1652 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
1653 " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
1654
1655 return 0;
1656}
1657
1658
1659static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
1660 char *cmd)
1661{
1662 u8 *buf;
1663 struct ether_header *eth;
1664 struct l2_packet_data *l2 = NULL;
1665 size_t len;
1666 u16 ethertype;
1667 int res = -1;
1668 const char *ifname = hapd->conf->iface;
1669
1670 if (os_strncmp(cmd, "ifname=", 7) == 0) {
1671 cmd += 7;
1672 ifname = cmd;
1673 cmd = os_strchr(cmd, ' ');
1674 if (cmd == NULL)
1675 return -1;
1676 *cmd++ = '\0';
1677 }
1678
1679 len = os_strlen(cmd);
1680 if (len & 1 || len < ETH_HLEN * 2)
1681 return -1;
1682 len /= 2;
1683
1684 buf = os_malloc(len);
1685 if (buf == NULL)
1686 return -1;
1687
1688 if (hexstr2bin(cmd, buf, len) < 0)
1689 goto done;
1690
1691 eth = (struct ether_header *) buf;
1692 ethertype = ntohs(eth->ether_type);
1693
1694 l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
1695 hostapd_data_test_rx, hapd, 1);
1696 if (l2 == NULL)
1697 goto done;
1698
1699 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
1700 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
1701done:
1702 if (l2)
1703 l2_packet_deinit(l2);
1704 os_free(buf);
1705
1706 return res < 0 ? -1 : 0;
1707}
1708
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001709
1710static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
1711{
1712#ifdef WPA_TRACE_BFD
1713 extern char wpa_trace_fail_func[256];
1714 extern unsigned int wpa_trace_fail_after;
1715 char *pos;
1716
1717 wpa_trace_fail_after = atoi(cmd);
1718 pos = os_strchr(cmd, ':');
1719 if (pos) {
1720 pos++;
1721 os_strlcpy(wpa_trace_fail_func, pos,
1722 sizeof(wpa_trace_fail_func));
1723 } else {
1724 wpa_trace_fail_after = 0;
1725 }
1726
1727 return 0;
1728#else /* WPA_TRACE_BFD */
1729 return -1;
1730#endif /* WPA_TRACE_BFD */
1731}
1732
1733
1734static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
1735 char *buf, size_t buflen)
1736{
1737#ifdef WPA_TRACE_BFD
1738 extern char wpa_trace_fail_func[256];
1739 extern unsigned int wpa_trace_fail_after;
1740
1741 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
1742 wpa_trace_fail_func);
1743#else /* WPA_TRACE_BFD */
1744 return -1;
1745#endif /* WPA_TRACE_BFD */
1746}
1747
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001748#endif /* CONFIG_TESTING_OPTIONS */
1749
1750
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001751static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
1752 char *pos)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001753{
1754#ifdef NEED_AP_MLME
1755 struct csa_settings settings;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001756 int ret;
1757 unsigned int i;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001758
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001759 ret = hostapd_parse_csa_settings(pos, &settings);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001760 if (ret)
1761 return ret;
1762
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001763 for (i = 0; i < iface->num_bss; i++) {
1764 ret = hostapd_switch_channel(iface->bss[i], &settings);
1765 if (ret) {
1766 /* FIX: What do we do if CSA fails in the middle of
1767 * submitting multi-BSS CSA requests? */
1768 return ret;
1769 }
1770 }
1771
1772 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001773#else /* NEED_AP_MLME */
1774 return -1;
1775#endif /* NEED_AP_MLME */
1776}
1777
1778
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001779static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
1780 int reply_size, const char *param)
1781{
1782#ifdef RADIUS_SERVER
1783 if (os_strcmp(param, "radius_server") == 0) {
1784 return radius_server_get_mib(hapd->radius_srv, reply,
1785 reply_size);
1786 }
1787#endif /* RADIUS_SERVER */
1788 return -1;
1789}
1790
1791
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001792static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
1793 char *buf, size_t buflen)
1794{
1795 int ret;
1796 char *pos;
1797 u8 *data = NULL;
1798 unsigned int vendor_id, subcmd;
1799 struct wpabuf *reply;
1800 size_t data_len = 0;
1801
1802 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
1803 vendor_id = strtoul(cmd, &pos, 16);
1804 if (!isblank(*pos))
1805 return -EINVAL;
1806
1807 subcmd = strtoul(pos, &pos, 10);
1808
1809 if (*pos != '\0') {
1810 if (!isblank(*pos++))
1811 return -EINVAL;
1812 data_len = os_strlen(pos);
1813 }
1814
1815 if (data_len) {
1816 data_len /= 2;
1817 data = os_malloc(data_len);
1818 if (!data)
1819 return -ENOBUFS;
1820
1821 if (hexstr2bin(pos, data, data_len)) {
1822 wpa_printf(MSG_DEBUG,
1823 "Vendor command: wrong parameter format");
1824 os_free(data);
1825 return -EINVAL;
1826 }
1827 }
1828
1829 reply = wpabuf_alloc((buflen - 1) / 2);
1830 if (!reply) {
1831 os_free(data);
1832 return -ENOBUFS;
1833 }
1834
1835 ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
1836 reply);
1837
1838 if (ret == 0)
1839 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
1840 wpabuf_len(reply));
1841
1842 wpabuf_free(reply);
1843 os_free(data);
1844
1845 return ret;
1846}
1847
1848
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001849static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
1850 void *sock_ctx)
1851{
1852 struct hostapd_data *hapd = eloop_ctx;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001853 char buf[4096];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001854 int res;
1855 struct sockaddr_un from;
1856 socklen_t fromlen = sizeof(from);
1857 char *reply;
1858 const int reply_size = 4096;
1859 int reply_len;
1860 int level = MSG_DEBUG;
1861
1862 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1863 (struct sockaddr *) &from, &fromlen);
1864 if (res < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001865 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
1866 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001867 return;
1868 }
1869 buf[res] = '\0';
1870 if (os_strcmp(buf, "PING") == 0)
1871 level = MSG_EXCESSIVE;
1872 wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
1873
1874 reply = os_malloc(reply_size);
1875 if (reply == NULL) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001876 if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
1877 fromlen) < 0) {
1878 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
1879 strerror(errno));
1880 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001881 return;
1882 }
1883
1884 os_memcpy(reply, "OK\n", 3);
1885 reply_len = 3;
1886
1887 if (os_strcmp(buf, "PING") == 0) {
1888 os_memcpy(reply, "PONG\n", 5);
1889 reply_len = 5;
1890 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
1891 if (wpa_debug_reopen_file() < 0)
1892 reply_len = -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001893 } else if (os_strcmp(buf, "STATUS") == 0) {
1894 reply_len = hostapd_ctrl_iface_status(hapd, reply,
1895 reply_size);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001896 } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
1897 reply_len = hostapd_drv_status(hapd, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001898 } else if (os_strcmp(buf, "MIB") == 0) {
1899 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
1900 if (reply_len >= 0) {
1901 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
1902 reply_size - reply_len);
1903 if (res < 0)
1904 reply_len = -1;
1905 else
1906 reply_len += res;
1907 }
1908 if (reply_len >= 0) {
1909 res = ieee802_1x_get_mib(hapd, reply + reply_len,
1910 reply_size - reply_len);
1911 if (res < 0)
1912 reply_len = -1;
1913 else
1914 reply_len += res;
1915 }
1916#ifndef CONFIG_NO_RADIUS
1917 if (reply_len >= 0) {
1918 res = radius_client_get_mib(hapd->radius,
1919 reply + reply_len,
1920 reply_size - reply_len);
1921 if (res < 0)
1922 reply_len = -1;
1923 else
1924 reply_len += res;
1925 }
1926#endif /* CONFIG_NO_RADIUS */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001927 } else if (os_strncmp(buf, "MIB ", 4) == 0) {
1928 reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
1929 buf + 4);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001930 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
1931 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
1932 reply_size);
1933 } else if (os_strncmp(buf, "STA ", 4) == 0) {
1934 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
1935 reply_size);
1936 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
1937 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
1938 reply_size);
1939 } else if (os_strcmp(buf, "ATTACH") == 0) {
1940 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
1941 reply_len = -1;
1942 } else if (os_strcmp(buf, "DETACH") == 0) {
1943 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
1944 reply_len = -1;
1945 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
1946 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
1947 buf + 6))
1948 reply_len = -1;
1949 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
1950 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
1951 reply_len = -1;
1952 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
1953 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
1954 reply_len = -1;
1955 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
1956 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
1957 reply_len = -1;
1958#ifdef CONFIG_IEEE80211W
1959#ifdef NEED_AP_MLME
1960 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
1961 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
1962 reply_len = -1;
1963#endif /* NEED_AP_MLME */
1964#endif /* CONFIG_IEEE80211W */
1965#ifdef CONFIG_WPS
1966 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
1967 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
1968 reply_len = -1;
1969 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
1970 reply_len = hostapd_ctrl_iface_wps_check_pin(
1971 hapd, buf + 14, reply, reply_size);
1972 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
1973 if (hostapd_wps_button_pushed(hapd, NULL))
1974 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001975 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
1976 if (hostapd_wps_cancel(hapd))
1977 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001978 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
1979 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
1980 reply, reply_size);
1981 } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
1982 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
1983 reply_len = -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001984 } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
1985 reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
1986 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001987#ifdef CONFIG_WPS_NFC
1988 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
1989 if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
1990 reply_len = -1;
1991 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
1992 reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
1993 hapd, buf + 21, reply, reply_size);
1994 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
1995 reply_len = hostapd_ctrl_iface_wps_nfc_token(
1996 hapd, buf + 14, reply, reply_size);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001997 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
1998 reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
1999 hapd, buf + 21, reply, reply_size);
2000 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
2001 if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
2002 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002003#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002004#endif /* CONFIG_WPS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002005#ifdef CONFIG_INTERWORKING
2006 } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
2007 if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
2008 reply_len = -1;
2009 } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
2010 if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
2011 reply_len = -1;
2012#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002013#ifdef CONFIG_HS20
2014 } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
2015 if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
2016 reply_len = -1;
2017 } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
2018 if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
2019 reply_len = -1;
2020#endif /* CONFIG_HS20 */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002021#ifdef CONFIG_WNM
2022 } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
2023 if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
2024 reply_len = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002025 } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
2026 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
2027 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002028 } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
2029 if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
2030 reply_len = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002031#endif /* CONFIG_WNM */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002032 } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
2033 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
2034 reply_size);
2035 } else if (os_strncmp(buf, "SET ", 4) == 0) {
2036 if (hostapd_ctrl_iface_set(hapd, buf + 4))
2037 reply_len = -1;
2038 } else if (os_strncmp(buf, "GET ", 4) == 0) {
2039 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
2040 reply_size);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002041 } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
2042 if (hostapd_ctrl_iface_enable(hapd->iface))
2043 reply_len = -1;
2044 } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
2045 if (hostapd_ctrl_iface_reload(hapd->iface))
2046 reply_len = -1;
2047 } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
2048 if (hostapd_ctrl_iface_disable(hapd->iface))
2049 reply_len = -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002050#ifdef CONFIG_TESTING_OPTIONS
2051 } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
2052 if (hostapd_ctrl_iface_radar(hapd, buf + 6))
2053 reply_len = -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002054 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
2055 if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
2056 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002057 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
2058 if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
2059 reply_len = -1;
2060 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
2061 if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
2062 reply_len = -1;
2063 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
2064 if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
2065 reply_len = -1;
2066 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
2067 if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
2068 reply_len = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002069 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
2070 if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
2071 reply_len = -1;
2072 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
2073 reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
2074 reply_size);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002075#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002076 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002077 if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002078 reply_len = -1;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07002079 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
2080 reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
2081 reply_size);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002082 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
2083 ieee802_1x_erp_flush(hapd);
2084#ifdef RADIUS_SERVER
2085 radius_server_erp_flush(hapd->radius_srv);
2086#endif /* RADIUS_SERVER */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002087 } else {
2088 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
2089 reply_len = 16;
2090 }
2091
2092 if (reply_len < 0) {
2093 os_memcpy(reply, "FAIL\n", 5);
2094 reply_len = 5;
2095 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002096 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
2097 fromlen) < 0) {
2098 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2099 strerror(errno));
2100 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002101 os_free(reply);
2102}
2103
2104
2105static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
2106{
2107 char *buf;
2108 size_t len;
2109
2110 if (hapd->conf->ctrl_interface == NULL)
2111 return NULL;
2112
2113 len = os_strlen(hapd->conf->ctrl_interface) +
2114 os_strlen(hapd->conf->iface) + 2;
2115 buf = os_malloc(len);
2116 if (buf == NULL)
2117 return NULL;
2118
2119 os_snprintf(buf, len, "%s/%s",
2120 hapd->conf->ctrl_interface, hapd->conf->iface);
2121 buf[len - 1] = '\0';
2122 return buf;
2123}
2124
2125
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002126static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002127 const char *txt, size_t len)
2128{
2129 struct hostapd_data *hapd = ctx;
2130 if (hapd == NULL)
2131 return;
2132 hostapd_ctrl_iface_send(hapd, level, txt, len);
2133}
2134
2135
2136int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
2137{
2138 struct sockaddr_un addr;
2139 int s = -1;
2140 char *fname = NULL;
2141
Dmitry Shmidt04949592012-07-19 12:16:46 -07002142 if (hapd->ctrl_sock > -1) {
2143 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
2144 return 0;
2145 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002146
2147 if (hapd->conf->ctrl_interface == NULL)
2148 return 0;
2149
2150 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2151 if (errno == EEXIST) {
2152 wpa_printf(MSG_DEBUG, "Using existing control "
2153 "interface directory.");
2154 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002155 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
2156 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002157 goto fail;
2158 }
2159 }
2160
2161 if (hapd->conf->ctrl_interface_gid_set &&
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002162 chown(hapd->conf->ctrl_interface, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002163 hapd->conf->ctrl_interface_gid) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002164 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2165 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002166 return -1;
2167 }
2168
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002169 if (!hapd->conf->ctrl_interface_gid_set &&
2170 hapd->iface->interfaces->ctrl_iface_group &&
2171 chown(hapd->conf->ctrl_interface, -1,
2172 hapd->iface->interfaces->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002173 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2174 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002175 return -1;
2176 }
2177
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002178#ifdef ANDROID
2179 /*
2180 * Android is using umask 0077 which would leave the control interface
2181 * directory without group access. This breaks things since Wi-Fi
2182 * framework assumes that this directory can be accessed by other
2183 * applications in the wifi group. Fix this by adding group access even
2184 * if umask value would prevent this.
2185 */
2186 if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2187 wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
2188 strerror(errno));
2189 /* Try to continue anyway */
2190 }
2191#endif /* ANDROID */
2192
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002193 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
2194 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
2195 goto fail;
2196
2197 s = socket(PF_UNIX, SOCK_DGRAM, 0);
2198 if (s < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002199 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002200 goto fail;
2201 }
2202
2203 os_memset(&addr, 0, sizeof(addr));
2204#ifdef __FreeBSD__
2205 addr.sun_len = sizeof(addr);
2206#endif /* __FreeBSD__ */
2207 addr.sun_family = AF_UNIX;
2208 fname = hostapd_ctrl_iface_path(hapd);
2209 if (fname == NULL)
2210 goto fail;
2211 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
2212 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2213 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
2214 strerror(errno));
2215 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2216 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
2217 " allow connections - assuming it was left"
2218 "over from forced program termination");
2219 if (unlink(fname) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002220 wpa_printf(MSG_ERROR,
2221 "Could not unlink existing ctrl_iface socket '%s': %s",
2222 fname, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002223 goto fail;
2224 }
2225 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
2226 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002227 wpa_printf(MSG_ERROR,
2228 "hostapd-ctrl-iface: bind(PF_UNIX): %s",
2229 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002230 goto fail;
2231 }
2232 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
2233 "ctrl_iface socket '%s'", fname);
2234 } else {
2235 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
2236 "be in use - cannot override it");
2237 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
2238 "not used anymore", fname);
2239 os_free(fname);
2240 fname = NULL;
2241 goto fail;
2242 }
2243 }
2244
2245 if (hapd->conf->ctrl_interface_gid_set &&
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002246 chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002247 wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2248 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002249 goto fail;
2250 }
2251
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002252 if (!hapd->conf->ctrl_interface_gid_set &&
2253 hapd->iface->interfaces->ctrl_iface_group &&
2254 chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002255 wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2256 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002257 goto fail;
2258 }
2259
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002260 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002261 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
2262 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002263 goto fail;
2264 }
2265 os_free(fname);
2266
2267 hapd->ctrl_sock = s;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002268 if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
2269 NULL) < 0) {
2270 hostapd_ctrl_iface_deinit(hapd);
2271 return -1;
2272 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002273 hapd->msg_ctx = hapd;
2274 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
2275
2276 return 0;
2277
2278fail:
2279 if (s >= 0)
2280 close(s);
2281 if (fname) {
2282 unlink(fname);
2283 os_free(fname);
2284 }
2285 return -1;
2286}
2287
2288
2289void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
2290{
2291 struct wpa_ctrl_dst *dst, *prev;
2292
2293 if (hapd->ctrl_sock > -1) {
2294 char *fname;
2295 eloop_unregister_read_sock(hapd->ctrl_sock);
2296 close(hapd->ctrl_sock);
2297 hapd->ctrl_sock = -1;
2298 fname = hostapd_ctrl_iface_path(hapd);
2299 if (fname)
2300 unlink(fname);
2301 os_free(fname);
2302
2303 if (hapd->conf->ctrl_interface &&
2304 rmdir(hapd->conf->ctrl_interface) < 0) {
2305 if (errno == ENOTEMPTY) {
2306 wpa_printf(MSG_DEBUG, "Control interface "
2307 "directory not empty - leaving it "
2308 "behind");
2309 } else {
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002310 wpa_printf(MSG_ERROR,
2311 "rmdir[ctrl_interface=%s]: %s",
2312 hapd->conf->ctrl_interface,
2313 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002314 }
2315 }
2316 }
2317
2318 dst = hapd->ctrl_dst;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002319 hapd->ctrl_dst = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002320 while (dst) {
2321 prev = dst;
2322 dst = dst->next;
2323 os_free(prev);
2324 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002325
2326#ifdef CONFIG_TESTING_OPTIONS
2327 l2_packet_deinit(hapd->l2_test);
2328 hapd->l2_test = NULL;
2329#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002330}
2331
2332
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002333static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
2334 char *buf)
2335{
2336 if (hostapd_add_iface(interfaces, buf) < 0) {
2337 wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
2338 return -1;
2339 }
2340 return 0;
2341}
2342
2343
2344static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
2345 char *buf)
2346{
2347 if (hostapd_remove_iface(interfaces, buf) < 0) {
2348 wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
2349 return -1;
2350 }
2351 return 0;
2352}
2353
2354
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002355static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
2356{
2357#ifdef CONFIG_WPS_TESTING
2358 wps_version_number = 0x20;
2359 wps_testing_dummy_cred = 0;
2360 wps_corrupt_pkhash = 0;
2361#endif /* CONFIG_WPS_TESTING */
2362}
2363
2364
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002365static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
2366 void *sock_ctx)
2367{
2368 void *interfaces = eloop_ctx;
2369 char buf[256];
2370 int res;
2371 struct sockaddr_un from;
2372 socklen_t fromlen = sizeof(from);
2373 char reply[24];
2374 int reply_len;
2375
2376 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
2377 (struct sockaddr *) &from, &fromlen);
2378 if (res < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002379 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
2380 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002381 return;
2382 }
2383 buf[res] = '\0';
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002384 wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002385
2386 os_memcpy(reply, "OK\n", 3);
2387 reply_len = 3;
2388
2389 if (os_strcmp(buf, "PING") == 0) {
2390 os_memcpy(reply, "PONG\n", 5);
2391 reply_len = 5;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002392 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
2393 if (wpa_debug_reopen_file() < 0)
2394 reply_len = -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08002395 } else if (os_strcmp(buf, "FLUSH") == 0) {
2396 hostapd_ctrl_iface_flush(interfaces);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002397 } else if (os_strncmp(buf, "ADD ", 4) == 0) {
2398 if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
2399 reply_len = -1;
2400 } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
2401 if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
2402 reply_len = -1;
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -08002403#ifdef CONFIG_MODULE_TESTS
2404 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
2405 int hapd_module_tests(void);
2406 if (hapd_module_tests() < 0)
2407 reply_len = -1;
2408#endif /* CONFIG_MODULE_TESTS */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002409 } else {
2410 wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
2411 "ignored");
2412 reply_len = -1;
2413 }
2414
2415 if (reply_len < 0) {
2416 os_memcpy(reply, "FAIL\n", 5);
2417 reply_len = 5;
2418 }
2419
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002420 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
2421 fromlen) < 0) {
2422 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2423 strerror(errno));
2424 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002425}
2426
2427
2428static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
2429{
2430 char *buf;
2431 size_t len;
2432
2433 if (interface->global_iface_path == NULL)
2434 return NULL;
2435
2436 len = os_strlen(interface->global_iface_path) +
2437 os_strlen(interface->global_iface_name) + 2;
2438 buf = os_malloc(len);
2439 if (buf == NULL)
2440 return NULL;
2441
2442 os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
2443 interface->global_iface_name);
2444 buf[len - 1] = '\0';
2445 return buf;
2446}
2447
2448
2449int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
2450{
2451 struct sockaddr_un addr;
2452 int s = -1;
2453 char *fname = NULL;
2454
2455 if (interface->global_iface_path == NULL) {
2456 wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
2457 return 0;
2458 }
2459
2460 if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
2461 if (errno == EEXIST) {
2462 wpa_printf(MSG_DEBUG, "Using existing control "
2463 "interface directory.");
2464 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002465 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
2466 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002467 goto fail;
2468 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002469 } else if (interface->ctrl_iface_group &&
2470 chown(interface->global_iface_path, -1,
2471 interface->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002472 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2473 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002474 goto fail;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002475 }
2476
2477 if (os_strlen(interface->global_iface_path) + 1 +
2478 os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
2479 goto fail;
2480
2481 s = socket(PF_UNIX, SOCK_DGRAM, 0);
2482 if (s < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002483 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002484 goto fail;
2485 }
2486
2487 os_memset(&addr, 0, sizeof(addr));
2488#ifdef __FreeBSD__
2489 addr.sun_len = sizeof(addr);
2490#endif /* __FreeBSD__ */
2491 addr.sun_family = AF_UNIX;
2492 fname = hostapd_global_ctrl_iface_path(interface);
2493 if (fname == NULL)
2494 goto fail;
2495 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
2496 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2497 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
2498 strerror(errno));
2499 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2500 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
2501 " allow connections - assuming it was left"
2502 "over from forced program termination");
2503 if (unlink(fname) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002504 wpa_printf(MSG_ERROR,
2505 "Could not unlink existing ctrl_iface socket '%s': %s",
2506 fname, strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002507 goto fail;
2508 }
2509 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
2510 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002511 wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
2512 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002513 goto fail;
2514 }
2515 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
2516 "ctrl_iface socket '%s'", fname);
2517 } else {
2518 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
2519 "be in use - cannot override it");
2520 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
2521 "not used anymore", fname);
2522 os_free(fname);
2523 fname = NULL;
2524 goto fail;
2525 }
2526 }
2527
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002528 if (interface->ctrl_iface_group &&
2529 chown(fname, -1, interface->ctrl_iface_group) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002530 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2531 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002532 goto fail;
2533 }
2534
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002535 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002536 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
2537 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002538 goto fail;
2539 }
2540 os_free(fname);
2541
2542 interface->global_ctrl_sock = s;
2543 eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
2544 interface, NULL);
2545
2546 return 0;
2547
2548fail:
2549 if (s >= 0)
2550 close(s);
2551 if (fname) {
2552 unlink(fname);
2553 os_free(fname);
2554 }
2555 return -1;
2556}
2557
2558
2559void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
2560{
2561 char *fname = NULL;
2562
2563 if (interfaces->global_ctrl_sock > -1) {
2564 eloop_unregister_read_sock(interfaces->global_ctrl_sock);
2565 close(interfaces->global_ctrl_sock);
2566 interfaces->global_ctrl_sock = -1;
2567 fname = hostapd_global_ctrl_iface_path(interfaces);
2568 if (fname) {
2569 unlink(fname);
2570 os_free(fname);
2571 }
2572
2573 if (interfaces->global_iface_path &&
2574 rmdir(interfaces->global_iface_path) < 0) {
2575 if (errno == ENOTEMPTY) {
2576 wpa_printf(MSG_DEBUG, "Control interface "
2577 "directory not empty - leaving it "
2578 "behind");
2579 } else {
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002580 wpa_printf(MSG_ERROR,
2581 "rmdir[ctrl_interface=%s]: %s",
2582 interfaces->global_iface_path,
2583 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002584 }
2585 }
2586 os_free(interfaces->global_iface_path);
2587 interfaces->global_iface_path = NULL;
2588 }
2589}
2590
2591
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002592static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
2593 const char *buf, size_t len)
2594{
2595 struct wpa_ctrl_dst *dst, *next;
2596 struct msghdr msg;
2597 int idx;
2598 struct iovec io[2];
2599 char levelstr[10];
2600
2601 dst = hapd->ctrl_dst;
2602 if (hapd->ctrl_sock < 0 || dst == NULL)
2603 return;
2604
2605 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
2606 io[0].iov_base = levelstr;
2607 io[0].iov_len = os_strlen(levelstr);
2608 io[1].iov_base = (char *) buf;
2609 io[1].iov_len = len;
2610 os_memset(&msg, 0, sizeof(msg));
2611 msg.msg_iov = io;
2612 msg.msg_iovlen = 2;
2613
2614 idx = 0;
2615 while (dst) {
2616 next = dst->next;
2617 if (level >= dst->debug_level) {
2618 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
2619 (u8 *) dst->addr.sun_path, dst->addrlen -
2620 offsetof(struct sockaddr_un, sun_path));
2621 msg.msg_name = &dst->addr;
2622 msg.msg_namelen = dst->addrlen;
2623 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
2624 int _errno = errno;
2625 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
2626 "%d - %s",
2627 idx, errno, strerror(errno));
2628 dst->errors++;
2629 if (dst->errors > 10 || _errno == ENOENT) {
2630 hostapd_ctrl_iface_detach(
2631 hapd, &dst->addr,
2632 dst->addrlen);
2633 }
2634 } else
2635 dst->errors = 0;
2636 }
2637 idx++;
2638 dst = next;
2639 }
2640}
2641
2642#endif /* CONFIG_NATIVE_WINDOWS */