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