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 : #ifdef CONFIG_CTRL_IFACE_UDP
23 : #include <netdb.h>
24 : #endif /* CONFIG_CTRL_IFACE_UDP */
25 :
26 : #include "utils/common.h"
27 : #include "utils/eloop.h"
28 : #include "utils/module_tests.h"
29 : #include "common/version.h"
30 : #include "common/ieee802_11_defs.h"
31 : #include "common/ctrl_iface_common.h"
32 : #include "crypto/tls.h"
33 : #include "drivers/driver.h"
34 : #include "eapol_auth/eapol_auth_sm.h"
35 : #include "radius/radius_client.h"
36 : #include "radius/radius_server.h"
37 : #include "l2_packet/l2_packet.h"
38 : #include "ap/hostapd.h"
39 : #include "ap/ap_config.h"
40 : #include "ap/ieee802_1x.h"
41 : #include "ap/wpa_auth.h"
42 : #include "ap/ieee802_11.h"
43 : #include "ap/sta_info.h"
44 : #include "ap/wps_hostapd.h"
45 : #include "ap/ctrl_iface_ap.h"
46 : #include "ap/ap_drv_ops.h"
47 : #include "ap/hs20.h"
48 : #include "ap/wnm_ap.h"
49 : #include "ap/wpa_auth.h"
50 : #include "ap/beacon.h"
51 : #include "ap/neighbor_db.h"
52 : #include "ap/rrm.h"
53 : #include "wps/wps_defs.h"
54 : #include "wps/wps.h"
55 : #include "fst/fst_ctrl_iface.h"
56 : #include "config_file.h"
57 : #include "ctrl_iface.h"
58 :
59 :
60 : #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
61 :
62 : #ifdef CONFIG_CTRL_IFACE_UDP
63 : #define COOKIE_LEN 8
64 : static unsigned char cookie[COOKIE_LEN];
65 : static unsigned char gcookie[COOKIE_LEN];
66 : #define HOSTAPD_CTRL_IFACE_PORT 8877
67 : #define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
68 : #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
69 : #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50
70 : #endif /* CONFIG_CTRL_IFACE_UDP */
71 :
72 : static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
73 : enum wpa_msg_type type,
74 : const char *buf, size_t len);
75 :
76 :
77 2443 : static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
78 : struct sockaddr_storage *from,
79 : socklen_t fromlen)
80 : {
81 2443 : return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen);
82 : }
83 :
84 :
85 2318 : static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
86 : struct sockaddr_storage *from,
87 : socklen_t fromlen)
88 : {
89 2318 : return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
90 : }
91 :
92 :
93 1 : static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
94 : struct sockaddr_storage *from,
95 : socklen_t fromlen,
96 : char *level)
97 : {
98 1 : return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
99 : }
100 :
101 :
102 3 : static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
103 : const char *txtaddr)
104 : {
105 : u8 addr[ETH_ALEN];
106 : struct sta_info *sta;
107 :
108 3 : wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
109 :
110 3 : if (hwaddr_aton(txtaddr, addr))
111 1 : return -1;
112 :
113 2 : sta = ap_get_sta(hapd, addr);
114 2 : if (sta)
115 0 : return 0;
116 :
117 12 : wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
118 12 : "notification", MAC2STR(addr));
119 2 : sta = ap_sta_add(hapd, addr);
120 2 : if (sta == NULL)
121 0 : return -1;
122 :
123 2 : hostapd_new_assoc_sta(hapd, sta, 0);
124 2 : return 0;
125 : }
126 :
127 :
128 : #ifdef CONFIG_IEEE80211W
129 : #ifdef NEED_AP_MLME
130 3 : static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
131 : const char *txtaddr)
132 : {
133 : u8 addr[ETH_ALEN];
134 : u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
135 :
136 3 : wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
137 :
138 6 : if (hwaddr_aton(txtaddr, addr) ||
139 3 : os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
140 0 : return -1;
141 :
142 3 : ieee802_11_send_sa_query_req(hapd, addr, trans_id);
143 :
144 3 : return 0;
145 : }
146 : #endif /* NEED_AP_MLME */
147 : #endif /* CONFIG_IEEE80211W */
148 :
149 :
150 : #ifdef CONFIG_WPS
151 117 : static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
152 : {
153 117 : char *pin = os_strchr(txt, ' ');
154 : char *timeout_txt;
155 : int timeout;
156 117 : u8 addr_buf[ETH_ALEN], *addr = NULL;
157 : char *pos;
158 :
159 117 : if (pin == NULL)
160 1 : return -1;
161 116 : *pin++ = '\0';
162 :
163 116 : timeout_txt = os_strchr(pin, ' ');
164 116 : if (timeout_txt) {
165 2 : *timeout_txt++ = '\0';
166 2 : timeout = atoi(timeout_txt);
167 2 : pos = os_strchr(timeout_txt, ' ');
168 2 : if (pos) {
169 1 : *pos++ = '\0';
170 1 : if (hwaddr_aton(pos, addr_buf) == 0)
171 1 : addr = addr_buf;
172 : }
173 : } else
174 114 : timeout = 0;
175 :
176 116 : return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
177 : }
178 :
179 :
180 10 : static int hostapd_ctrl_iface_wps_check_pin(
181 : struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
182 : {
183 : char pin[9];
184 : size_t len;
185 : char *pos;
186 : int ret;
187 :
188 10 : wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
189 : (u8 *) cmd, os_strlen(cmd));
190 90 : for (pos = cmd, len = 0; *pos != '\0'; pos++) {
191 83 : if (*pos < '0' || *pos > '9')
192 6 : continue;
193 77 : pin[len++] = *pos;
194 77 : if (len == 9) {
195 3 : wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
196 3 : return -1;
197 : }
198 : }
199 7 : if (len != 4 && len != 8) {
200 2 : wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
201 2 : return -1;
202 : }
203 5 : pin[len] = '\0';
204 :
205 5 : if (len == 8) {
206 : unsigned int pin_val;
207 5 : pin_val = atoi(pin);
208 5 : if (!wps_pin_valid(pin_val)) {
209 1 : wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
210 1 : ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
211 1 : if (os_snprintf_error(buflen, ret))
212 0 : return -1;
213 1 : return ret;
214 : }
215 : }
216 :
217 4 : ret = os_snprintf(buf, buflen, "%s", pin);
218 4 : if (os_snprintf_error(buflen, ret))
219 0 : return -1;
220 :
221 4 : return ret;
222 : }
223 :
224 :
225 : #ifdef CONFIG_WPS_NFC
226 3 : static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
227 : char *pos)
228 : {
229 : size_t len;
230 : struct wpabuf *buf;
231 : int ret;
232 :
233 3 : len = os_strlen(pos);
234 3 : if (len & 0x01)
235 0 : return -1;
236 3 : len /= 2;
237 :
238 3 : buf = wpabuf_alloc(len);
239 3 : if (buf == NULL)
240 0 : return -1;
241 3 : if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
242 0 : wpabuf_free(buf);
243 0 : return -1;
244 : }
245 :
246 3 : ret = hostapd_wps_nfc_tag_read(hapd, buf);
247 3 : wpabuf_free(buf);
248 :
249 3 : return ret;
250 : }
251 :
252 :
253 4 : static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
254 : char *cmd, char *reply,
255 : size_t max_len)
256 : {
257 : int ndef;
258 : struct wpabuf *buf;
259 : int res;
260 :
261 4 : if (os_strcmp(cmd, "WPS") == 0)
262 0 : ndef = 0;
263 4 : else if (os_strcmp(cmd, "NDEF") == 0)
264 4 : ndef = 1;
265 : else
266 0 : return -1;
267 :
268 4 : buf = hostapd_wps_nfc_config_token(hapd, ndef);
269 4 : if (buf == NULL)
270 2 : return -1;
271 :
272 2 : res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
273 : wpabuf_len(buf));
274 2 : reply[res++] = '\n';
275 2 : reply[res] = '\0';
276 :
277 2 : wpabuf_free(buf);
278 :
279 2 : return res;
280 : }
281 :
282 :
283 6 : static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
284 : char *reply, size_t max_len,
285 : int ndef)
286 : {
287 : struct wpabuf *buf;
288 : int res;
289 :
290 6 : buf = hostapd_wps_nfc_token_gen(hapd, ndef);
291 6 : if (buf == NULL)
292 2 : return -1;
293 :
294 4 : res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
295 : wpabuf_len(buf));
296 4 : reply[res++] = '\n';
297 4 : reply[res] = '\0';
298 :
299 4 : wpabuf_free(buf);
300 :
301 4 : return res;
302 : }
303 :
304 :
305 9 : static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
306 : char *cmd, char *reply,
307 : size_t max_len)
308 : {
309 9 : if (os_strcmp(cmd, "WPS") == 0)
310 4 : return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
311 : max_len, 0);
312 :
313 5 : if (os_strcmp(cmd, "NDEF") == 0)
314 2 : return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
315 : max_len, 1);
316 :
317 3 : if (os_strcmp(cmd, "enable") == 0)
318 2 : return hostapd_wps_nfc_token_enable(hapd);
319 :
320 1 : if (os_strcmp(cmd, "disable") == 0) {
321 1 : hostapd_wps_nfc_token_disable(hapd);
322 1 : return 0;
323 : }
324 :
325 0 : return -1;
326 : }
327 :
328 :
329 10 : static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
330 : char *cmd, char *reply,
331 : size_t max_len)
332 : {
333 : struct wpabuf *buf;
334 : int res;
335 : char *pos;
336 : int ndef;
337 :
338 10 : pos = os_strchr(cmd, ' ');
339 10 : if (pos == NULL)
340 0 : return -1;
341 10 : *pos++ = '\0';
342 :
343 10 : if (os_strcmp(cmd, "WPS") == 0)
344 0 : ndef = 0;
345 10 : else if (os_strcmp(cmd, "NDEF") == 0)
346 10 : ndef = 1;
347 : else
348 0 : return -1;
349 :
350 10 : if (os_strcmp(pos, "WPS-CR") == 0)
351 10 : buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
352 : else
353 0 : buf = NULL;
354 10 : if (buf == NULL)
355 2 : return -1;
356 :
357 8 : res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
358 : wpabuf_len(buf));
359 8 : reply[res++] = '\n';
360 8 : reply[res] = '\0';
361 :
362 8 : wpabuf_free(buf);
363 :
364 8 : return res;
365 : }
366 :
367 :
368 18 : static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
369 : char *cmd)
370 : {
371 : size_t len;
372 : struct wpabuf *req, *sel;
373 : int ret;
374 : char *pos, *role, *type, *pos2;
375 :
376 18 : role = cmd;
377 18 : pos = os_strchr(role, ' ');
378 18 : if (pos == NULL)
379 2 : return -1;
380 16 : *pos++ = '\0';
381 :
382 16 : type = pos;
383 16 : pos = os_strchr(type, ' ');
384 16 : if (pos == NULL)
385 1 : return -1;
386 15 : *pos++ = '\0';
387 :
388 15 : pos2 = os_strchr(pos, ' ');
389 15 : if (pos2 == NULL)
390 1 : return -1;
391 14 : *pos2++ = '\0';
392 :
393 14 : len = os_strlen(pos);
394 14 : if (len & 0x01)
395 1 : return -1;
396 13 : len /= 2;
397 :
398 13 : req = wpabuf_alloc(len);
399 13 : if (req == NULL)
400 0 : return -1;
401 13 : if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
402 1 : wpabuf_free(req);
403 1 : return -1;
404 : }
405 :
406 12 : len = os_strlen(pos2);
407 12 : if (len & 0x01) {
408 1 : wpabuf_free(req);
409 1 : return -1;
410 : }
411 11 : len /= 2;
412 :
413 11 : sel = wpabuf_alloc(len);
414 11 : if (sel == NULL) {
415 0 : wpabuf_free(req);
416 0 : return -1;
417 : }
418 11 : if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
419 1 : wpabuf_free(req);
420 1 : wpabuf_free(sel);
421 1 : return -1;
422 : }
423 :
424 10 : if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
425 9 : ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
426 : } else {
427 1 : wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
428 : "reported: role=%s type=%s", role, type);
429 1 : ret = -1;
430 : }
431 10 : wpabuf_free(req);
432 10 : wpabuf_free(sel);
433 :
434 10 : return ret;
435 : }
436 :
437 : #endif /* CONFIG_WPS_NFC */
438 :
439 :
440 19 : static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
441 : char *buf, size_t buflen)
442 : {
443 19 : int timeout = 300;
444 : char *pos;
445 : const char *pin_txt;
446 :
447 19 : pos = os_strchr(txt, ' ');
448 19 : if (pos)
449 5 : *pos++ = '\0';
450 :
451 19 : if (os_strcmp(txt, "disable") == 0) {
452 6 : hostapd_wps_ap_pin_disable(hapd);
453 6 : return os_snprintf(buf, buflen, "OK\n");
454 : }
455 :
456 13 : if (os_strcmp(txt, "random") == 0) {
457 6 : if (pos)
458 2 : timeout = atoi(pos);
459 6 : pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
460 6 : if (pin_txt == NULL)
461 2 : return -1;
462 4 : return os_snprintf(buf, buflen, "%s", pin_txt);
463 : }
464 :
465 7 : if (os_strcmp(txt, "get") == 0) {
466 4 : pin_txt = hostapd_wps_ap_pin_get(hapd);
467 4 : if (pin_txt == NULL)
468 2 : return -1;
469 2 : return os_snprintf(buf, buflen, "%s", pin_txt);
470 : }
471 :
472 3 : if (os_strcmp(txt, "set") == 0) {
473 : char *pin;
474 3 : if (pos == NULL)
475 0 : return -1;
476 3 : pin = pos;
477 3 : pos = os_strchr(pos, ' ');
478 3 : if (pos) {
479 1 : *pos++ = '\0';
480 1 : timeout = atoi(pos);
481 : }
482 3 : if (os_strlen(pin) > buflen)
483 0 : return -1;
484 3 : if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
485 0 : return -1;
486 3 : return os_snprintf(buf, buflen, "%s", pin);
487 : }
488 :
489 0 : return -1;
490 : }
491 :
492 :
493 4 : static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
494 : {
495 : char *pos;
496 4 : char *ssid, *auth, *encr = NULL, *key = NULL;
497 :
498 4 : ssid = txt;
499 4 : pos = os_strchr(txt, ' ');
500 4 : if (!pos)
501 0 : return -1;
502 4 : *pos++ = '\0';
503 :
504 4 : auth = pos;
505 4 : pos = os_strchr(pos, ' ');
506 4 : if (pos) {
507 4 : *pos++ = '\0';
508 4 : encr = pos;
509 4 : pos = os_strchr(pos, ' ');
510 4 : if (pos) {
511 4 : *pos++ = '\0';
512 4 : key = pos;
513 : }
514 : }
515 :
516 4 : return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
517 : }
518 :
519 :
520 6 : static const char * pbc_status_str(enum pbc_status status)
521 : {
522 6 : switch (status) {
523 : case WPS_PBC_STATUS_DISABLE:
524 5 : return "Disabled";
525 : case WPS_PBC_STATUS_ACTIVE:
526 1 : return "Active";
527 : case WPS_PBC_STATUS_TIMEOUT:
528 0 : return "Timed-out";
529 : case WPS_PBC_STATUS_OVERLAP:
530 0 : return "Overlap";
531 : default:
532 0 : return "Unknown";
533 : }
534 : }
535 :
536 :
537 6 : static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
538 : char *buf, size_t buflen)
539 : {
540 : int ret;
541 : char *pos, *end;
542 :
543 6 : pos = buf;
544 6 : end = buf + buflen;
545 :
546 6 : ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
547 : pbc_status_str(hapd->wps_stats.pbc_status));
548 :
549 6 : if (os_snprintf_error(end - pos, ret))
550 0 : return pos - buf;
551 6 : pos += ret;
552 :
553 11 : ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
554 6 : (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
555 : "Success":
556 5 : (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
557 5 : "Failed" : "None")));
558 :
559 6 : if (os_snprintf_error(end - pos, ret))
560 0 : return pos - buf;
561 6 : pos += ret;
562 :
563 : /* If status == Failure - Add possible Reasons */
564 9 : if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
565 3 : hapd->wps_stats.failure_reason > 0) {
566 1 : ret = os_snprintf(pos, end - pos,
567 : "Failure Reason: %s\n",
568 : wps_ei_str(hapd->wps_stats.failure_reason));
569 :
570 1 : if (os_snprintf_error(end - pos, ret))
571 0 : return pos - buf;
572 1 : pos += ret;
573 : }
574 :
575 6 : if (hapd->wps_stats.status) {
576 24 : ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
577 24 : MAC2STR(hapd->wps_stats.peer_addr));
578 :
579 4 : if (os_snprintf_error(end - pos, ret))
580 0 : return pos - buf;
581 4 : pos += ret;
582 : }
583 :
584 6 : return pos - buf;
585 : }
586 :
587 : #endif /* CONFIG_WPS */
588 :
589 : #ifdef CONFIG_HS20
590 :
591 8 : static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
592 : const char *cmd)
593 : {
594 : u8 addr[ETH_ALEN];
595 : const char *url;
596 :
597 8 : if (hwaddr_aton(cmd, addr))
598 3 : return -1;
599 5 : url = cmd + 17;
600 5 : if (*url == '\0') {
601 1 : url = NULL;
602 : } else {
603 4 : if (*url != ' ')
604 1 : return -1;
605 3 : url++;
606 3 : if (*url == '\0')
607 0 : url = NULL;
608 : }
609 :
610 4 : return hs20_send_wnm_notification(hapd, addr, 1, url);
611 : }
612 :
613 :
614 7 : static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
615 : const char *cmd)
616 : {
617 : u8 addr[ETH_ALEN];
618 : int code, reauth_delay, ret;
619 : const char *pos;
620 : size_t url_len;
621 : struct wpabuf *req;
622 :
623 : /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
624 7 : if (hwaddr_aton(cmd, addr))
625 1 : return -1;
626 :
627 6 : pos = os_strchr(cmd, ' ');
628 6 : if (pos == NULL)
629 1 : return -1;
630 5 : pos++;
631 5 : code = atoi(pos);
632 :
633 5 : pos = os_strchr(pos, ' ');
634 5 : if (pos == NULL)
635 1 : return -1;
636 4 : pos++;
637 4 : reauth_delay = atoi(pos);
638 :
639 4 : url_len = 0;
640 4 : pos = os_strchr(pos, ' ');
641 4 : if (pos) {
642 4 : pos++;
643 4 : url_len = os_strlen(pos);
644 : }
645 :
646 4 : req = wpabuf_alloc(4 + url_len);
647 4 : if (req == NULL)
648 0 : return -1;
649 4 : wpabuf_put_u8(req, code);
650 4 : wpabuf_put_le16(req, reauth_delay);
651 4 : wpabuf_put_u8(req, url_len);
652 4 : if (pos)
653 4 : wpabuf_put_data(req, pos, url_len);
654 :
655 24 : wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
656 : " to indicate imminent deauthentication (code=%d "
657 24 : "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
658 4 : ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
659 4 : wpabuf_free(req);
660 4 : return ret;
661 : }
662 :
663 : #endif /* CONFIG_HS20 */
664 :
665 :
666 : #ifdef CONFIG_INTERWORKING
667 :
668 8 : static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
669 : const char *cmd)
670 : {
671 8 : u8 qos_map_set[16 + 2 * 21], count = 0;
672 8 : const char *pos = cmd;
673 : int val, ret;
674 :
675 : for (;;) {
676 140 : if (count == sizeof(qos_map_set)) {
677 1 : wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
678 1 : return -1;
679 : }
680 :
681 139 : val = atoi(pos);
682 139 : if (val < 0 || val > 255) {
683 1 : wpa_printf(MSG_INFO, "Invalid QoS Map Set");
684 1 : return -1;
685 : }
686 :
687 138 : qos_map_set[count++] = val;
688 138 : pos = os_strchr(pos, ',');
689 138 : if (!pos)
690 6 : break;
691 132 : pos++;
692 132 : }
693 :
694 6 : if (count < 16 || count & 1) {
695 3 : wpa_printf(MSG_INFO, "Invalid QoS Map Set");
696 3 : return -1;
697 : }
698 :
699 3 : ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
700 3 : if (ret) {
701 0 : wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
702 0 : return -1;
703 : }
704 :
705 3 : os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
706 3 : hapd->conf->qos_map_set_len = count;
707 :
708 3 : return 0;
709 : }
710 :
711 :
712 5 : static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
713 : const char *cmd)
714 : {
715 : u8 addr[ETH_ALEN];
716 : struct sta_info *sta;
717 : struct wpabuf *buf;
718 5 : u8 *qos_map_set = hapd->conf->qos_map_set;
719 5 : u8 qos_map_set_len = hapd->conf->qos_map_set_len;
720 : int ret;
721 :
722 5 : if (!qos_map_set_len) {
723 1 : wpa_printf(MSG_INFO, "QoS Map Set is not set");
724 1 : return -1;
725 : }
726 :
727 4 : if (hwaddr_aton(cmd, addr))
728 1 : return -1;
729 :
730 3 : sta = ap_get_sta(hapd, addr);
731 3 : if (sta == NULL) {
732 6 : wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
733 : "for QoS Map Configuration message",
734 6 : MAC2STR(addr));
735 1 : return -1;
736 : }
737 :
738 2 : if (!sta->qos_map_enabled) {
739 6 : wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
740 6 : "support for QoS Map", MAC2STR(addr));
741 1 : return -1;
742 : }
743 :
744 1 : buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
745 1 : if (buf == NULL)
746 0 : return -1;
747 :
748 1 : wpabuf_put_u8(buf, WLAN_ACTION_QOS);
749 1 : wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
750 :
751 : /* QoS Map Set Element */
752 1 : wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
753 1 : wpabuf_put_u8(buf, qos_map_set_len);
754 1 : wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
755 :
756 2 : ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
757 1 : wpabuf_head(buf), wpabuf_len(buf));
758 1 : wpabuf_free(buf);
759 :
760 1 : return ret;
761 : }
762 :
763 : #endif /* CONFIG_INTERWORKING */
764 :
765 :
766 : #ifdef CONFIG_WNM
767 :
768 6 : static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
769 : const char *cmd)
770 : {
771 : u8 addr[ETH_ALEN];
772 : int disassoc_timer;
773 : struct sta_info *sta;
774 :
775 6 : if (hwaddr_aton(cmd, addr))
776 1 : return -1;
777 5 : if (cmd[17] != ' ')
778 1 : return -1;
779 4 : disassoc_timer = atoi(cmd + 17);
780 :
781 4 : sta = ap_get_sta(hapd, addr);
782 4 : if (sta == NULL) {
783 6 : wpa_printf(MSG_DEBUG, "Station " MACSTR
784 : " not found for disassociation imminent message",
785 6 : MAC2STR(addr));
786 1 : return -1;
787 : }
788 :
789 3 : return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
790 : }
791 :
792 :
793 10 : static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
794 : const char *cmd)
795 : {
796 : u8 addr[ETH_ALEN];
797 : const char *url, *timerstr;
798 : int disassoc_timer;
799 : struct sta_info *sta;
800 :
801 10 : if (hwaddr_aton(cmd, addr))
802 1 : return -1;
803 :
804 9 : sta = ap_get_sta(hapd, addr);
805 9 : if (sta == NULL) {
806 6 : wpa_printf(MSG_DEBUG, "Station " MACSTR
807 : " not found for ESS disassociation imminent message",
808 6 : MAC2STR(addr));
809 1 : return -1;
810 : }
811 :
812 8 : timerstr = cmd + 17;
813 8 : if (*timerstr != ' ')
814 1 : return -1;
815 7 : timerstr++;
816 7 : disassoc_timer = atoi(timerstr);
817 7 : if (disassoc_timer < 0 || disassoc_timer > 65535)
818 1 : return -1;
819 :
820 6 : url = os_strchr(timerstr, ' ');
821 6 : if (url == NULL)
822 1 : return -1;
823 5 : url++;
824 :
825 5 : return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
826 : }
827 :
828 :
829 32 : static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
830 : const char *cmd)
831 : {
832 : u8 addr[ETH_ALEN];
833 : const char *pos, *end;
834 32 : int disassoc_timer = 0;
835 : struct sta_info *sta;
836 32 : u8 req_mode = 0, valid_int = 0x01;
837 : u8 bss_term_dur[12];
838 32 : char *url = NULL;
839 : int ret;
840 : u8 nei_rep[1000];
841 32 : u8 *nei_pos = nei_rep;
842 : u8 mbo[10];
843 32 : size_t mbo_len = 0;
844 :
845 32 : if (hwaddr_aton(cmd, addr)) {
846 0 : wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
847 0 : return -1;
848 : }
849 :
850 32 : sta = ap_get_sta(hapd, addr);
851 32 : if (sta == NULL) {
852 0 : wpa_printf(MSG_DEBUG, "Station " MACSTR
853 : " not found for BSS TM Request message",
854 0 : MAC2STR(addr));
855 0 : return -1;
856 : }
857 :
858 32 : pos = os_strstr(cmd, " disassoc_timer=");
859 32 : if (pos) {
860 2 : pos += 16;
861 2 : disassoc_timer = atoi(pos);
862 2 : if (disassoc_timer < 0 || disassoc_timer > 65535) {
863 0 : wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
864 0 : return -1;
865 : }
866 : }
867 :
868 32 : pos = os_strstr(cmd, " valid_int=");
869 32 : if (pos) {
870 10 : pos += 11;
871 10 : valid_int = atoi(pos);
872 : }
873 :
874 32 : pos = os_strstr(cmd, " bss_term=");
875 32 : if (pos) {
876 0 : pos += 10;
877 0 : req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
878 : /* TODO: TSF configurable/learnable */
879 0 : bss_term_dur[0] = 4; /* Subelement ID */
880 0 : bss_term_dur[1] = 10; /* Length */
881 0 : os_memset(bss_term_dur, 2, 8);
882 0 : end = os_strchr(pos, ',');
883 0 : if (end == NULL) {
884 0 : wpa_printf(MSG_DEBUG, "Invalid bss_term data");
885 0 : return -1;
886 : }
887 0 : end++;
888 0 : WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
889 : }
890 :
891 :
892 : /*
893 : * BSS Transition Candidate List Entries - Neighbor Report elements
894 : * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
895 : * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
896 : */
897 32 : pos = cmd;
898 172 : while (pos) {
899 : u8 *nei_start;
900 : long int val;
901 : char *endptr, *tmp;
902 :
903 133 : pos = os_strstr(pos, " neighbor=");
904 133 : if (!pos)
905 25 : break;
906 108 : if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) {
907 0 : wpa_printf(MSG_DEBUG,
908 : "Not enough room for additional neighbor");
909 0 : return -1;
910 : }
911 108 : pos += 10;
912 :
913 108 : nei_start = nei_pos;
914 108 : *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
915 108 : nei_pos++; /* length to be filled in */
916 :
917 108 : if (hwaddr_aton(pos, nei_pos)) {
918 0 : wpa_printf(MSG_DEBUG, "Invalid BSSID");
919 0 : return -1;
920 : }
921 108 : nei_pos += ETH_ALEN;
922 108 : pos += 17;
923 108 : if (*pos != ',') {
924 0 : wpa_printf(MSG_DEBUG, "Missing BSSID Information");
925 0 : return -1;
926 : }
927 108 : pos++;
928 :
929 108 : val = strtol(pos, &endptr, 0);
930 108 : WPA_PUT_LE32(nei_pos, val);
931 108 : nei_pos += 4;
932 108 : if (*endptr != ',') {
933 0 : wpa_printf(MSG_DEBUG, "Missing Operating Class");
934 0 : return -1;
935 : }
936 108 : pos = endptr + 1;
937 :
938 108 : *nei_pos++ = atoi(pos); /* Operating Class */
939 108 : pos = os_strchr(pos, ',');
940 108 : if (pos == NULL) {
941 0 : wpa_printf(MSG_DEBUG, "Missing Channel Number");
942 0 : return -1;
943 : }
944 108 : pos++;
945 :
946 108 : *nei_pos++ = atoi(pos); /* Channel Number */
947 108 : pos = os_strchr(pos, ',');
948 108 : if (pos == NULL) {
949 0 : wpa_printf(MSG_DEBUG, "Missing PHY Type");
950 0 : return -1;
951 : }
952 108 : pos++;
953 :
954 108 : *nei_pos++ = atoi(pos); /* PHY Type */
955 108 : end = os_strchr(pos, ' ');
956 108 : tmp = os_strchr(pos, ',');
957 108 : if (tmp && (!end || tmp < end)) {
958 : /* Optional Subelements (hexdump) */
959 : size_t len;
960 :
961 23 : pos = tmp + 1;
962 23 : end = os_strchr(pos, ' ');
963 23 : if (end)
964 16 : len = end - pos;
965 : else
966 7 : len = os_strlen(pos);
967 23 : if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) {
968 0 : wpa_printf(MSG_DEBUG,
969 : "Not enough room for neighbor subelements");
970 0 : return -1;
971 : }
972 46 : if (len & 0x01 ||
973 23 : hexstr2bin(pos, nei_pos, len / 2) < 0) {
974 0 : wpa_printf(MSG_DEBUG,
975 : "Invalid neighbor subelement info");
976 0 : return -1;
977 : }
978 23 : nei_pos += len / 2;
979 23 : pos = end;
980 : }
981 :
982 108 : nei_start[1] = nei_pos - nei_start - 2;
983 : }
984 :
985 32 : pos = os_strstr(cmd, " url=");
986 32 : if (pos) {
987 : size_t len;
988 0 : pos += 5;
989 0 : end = os_strchr(pos, ' ');
990 0 : if (end)
991 0 : len = end - pos;
992 : else
993 0 : len = os_strlen(pos);
994 0 : url = os_malloc(len + 1);
995 0 : if (url == NULL)
996 0 : return -1;
997 0 : os_memcpy(url, pos, len);
998 0 : url[len] = '\0';
999 0 : req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
1000 : }
1001 :
1002 32 : if (os_strstr(cmd, " pref=1"))
1003 25 : req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
1004 32 : if (os_strstr(cmd, " abridged=1"))
1005 10 : req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1006 32 : if (os_strstr(cmd, " disassoc_imminent=1"))
1007 1 : req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
1008 :
1009 : #ifdef CONFIG_MBO
1010 32 : pos = os_strstr(cmd, "mbo=");
1011 32 : if (pos) {
1012 : unsigned int mbo_reason, cell_pref, reassoc_delay;
1013 3 : u8 *mbo_pos = mbo;
1014 :
1015 3 : ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
1016 : &reassoc_delay, &cell_pref);
1017 3 : if (ret != 3) {
1018 0 : wpa_printf(MSG_DEBUG,
1019 : "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
1020 2 : return -1;
1021 : }
1022 :
1023 3 : if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
1024 1 : wpa_printf(MSG_DEBUG,
1025 : "Invalid MBO transition reason code %u",
1026 : mbo_reason);
1027 1 : return -1;
1028 : }
1029 :
1030 : /* Valid values for Cellular preference are: 0, 1, 255 */
1031 2 : if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
1032 0 : wpa_printf(MSG_DEBUG,
1033 : "Invalid MBO cellular capability %u",
1034 : cell_pref);
1035 0 : return -1;
1036 : }
1037 :
1038 4 : if (reassoc_delay > 65535 ||
1039 4 : (reassoc_delay &&
1040 2 : !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
1041 1 : wpa_printf(MSG_DEBUG,
1042 : "MBO: Assoc retry delay is only valid in disassoc imminent mode");
1043 1 : return -1;
1044 : }
1045 :
1046 1 : *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
1047 1 : *mbo_pos++ = 1;
1048 1 : *mbo_pos++ = mbo_reason;
1049 1 : *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
1050 1 : *mbo_pos++ = 1;
1051 1 : *mbo_pos++ = cell_pref;
1052 :
1053 1 : if (reassoc_delay) {
1054 1 : *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
1055 1 : *mbo_pos++ = 2;
1056 1 : WPA_PUT_LE16(mbo_pos, reassoc_delay);
1057 1 : mbo_pos += 2;
1058 : }
1059 :
1060 1 : mbo_len = mbo_pos - mbo;
1061 : }
1062 : #endif /* CONFIG_MBO */
1063 :
1064 60 : ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
1065 : valid_int, bss_term_dur, url,
1066 : nei_pos > nei_rep ? nei_rep : NULL,
1067 30 : nei_pos - nei_rep, mbo_len ? mbo : NULL,
1068 : mbo_len);
1069 30 : os_free(url);
1070 30 : return ret;
1071 : }
1072 :
1073 : #endif /* CONFIG_WNM */
1074 :
1075 :
1076 17 : static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
1077 : char *buf, size_t buflen)
1078 : {
1079 17 : int ret = 0;
1080 : char *pos, *end;
1081 :
1082 17 : pos = buf;
1083 17 : end = buf + buflen;
1084 :
1085 : WPA_ASSERT(hapd->conf->wpa_key_mgmt);
1086 :
1087 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
1088 7 : ret = os_snprintf(pos, end - pos, "WPA-PSK ");
1089 7 : if (os_snprintf_error(end - pos, ret))
1090 0 : return pos - buf;
1091 7 : pos += ret;
1092 : }
1093 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1094 3 : ret = os_snprintf(pos, end - pos, "WPA-EAP ");
1095 3 : if (os_snprintf_error(end - pos, ret))
1096 0 : return pos - buf;
1097 3 : pos += ret;
1098 : }
1099 : #ifdef CONFIG_IEEE80211R
1100 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1101 1 : ret = os_snprintf(pos, end - pos, "FT-PSK ");
1102 1 : if (os_snprintf_error(end - pos, ret))
1103 0 : return pos - buf;
1104 1 : pos += ret;
1105 : }
1106 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1107 3 : ret = os_snprintf(pos, end - pos, "FT-EAP ");
1108 3 : if (os_snprintf_error(end - pos, ret))
1109 0 : return pos - buf;
1110 3 : pos += ret;
1111 : }
1112 : #ifdef CONFIG_SAE
1113 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
1114 1 : ret = os_snprintf(pos, end - pos, "FT-SAE ");
1115 1 : if (os_snprintf_error(end - pos, ret))
1116 0 : return pos - buf;
1117 1 : pos += ret;
1118 : }
1119 : #endif /* CONFIG_SAE */
1120 : #endif /* CONFIG_IEEE80211R */
1121 : #ifdef CONFIG_IEEE80211W
1122 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1123 1 : ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
1124 1 : if (os_snprintf_error(end - pos, ret))
1125 0 : return pos - buf;
1126 1 : pos += ret;
1127 : }
1128 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1129 1 : ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
1130 1 : if (os_snprintf_error(end - pos, ret))
1131 0 : return pos - buf;
1132 1 : pos += ret;
1133 : }
1134 : #endif /* CONFIG_IEEE80211W */
1135 : #ifdef CONFIG_SAE
1136 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
1137 1 : ret = os_snprintf(pos, end - pos, "SAE ");
1138 1 : if (os_snprintf_error(end - pos, ret))
1139 0 : return pos - buf;
1140 1 : pos += ret;
1141 : }
1142 : #endif /* CONFIG_SAE */
1143 17 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
1144 0 : ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
1145 0 : if (os_snprintf_error(end - pos, ret))
1146 0 : return pos - buf;
1147 0 : pos += ret;
1148 : }
1149 17 : if (hapd->conf->wpa_key_mgmt &
1150 : WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
1151 0 : ret = os_snprintf(pos, end - pos,
1152 : "WPA-EAP-SUITE-B-192 ");
1153 0 : if (os_snprintf_error(end - pos, ret))
1154 0 : return pos - buf;
1155 0 : pos += ret;
1156 : }
1157 :
1158 17 : if (pos > buf && *(pos - 1) == ' ') {
1159 17 : *(pos - 1) = '\0';
1160 17 : pos--;
1161 : }
1162 :
1163 17 : return pos - buf;
1164 : }
1165 :
1166 :
1167 16 : static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
1168 : char *buf, size_t buflen)
1169 : {
1170 : int ret;
1171 : char *pos, *end;
1172 :
1173 16 : pos = buf;
1174 16 : end = buf + buflen;
1175 :
1176 128 : ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
1177 : "ssid=%s\n",
1178 96 : MAC2STR(hapd->own_addr),
1179 16 : wpa_ssid_txt(hapd->conf->ssid.ssid,
1180 16 : hapd->conf->ssid.ssid_len));
1181 16 : if (os_snprintf_error(end - pos, ret))
1182 0 : return pos - buf;
1183 16 : pos += ret;
1184 :
1185 : #ifdef CONFIG_WPS
1186 17 : ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
1187 16 : hapd->conf->wps_state == 0 ? "disabled" :
1188 1 : (hapd->conf->wps_state == 1 ? "not configured" :
1189 : "configured"));
1190 16 : if (os_snprintf_error(end - pos, ret))
1191 0 : return pos - buf;
1192 16 : pos += ret;
1193 :
1194 17 : if (hapd->conf->wps_state && hapd->conf->wpa &&
1195 1 : hapd->conf->ssid.wpa_passphrase) {
1196 1 : ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
1197 1 : hapd->conf->ssid.wpa_passphrase);
1198 1 : if (os_snprintf_error(end - pos, ret))
1199 0 : return pos - buf;
1200 1 : pos += ret;
1201 : }
1202 :
1203 17 : if (hapd->conf->wps_state && hapd->conf->wpa &&
1204 2 : hapd->conf->ssid.wpa_psk &&
1205 1 : hapd->conf->ssid.wpa_psk->group) {
1206 : char hex[PMK_LEN * 2 + 1];
1207 1 : wpa_snprintf_hex(hex, sizeof(hex),
1208 1 : hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
1209 1 : ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
1210 1 : if (os_snprintf_error(end - pos, ret))
1211 0 : return pos - buf;
1212 1 : pos += ret;
1213 : }
1214 : #endif /* CONFIG_WPS */
1215 :
1216 16 : if (hapd->conf->wpa) {
1217 15 : ret = os_snprintf(pos, end - pos, "wpa=%d\n", hapd->conf->wpa);
1218 15 : if (os_snprintf_error(end - pos, ret))
1219 0 : return pos - buf;
1220 15 : pos += ret;
1221 : }
1222 :
1223 16 : if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
1224 15 : ret = os_snprintf(pos, end - pos, "key_mgmt=");
1225 15 : if (os_snprintf_error(end - pos, ret))
1226 0 : return pos - buf;
1227 15 : pos += ret;
1228 :
1229 15 : pos += hostapd_ctrl_iface_get_key_mgmt(hapd, pos, end - pos);
1230 :
1231 15 : ret = os_snprintf(pos, end - pos, "\n");
1232 15 : if (os_snprintf_error(end - pos, ret))
1233 0 : return pos - buf;
1234 15 : pos += ret;
1235 : }
1236 :
1237 16 : if (hapd->conf->wpa) {
1238 15 : ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
1239 15 : wpa_cipher_txt(hapd->conf->wpa_group));
1240 15 : if (os_snprintf_error(end - pos, ret))
1241 0 : return pos - buf;
1242 15 : pos += ret;
1243 : }
1244 :
1245 16 : if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
1246 15 : ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
1247 15 : if (os_snprintf_error(end - pos, ret))
1248 0 : return pos - buf;
1249 15 : pos += ret;
1250 :
1251 15 : ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
1252 : " ");
1253 15 : if (ret < 0)
1254 0 : return pos - buf;
1255 15 : pos += ret;
1256 :
1257 15 : ret = os_snprintf(pos, end - pos, "\n");
1258 15 : if (os_snprintf_error(end - pos, ret))
1259 0 : return pos - buf;
1260 15 : pos += ret;
1261 : }
1262 :
1263 16 : if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
1264 2 : ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
1265 2 : if (os_snprintf_error(end - pos, ret))
1266 0 : return pos - buf;
1267 2 : pos += ret;
1268 :
1269 2 : ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
1270 : " ");
1271 2 : if (ret < 0)
1272 0 : return pos - buf;
1273 2 : pos += ret;
1274 :
1275 2 : ret = os_snprintf(pos, end - pos, "\n");
1276 2 : if (os_snprintf_error(end - pos, ret))
1277 0 : return pos - buf;
1278 2 : pos += ret;
1279 : }
1280 :
1281 16 : return pos - buf;
1282 : }
1283 :
1284 :
1285 31291 : static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1286 : {
1287 : char *value;
1288 31291 : int ret = 0;
1289 :
1290 31291 : value = os_strchr(cmd, ' ');
1291 31291 : if (value == NULL)
1292 0 : return -1;
1293 31291 : *value++ = '\0';
1294 :
1295 31291 : wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
1296 : if (0) {
1297 : #ifdef CONFIG_WPS_TESTING
1298 31291 : } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
1299 : long int val;
1300 5 : val = strtol(value, NULL, 0);
1301 5 : if (val < 0 || val > 0xff) {
1302 0 : ret = -1;
1303 0 : wpa_printf(MSG_DEBUG, "WPS: Invalid "
1304 : "wps_version_number %ld", val);
1305 : } else {
1306 5 : wps_version_number = val;
1307 10 : wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
1308 : "version %u.%u",
1309 5 : (wps_version_number & 0xf0) >> 4,
1310 : wps_version_number & 0x0f);
1311 5 : hostapd_wps_update_ie(hapd);
1312 : }
1313 31286 : } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
1314 0 : wps_testing_dummy_cred = atoi(value);
1315 0 : wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
1316 : wps_testing_dummy_cred);
1317 31286 : } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
1318 1 : wps_corrupt_pkhash = atoi(value);
1319 1 : wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
1320 : wps_corrupt_pkhash);
1321 : #endif /* CONFIG_WPS_TESTING */
1322 : #ifdef CONFIG_INTERWORKING
1323 31285 : } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
1324 8 : int val = atoi(value);
1325 8 : if (val <= 0)
1326 0 : ret = -1;
1327 : else
1328 8 : hapd->gas_frag_limit = val;
1329 : #endif /* CONFIG_INTERWORKING */
1330 : #ifdef CONFIG_TESTING_OPTIONS
1331 31277 : } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
1332 197 : hapd->ext_mgmt_frame_handling = atoi(value);
1333 31080 : } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
1334 177 : hapd->ext_eapol_frame_io = atoi(value);
1335 : #endif /* CONFIG_TESTING_OPTIONS */
1336 : #ifdef CONFIG_MBO
1337 30903 : } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
1338 : int val;
1339 :
1340 7 : if (!hapd->conf->mbo_enabled)
1341 0 : return -1;
1342 :
1343 7 : val = atoi(value);
1344 7 : if (val < 0 || val > 1)
1345 1 : return -1;
1346 :
1347 6 : hapd->mbo_assoc_disallow = val;
1348 6 : ieee802_11_update_beacons(hapd->iface);
1349 :
1350 : /*
1351 : * TODO: Need to configure drivers that do AP MLME offload with
1352 : * disallowing station logic.
1353 : */
1354 : #endif /* CONFIG_MBO */
1355 : } else {
1356 : struct sta_info *sta;
1357 : struct vlan_description vlan_id;
1358 :
1359 30896 : ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
1360 30896 : if (ret)
1361 176 : return ret;
1362 :
1363 30720 : if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
1364 4 : for (sta = hapd->sta_list; sta; sta = sta->next) {
1365 4 : if (hostapd_maclist_found(
1366 2 : hapd->conf->deny_mac,
1367 2 : hapd->conf->num_deny_mac, sta->addr,
1368 1 : &vlan_id) &&
1369 1 : (!vlan_id.notempty ||
1370 0 : !vlan_compare(&vlan_id, sta->vlan_desc)))
1371 1 : ap_sta_disconnect(
1372 1 : hapd, sta, sta->addr,
1373 : WLAN_REASON_UNSPECIFIED);
1374 : }
1375 30721 : } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED &&
1376 3 : os_strcasecmp(cmd, "accept_mac_file") == 0) {
1377 3 : for (sta = hapd->sta_list; sta; sta = sta->next) {
1378 4 : if (!hostapd_maclist_found(
1379 2 : hapd->conf->accept_mac,
1380 2 : hapd->conf->num_accept_mac,
1381 3 : sta->addr, &vlan_id) ||
1382 1 : (vlan_id.notempty &&
1383 0 : vlan_compare(&vlan_id, sta->vlan_desc)))
1384 1 : ap_sta_disconnect(
1385 1 : hapd, sta, sta->addr,
1386 : WLAN_REASON_UNSPECIFIED);
1387 : }
1388 : }
1389 : }
1390 :
1391 31114 : return ret;
1392 : }
1393 :
1394 :
1395 14 : static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1396 : char *buf, size_t buflen)
1397 : {
1398 : int res;
1399 :
1400 14 : wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1401 :
1402 14 : if (os_strcmp(cmd, "version") == 0) {
1403 2 : res = os_snprintf(buf, buflen, "%s", VERSION_STR);
1404 2 : if (os_snprintf_error(buflen, res))
1405 0 : return -1;
1406 2 : return res;
1407 12 : } else if (os_strcmp(cmd, "tls_library") == 0) {
1408 11 : res = tls_get_library_version(buf, buflen);
1409 11 : if (os_snprintf_error(buflen, res))
1410 0 : return -1;
1411 11 : return res;
1412 : }
1413 :
1414 1 : return -1;
1415 : }
1416 :
1417 :
1418 2004 : static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1419 : {
1420 2004 : if (hostapd_enable_iface(iface) < 0) {
1421 37 : wpa_printf(MSG_ERROR, "Enabling of interface failed");
1422 37 : return -1;
1423 : }
1424 1967 : return 0;
1425 : }
1426 :
1427 :
1428 2 : static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1429 : {
1430 2 : if (hostapd_reload_iface(iface) < 0) {
1431 0 : wpa_printf(MSG_ERROR, "Reloading of interface failed");
1432 0 : return -1;
1433 : }
1434 2 : return 0;
1435 : }
1436 :
1437 :
1438 198 : static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1439 : {
1440 198 : if (hostapd_disable_iface(iface) < 0) {
1441 6 : wpa_printf(MSG_ERROR, "Disabling of interface failed");
1442 6 : return -1;
1443 : }
1444 192 : return 0;
1445 : }
1446 :
1447 :
1448 : #ifdef CONFIG_TESTING_OPTIONS
1449 :
1450 4 : static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
1451 : {
1452 : union wpa_event_data data;
1453 : char *pos, *param;
1454 : enum wpa_event_type event;
1455 :
1456 4 : wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
1457 :
1458 4 : os_memset(&data, 0, sizeof(data));
1459 :
1460 4 : param = os_strchr(cmd, ' ');
1461 4 : if (param == NULL)
1462 0 : return -1;
1463 4 : *param++ = '\0';
1464 :
1465 4 : if (os_strcmp(cmd, "DETECTED") == 0)
1466 4 : event = EVENT_DFS_RADAR_DETECTED;
1467 0 : else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
1468 0 : event = EVENT_DFS_CAC_FINISHED;
1469 0 : else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
1470 0 : event = EVENT_DFS_CAC_ABORTED;
1471 0 : else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
1472 0 : event = EVENT_DFS_NOP_FINISHED;
1473 : else {
1474 0 : wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
1475 : cmd);
1476 0 : return -1;
1477 : }
1478 :
1479 4 : pos = os_strstr(param, "freq=");
1480 4 : if (pos)
1481 4 : data.dfs_event.freq = atoi(pos + 5);
1482 :
1483 4 : pos = os_strstr(param, "ht_enabled=1");
1484 4 : if (pos)
1485 4 : data.dfs_event.ht_enabled = 1;
1486 :
1487 4 : pos = os_strstr(param, "chan_offset=");
1488 4 : if (pos)
1489 0 : data.dfs_event.chan_offset = atoi(pos + 12);
1490 :
1491 4 : pos = os_strstr(param, "chan_width=");
1492 4 : if (pos)
1493 4 : data.dfs_event.chan_width = atoi(pos + 11);
1494 :
1495 4 : pos = os_strstr(param, "cf1=");
1496 4 : if (pos)
1497 0 : data.dfs_event.cf1 = atoi(pos + 4);
1498 :
1499 4 : pos = os_strstr(param, "cf2=");
1500 4 : if (pos)
1501 0 : data.dfs_event.cf2 = atoi(pos + 4);
1502 :
1503 4 : wpa_supplicant_event(hapd, event, &data);
1504 :
1505 4 : return 0;
1506 : }
1507 :
1508 :
1509 457 : static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
1510 : {
1511 : size_t len;
1512 : u8 *buf;
1513 : int res;
1514 :
1515 457 : wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
1516 :
1517 457 : len = os_strlen(cmd);
1518 457 : if (len & 1)
1519 0 : return -1;
1520 457 : len /= 2;
1521 :
1522 457 : buf = os_malloc(len);
1523 457 : if (buf == NULL)
1524 0 : return -1;
1525 :
1526 457 : if (hexstr2bin(cmd, buf, len) < 0) {
1527 0 : os_free(buf);
1528 0 : return -1;
1529 : }
1530 :
1531 457 : res = hostapd_drv_send_mlme(hapd, buf, len, 0);
1532 457 : os_free(buf);
1533 457 : return res;
1534 : }
1535 :
1536 :
1537 318 : static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
1538 : {
1539 : char *pos;
1540 : u8 src[ETH_ALEN], *buf;
1541 : int used;
1542 : size_t len;
1543 :
1544 318 : wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
1545 :
1546 318 : pos = cmd;
1547 318 : used = hwaddr_aton2(pos, src);
1548 318 : if (used < 0)
1549 0 : return -1;
1550 318 : pos += used;
1551 954 : while (*pos == ' ')
1552 318 : pos++;
1553 :
1554 318 : len = os_strlen(pos);
1555 318 : if (len & 1)
1556 0 : return -1;
1557 318 : len /= 2;
1558 :
1559 318 : buf = os_malloc(len);
1560 318 : if (buf == NULL)
1561 0 : return -1;
1562 :
1563 318 : if (hexstr2bin(pos, buf, len) < 0) {
1564 0 : os_free(buf);
1565 0 : return -1;
1566 : }
1567 :
1568 318 : ieee802_1x_receive(hapd, src, buf, len);
1569 318 : os_free(buf);
1570 :
1571 318 : return 0;
1572 : }
1573 :
1574 :
1575 1425 : static u16 ipv4_hdr_checksum(const void *buf, size_t len)
1576 : {
1577 : size_t i;
1578 1425 : u32 sum = 0;
1579 1425 : const u16 *pos = buf;
1580 :
1581 15675 : for (i = 0; i < len / 2; i++)
1582 14250 : sum += *pos++;
1583 :
1584 4275 : while (sum >> 16)
1585 1425 : sum = (sum & 0xffff) + (sum >> 16);
1586 :
1587 1425 : return sum ^ 0xffff;
1588 : }
1589 :
1590 :
1591 : #define HWSIM_PACKETLEN 1500
1592 : #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
1593 :
1594 1422 : static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
1595 : size_t len)
1596 : {
1597 1422 : struct hostapd_data *hapd = ctx;
1598 : const struct ether_header *eth;
1599 : struct iphdr ip;
1600 : const u8 *pos;
1601 : unsigned int i;
1602 :
1603 1422 : if (len != HWSIM_PACKETLEN)
1604 0 : return;
1605 :
1606 1422 : eth = (const struct ether_header *) buf;
1607 1422 : os_memcpy(&ip, eth + 1, sizeof(ip));
1608 1422 : pos = &buf[sizeof(*eth) + sizeof(ip)];
1609 :
1610 2844 : if (ip.ihl != 5 || ip.version != 4 ||
1611 1422 : ntohs(ip.tot_len) != HWSIM_IP_LEN)
1612 0 : return;
1613 :
1614 2086074 : for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
1615 2084652 : if (*pos != (u8) i)
1616 0 : return;
1617 2084652 : pos++;
1618 : }
1619 :
1620 17064 : wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
1621 17064 : MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
1622 : }
1623 :
1624 :
1625 1330 : static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
1626 : char *cmd)
1627 : {
1628 1330 : int enabled = atoi(cmd);
1629 : char *pos;
1630 : const char *ifname;
1631 :
1632 1330 : if (!enabled) {
1633 665 : if (hapd->l2_test) {
1634 665 : l2_packet_deinit(hapd->l2_test);
1635 665 : hapd->l2_test = NULL;
1636 665 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1637 : "test data: Disabled");
1638 : }
1639 665 : return 0;
1640 : }
1641 :
1642 665 : if (hapd->l2_test)
1643 0 : return 0;
1644 :
1645 665 : pos = os_strstr(cmd, " ifname=");
1646 665 : if (pos)
1647 60 : ifname = pos + 8;
1648 : else
1649 605 : ifname = hapd->conf->iface;
1650 :
1651 665 : hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
1652 : ETHERTYPE_IP, hostapd_data_test_rx,
1653 : hapd, 1);
1654 665 : if (hapd->l2_test == NULL)
1655 0 : return -1;
1656 :
1657 665 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
1658 :
1659 665 : return 0;
1660 : }
1661 :
1662 :
1663 1425 : static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
1664 : {
1665 : u8 dst[ETH_ALEN], src[ETH_ALEN];
1666 : char *pos;
1667 : int used;
1668 : long int val;
1669 : u8 tos;
1670 : u8 buf[2 + HWSIM_PACKETLEN];
1671 : struct ether_header *eth;
1672 : struct iphdr *ip;
1673 : u8 *dpos;
1674 : unsigned int i;
1675 :
1676 1425 : if (hapd->l2_test == NULL)
1677 0 : return -1;
1678 :
1679 : /* format: <dst> <src> <tos> */
1680 :
1681 1425 : pos = cmd;
1682 1425 : used = hwaddr_aton2(pos, dst);
1683 1425 : if (used < 0)
1684 0 : return -1;
1685 1425 : pos += used;
1686 4275 : while (*pos == ' ')
1687 1425 : pos++;
1688 1425 : used = hwaddr_aton2(pos, src);
1689 1425 : if (used < 0)
1690 0 : return -1;
1691 1425 : pos += used;
1692 :
1693 1425 : val = strtol(pos, NULL, 0);
1694 1425 : if (val < 0 || val > 0xff)
1695 0 : return -1;
1696 1425 : tos = val;
1697 :
1698 1425 : eth = (struct ether_header *) &buf[2];
1699 1425 : os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
1700 1425 : os_memcpy(eth->ether_shost, src, ETH_ALEN);
1701 1425 : eth->ether_type = htons(ETHERTYPE_IP);
1702 1425 : ip = (struct iphdr *) (eth + 1);
1703 1425 : os_memset(ip, 0, sizeof(*ip));
1704 1425 : ip->ihl = 5;
1705 1425 : ip->version = 4;
1706 1425 : ip->ttl = 64;
1707 1425 : ip->tos = tos;
1708 1425 : ip->tot_len = htons(HWSIM_IP_LEN);
1709 1425 : ip->protocol = 1;
1710 1425 : ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
1711 1425 : ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
1712 1425 : ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
1713 1425 : dpos = (u8 *) (ip + 1);
1714 2090475 : for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
1715 2089050 : *dpos++ = i;
1716 :
1717 1425 : if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
1718 : HWSIM_PACKETLEN) < 0)
1719 0 : return -1;
1720 :
1721 1425 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
1722 : " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
1723 :
1724 1425 : return 0;
1725 : }
1726 :
1727 :
1728 59 : static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
1729 : char *cmd)
1730 : {
1731 : u8 *buf;
1732 : struct ether_header *eth;
1733 59 : struct l2_packet_data *l2 = NULL;
1734 : size_t len;
1735 : u16 ethertype;
1736 59 : int res = -1;
1737 59 : const char *ifname = hapd->conf->iface;
1738 :
1739 59 : if (os_strncmp(cmd, "ifname=", 7) == 0) {
1740 53 : cmd += 7;
1741 53 : ifname = cmd;
1742 53 : cmd = os_strchr(cmd, ' ');
1743 53 : if (cmd == NULL)
1744 0 : return -1;
1745 53 : *cmd++ = '\0';
1746 : }
1747 :
1748 59 : len = os_strlen(cmd);
1749 59 : if (len & 1 || len < ETH_HLEN * 2)
1750 0 : return -1;
1751 59 : len /= 2;
1752 :
1753 59 : buf = os_malloc(len);
1754 59 : if (buf == NULL)
1755 0 : return -1;
1756 :
1757 59 : if (hexstr2bin(cmd, buf, len) < 0)
1758 0 : goto done;
1759 :
1760 59 : eth = (struct ether_header *) buf;
1761 59 : ethertype = ntohs(eth->ether_type);
1762 :
1763 59 : l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
1764 : hostapd_data_test_rx, hapd, 1);
1765 59 : if (l2 == NULL)
1766 0 : goto done;
1767 :
1768 59 : res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
1769 59 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
1770 : done:
1771 59 : if (l2)
1772 59 : l2_packet_deinit(l2);
1773 59 : os_free(buf);
1774 :
1775 59 : return res < 0 ? -1 : 0;
1776 : }
1777 :
1778 :
1779 853 : static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
1780 : {
1781 : #ifdef WPA_TRACE_BFD
1782 : char *pos;
1783 :
1784 853 : wpa_trace_fail_after = atoi(cmd);
1785 853 : pos = os_strchr(cmd, ':');
1786 853 : if (pos) {
1787 853 : pos++;
1788 853 : os_strlcpy(wpa_trace_fail_func, pos,
1789 : sizeof(wpa_trace_fail_func));
1790 : } else {
1791 0 : wpa_trace_fail_after = 0;
1792 : }
1793 :
1794 853 : return 0;
1795 : #else /* WPA_TRACE_BFD */
1796 : return -1;
1797 : #endif /* WPA_TRACE_BFD */
1798 : }
1799 :
1800 :
1801 611 : static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
1802 : char *buf, size_t buflen)
1803 : {
1804 : #ifdef WPA_TRACE_BFD
1805 611 : return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
1806 : wpa_trace_fail_func);
1807 : #else /* WPA_TRACE_BFD */
1808 : return -1;
1809 : #endif /* WPA_TRACE_BFD */
1810 : }
1811 :
1812 :
1813 9 : static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
1814 : {
1815 : #ifdef WPA_TRACE_BFD
1816 : char *pos;
1817 :
1818 9 : wpa_trace_test_fail_after = atoi(cmd);
1819 9 : pos = os_strchr(cmd, ':');
1820 9 : if (pos) {
1821 9 : pos++;
1822 9 : os_strlcpy(wpa_trace_test_fail_func, pos,
1823 : sizeof(wpa_trace_test_fail_func));
1824 : } else {
1825 0 : wpa_trace_test_fail_after = 0;
1826 : }
1827 :
1828 9 : return 0;
1829 : #else /* WPA_TRACE_BFD */
1830 : return -1;
1831 : #endif /* WPA_TRACE_BFD */
1832 : }
1833 :
1834 :
1835 9 : static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
1836 : char *buf, size_t buflen)
1837 : {
1838 : #ifdef WPA_TRACE_BFD
1839 9 : return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
1840 : wpa_trace_test_fail_func);
1841 : #else /* WPA_TRACE_BFD */
1842 : return -1;
1843 : #endif /* WPA_TRACE_BFD */
1844 : }
1845 :
1846 : #endif /* CONFIG_TESTING_OPTIONS */
1847 :
1848 :
1849 33 : static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
1850 : char *pos)
1851 : {
1852 : #ifdef NEED_AP_MLME
1853 : struct csa_settings settings;
1854 : int ret;
1855 : unsigned int i;
1856 :
1857 33 : ret = hostapd_parse_csa_settings(pos, &settings);
1858 33 : if (ret)
1859 3 : return ret;
1860 :
1861 49 : for (i = 0; i < iface->num_bss; i++) {
1862 30 : ret = hostapd_switch_channel(iface->bss[i], &settings);
1863 30 : if (ret) {
1864 : /* FIX: What do we do if CSA fails in the middle of
1865 : * submitting multi-BSS CSA requests? */
1866 11 : return ret;
1867 : }
1868 : }
1869 :
1870 19 : return 0;
1871 : #else /* NEED_AP_MLME */
1872 : return -1;
1873 : #endif /* NEED_AP_MLME */
1874 : }
1875 :
1876 :
1877 15 : static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
1878 : int reply_size, const char *param)
1879 : {
1880 : #ifdef RADIUS_SERVER
1881 15 : if (os_strcmp(param, "radius_server") == 0) {
1882 13 : return radius_server_get_mib(hapd->radius_srv, reply,
1883 : reply_size);
1884 : }
1885 : #endif /* RADIUS_SERVER */
1886 2 : return -1;
1887 : }
1888 :
1889 :
1890 1 : static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
1891 : char *buf, size_t buflen)
1892 : {
1893 : int ret;
1894 : char *pos;
1895 1 : u8 *data = NULL;
1896 : unsigned int vendor_id, subcmd;
1897 : struct wpabuf *reply;
1898 1 : size_t data_len = 0;
1899 :
1900 : /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
1901 1 : vendor_id = strtoul(cmd, &pos, 16);
1902 1 : if (!isblank((unsigned char) *pos))
1903 0 : return -EINVAL;
1904 :
1905 1 : subcmd = strtoul(pos, &pos, 10);
1906 :
1907 1 : if (*pos != '\0') {
1908 1 : if (!isblank((unsigned char) *pos++))
1909 0 : return -EINVAL;
1910 1 : data_len = os_strlen(pos);
1911 : }
1912 :
1913 1 : if (data_len) {
1914 1 : data_len /= 2;
1915 1 : data = os_malloc(data_len);
1916 1 : if (!data)
1917 0 : return -ENOBUFS;
1918 :
1919 1 : if (hexstr2bin(pos, data, data_len)) {
1920 0 : wpa_printf(MSG_DEBUG,
1921 : "Vendor command: wrong parameter format");
1922 0 : os_free(data);
1923 0 : return -EINVAL;
1924 : }
1925 : }
1926 :
1927 1 : reply = wpabuf_alloc((buflen - 1) / 2);
1928 1 : if (!reply) {
1929 0 : os_free(data);
1930 0 : return -ENOBUFS;
1931 : }
1932 :
1933 1 : ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
1934 : reply);
1935 :
1936 1 : if (ret == 0)
1937 1 : ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
1938 : wpabuf_len(reply));
1939 :
1940 1 : wpabuf_free(reply);
1941 1 : os_free(data);
1942 :
1943 1 : return ret;
1944 : }
1945 :
1946 :
1947 11 : static int hostapd_ctrl_iface_eapol_reauth(struct hostapd_data *hapd,
1948 : const char *cmd)
1949 : {
1950 : u8 addr[ETH_ALEN];
1951 : struct sta_info *sta;
1952 :
1953 11 : if (hwaddr_aton(cmd, addr))
1954 0 : return -1;
1955 :
1956 11 : sta = ap_get_sta(hapd, addr);
1957 11 : if (!sta || !sta->eapol_sm)
1958 0 : return -1;
1959 :
1960 11 : eapol_auth_reauthenticate(sta->eapol_sm);
1961 11 : return 0;
1962 : }
1963 :
1964 :
1965 22 : static int hostapd_ctrl_iface_eapol_set(struct hostapd_data *hapd, char *cmd)
1966 : {
1967 : u8 addr[ETH_ALEN];
1968 : struct sta_info *sta;
1969 22 : char *pos = cmd, *param;
1970 :
1971 22 : if (hwaddr_aton(pos, addr) || pos[17] != ' ')
1972 2 : return -1;
1973 20 : pos += 18;
1974 20 : param = pos;
1975 20 : pos = os_strchr(pos, ' ');
1976 20 : if (!pos)
1977 1 : return -1;
1978 19 : *pos++ = '\0';
1979 :
1980 19 : sta = ap_get_sta(hapd, addr);
1981 19 : if (!sta || !sta->eapol_sm)
1982 1 : return -1;
1983 :
1984 18 : return eapol_auth_set_conf(sta->eapol_sm, param, pos);
1985 : }
1986 :
1987 :
1988 20 : static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
1989 : char *buf, size_t buflen)
1990 : {
1991 : char *pos, *end, *stamp;
1992 : int ret;
1993 :
1994 : /* cmd: "LOG_LEVEL [<level>]" */
1995 20 : if (*cmd == '\0') {
1996 10 : pos = buf;
1997 10 : end = buf + buflen;
1998 10 : ret = os_snprintf(pos, end - pos, "Current level: %s\n"
1999 : "Timestamp: %d\n",
2000 : debug_level_str(wpa_debug_level),
2001 : wpa_debug_timestamp);
2002 10 : if (os_snprintf_error(end - pos, ret))
2003 0 : ret = 0;
2004 :
2005 10 : return ret;
2006 : }
2007 :
2008 33 : while (*cmd == ' ')
2009 13 : cmd++;
2010 :
2011 10 : stamp = os_strchr(cmd, ' ');
2012 10 : if (stamp) {
2013 3 : *stamp++ = '\0';
2014 9 : while (*stamp == ' ') {
2015 3 : stamp++;
2016 : }
2017 : }
2018 :
2019 10 : if (os_strlen(cmd)) {
2020 10 : int level = str_to_debug_level(cmd);
2021 10 : if (level < 0)
2022 1 : return -1;
2023 9 : wpa_debug_level = level;
2024 : }
2025 :
2026 9 : if (stamp && os_strlen(stamp))
2027 3 : wpa_debug_timestamp = atoi(stamp);
2028 :
2029 9 : os_memcpy(buf, "OK\n", 3);
2030 9 : return 3;
2031 : }
2032 :
2033 :
2034 : #ifdef NEED_AP_MLME
2035 6 : static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
2036 : char *buf, size_t buflen)
2037 : {
2038 6 : struct hostapd_iface *iface = hapd->iface;
2039 : char *pos, *end;
2040 : struct hostapd_sta_info *info;
2041 : struct os_reltime now;
2042 :
2043 6 : if (!iface->num_sta_seen)
2044 1 : return 0;
2045 :
2046 5 : sta_track_expire(iface, 0);
2047 :
2048 5 : pos = buf;
2049 5 : end = buf + buflen;
2050 :
2051 5 : os_get_reltime(&now);
2052 13 : dl_list_for_each_reverse(info, &iface->sta_seen,
2053 : struct hostapd_sta_info, list) {
2054 : struct os_reltime age;
2055 : int ret;
2056 :
2057 8 : os_reltime_sub(&now, &info->last_seen, &age);
2058 56 : ret = os_snprintf(pos, end - pos, MACSTR " %u\n",
2059 56 : MAC2STR(info->addr), (unsigned int) age.sec);
2060 8 : if (os_snprintf_error(end - pos, ret))
2061 0 : break;
2062 8 : pos += ret;
2063 : }
2064 :
2065 5 : return pos - buf;
2066 : }
2067 : #endif /* NEED_AP_MLME */
2068 :
2069 :
2070 5 : static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
2071 : const char *cmd)
2072 : {
2073 : u8 addr[ETH_ALEN];
2074 :
2075 5 : if (hwaddr_aton(cmd, addr)) {
2076 1 : wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
2077 1 : return -1;
2078 : }
2079 :
2080 4 : return hostapd_send_lci_req(hapd, addr);
2081 : }
2082 :
2083 :
2084 9 : static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
2085 : {
2086 : u8 addr[ETH_ALEN];
2087 9 : char *token, *context = NULL;
2088 : int random_interval, min_ap;
2089 : u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
2090 : unsigned int n_responders;
2091 :
2092 9 : token = str_token(cmd, " ", &context);
2093 9 : if (!token || hwaddr_aton(token, addr)) {
2094 1 : wpa_printf(MSG_INFO,
2095 : "CTRL: REQ_RANGE - Bad destination address");
2096 1 : return -1;
2097 : }
2098 :
2099 8 : token = str_token(cmd, " ", &context);
2100 8 : if (!token)
2101 2 : return -1;
2102 :
2103 6 : random_interval = atoi(token);
2104 6 : if (random_interval < 0 || random_interval > 0xffff)
2105 0 : return -1;
2106 :
2107 6 : token = str_token(cmd, " ", &context);
2108 6 : if (!token)
2109 0 : return -1;
2110 :
2111 6 : min_ap = atoi(token);
2112 6 : if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
2113 1 : return -1;
2114 :
2115 5 : n_responders = 0;
2116 13 : while ((token = str_token(cmd, " ", &context))) {
2117 5 : if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
2118 0 : wpa_printf(MSG_INFO,
2119 : "CTRL: REQ_RANGE: Too many responders");
2120 0 : return -1;
2121 : }
2122 :
2123 5 : if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
2124 2 : wpa_printf(MSG_INFO,
2125 : "CTRL: REQ_RANGE: Bad responder address");
2126 2 : return -1;
2127 : }
2128 :
2129 3 : n_responders++;
2130 : }
2131 :
2132 3 : if (!n_responders) {
2133 1 : wpa_printf(MSG_INFO,
2134 : "CTRL: REQ_RANGE - No FTM responder address");
2135 1 : return -1;
2136 : }
2137 :
2138 2 : return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
2139 : responders, n_responders);
2140 : }
2141 :
2142 :
2143 17 : static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
2144 : {
2145 : struct wpa_ssid_value ssid;
2146 : u8 bssid[ETH_ALEN];
2147 17 : struct wpabuf *nr, *lci = NULL, *civic = NULL;
2148 : char *tmp;
2149 : int ret;
2150 :
2151 17 : if (!(hapd->conf->radio_measurements[0] &
2152 : WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
2153 1 : wpa_printf(MSG_ERROR,
2154 : "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
2155 1 : return -1;
2156 : }
2157 :
2158 16 : if (hwaddr_aton(buf, bssid)) {
2159 1 : wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
2160 1 : return -1;
2161 : }
2162 :
2163 15 : tmp = os_strstr(buf, "ssid=");
2164 15 : if (!tmp || ssid_parse(tmp + 5, &ssid)) {
2165 2 : wpa_printf(MSG_ERROR,
2166 : "CTRL: SET_NEIGHBOR: Bad or missing SSID");
2167 2 : return -1;
2168 : }
2169 13 : buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
2170 13 : if (!buf)
2171 0 : return -1;
2172 :
2173 13 : tmp = os_strstr(buf, "nr=");
2174 13 : if (!tmp) {
2175 1 : wpa_printf(MSG_ERROR,
2176 : "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
2177 1 : return -1;
2178 : }
2179 :
2180 12 : buf = os_strchr(tmp, ' ');
2181 12 : if (buf)
2182 9 : *buf++ = '\0';
2183 :
2184 12 : nr = wpabuf_parse_bin(tmp + 3);
2185 12 : if (!nr) {
2186 1 : wpa_printf(MSG_ERROR,
2187 : "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
2188 1 : return -1;
2189 : }
2190 :
2191 11 : if (!buf)
2192 2 : goto set;
2193 :
2194 9 : tmp = os_strstr(buf, "lci=");
2195 9 : if (tmp) {
2196 8 : buf = os_strchr(tmp, ' ');
2197 8 : if (buf)
2198 6 : *buf++ = '\0';
2199 8 : lci = wpabuf_parse_bin(tmp + 4);
2200 8 : if (!lci) {
2201 0 : wpa_printf(MSG_ERROR,
2202 : "CTRL: SET_NEIGHBOR: Bad LCI subelement");
2203 0 : wpabuf_free(nr);
2204 0 : return -1;
2205 : }
2206 : }
2207 :
2208 9 : if (!buf)
2209 2 : goto set;
2210 :
2211 7 : tmp = os_strstr(buf, "civic=");
2212 7 : if (tmp) {
2213 7 : buf = os_strchr(tmp, ' ');
2214 7 : if (buf)
2215 0 : *buf++ = '\0';
2216 7 : civic = wpabuf_parse_bin(tmp + 6);
2217 7 : if (!civic) {
2218 0 : wpa_printf(MSG_ERROR,
2219 : "CTRL: SET_NEIGHBOR: Bad civic subelement");
2220 0 : wpabuf_free(nr);
2221 0 : wpabuf_free(lci);
2222 0 : return -1;
2223 : }
2224 : }
2225 :
2226 : set:
2227 11 : ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic);
2228 :
2229 11 : wpabuf_free(nr);
2230 11 : wpabuf_free(lci);
2231 11 : wpabuf_free(civic);
2232 :
2233 11 : return ret;
2234 : }
2235 :
2236 :
2237 6 : static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
2238 : char *buf)
2239 : {
2240 : struct wpa_ssid_value ssid;
2241 : u8 bssid[ETH_ALEN];
2242 : char *tmp;
2243 :
2244 6 : if (hwaddr_aton(buf, bssid)) {
2245 0 : wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
2246 0 : return -1;
2247 : }
2248 :
2249 6 : tmp = os_strstr(buf, "ssid=");
2250 6 : if (!tmp || ssid_parse(tmp + 5, &ssid)) {
2251 0 : wpa_printf(MSG_ERROR,
2252 : "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
2253 0 : return -1;
2254 : }
2255 :
2256 6 : return hostapd_neighbor_remove(hapd, bssid, &ssid);
2257 : }
2258 :
2259 :
2260 2 : static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
2261 : size_t buflen)
2262 : {
2263 : int ret, i;
2264 : char *pos, *end;
2265 :
2266 2 : ret = os_snprintf(buf, buflen, "%016llX:\n",
2267 2 : (long long unsigned) iface->drv_flags);
2268 2 : if (os_snprintf_error(buflen, ret))
2269 0 : return -1;
2270 :
2271 2 : pos = buf + ret;
2272 2 : end = buf + buflen;
2273 :
2274 130 : for (i = 0; i < 64; i++) {
2275 128 : if (iface->drv_flags & (1LLU << i)) {
2276 26 : ret = os_snprintf(pos, end - pos, "%s\n",
2277 26 : driver_flag_to_string(1LLU << i));
2278 26 : if (os_snprintf_error(end - pos, ret))
2279 0 : return -1;
2280 26 : pos += ret;
2281 : }
2282 : }
2283 :
2284 2 : return pos - buf;
2285 : }
2286 :
2287 :
2288 47232 : static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
2289 : char *buf, char *reply,
2290 : int reply_size,
2291 : struct sockaddr_storage *from,
2292 : socklen_t fromlen)
2293 : {
2294 : int reply_len, res;
2295 :
2296 47232 : os_memcpy(reply, "OK\n", 3);
2297 47232 : reply_len = 3;
2298 :
2299 47232 : if (os_strcmp(buf, "PING") == 0) {
2300 2309 : os_memcpy(reply, "PONG\n", 5);
2301 2309 : reply_len = 5;
2302 44923 : } else if (os_strncmp(buf, "RELOG", 5) == 0) {
2303 0 : if (wpa_debug_reopen_file() < 0)
2304 0 : reply_len = -1;
2305 44923 : } else if (os_strcmp(buf, "STATUS") == 0) {
2306 717 : reply_len = hostapd_ctrl_iface_status(hapd, reply,
2307 : reply_size);
2308 44206 : } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
2309 18 : reply_len = hostapd_drv_status(hapd, reply, reply_size);
2310 44188 : } else if (os_strcmp(buf, "MIB") == 0) {
2311 13 : reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
2312 13 : if (reply_len >= 0) {
2313 13 : res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
2314 13 : reply_size - reply_len);
2315 13 : if (res < 0)
2316 0 : reply_len = -1;
2317 : else
2318 13 : reply_len += res;
2319 : }
2320 13 : if (reply_len >= 0) {
2321 13 : res = ieee802_1x_get_mib(hapd, reply + reply_len,
2322 13 : reply_size - reply_len);
2323 13 : if (res < 0)
2324 0 : reply_len = -1;
2325 : else
2326 13 : reply_len += res;
2327 : }
2328 : #ifndef CONFIG_NO_RADIUS
2329 13 : if (reply_len >= 0) {
2330 13 : res = radius_client_get_mib(hapd->radius,
2331 : reply + reply_len,
2332 13 : reply_size - reply_len);
2333 13 : if (res < 0)
2334 0 : reply_len = -1;
2335 : else
2336 13 : reply_len += res;
2337 : }
2338 : #endif /* CONFIG_NO_RADIUS */
2339 44175 : } else if (os_strncmp(buf, "MIB ", 4) == 0) {
2340 15 : reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
2341 : buf + 4);
2342 44160 : } else if (os_strcmp(buf, "STA-FIRST") == 0) {
2343 114 : reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
2344 : reply_size);
2345 44046 : } else if (os_strncmp(buf, "STA ", 4) == 0) {
2346 127 : reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
2347 : reply_size);
2348 43919 : } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
2349 4 : reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
2350 : reply_size);
2351 43915 : } else if (os_strcmp(buf, "ATTACH") == 0) {
2352 2443 : if (hostapd_ctrl_iface_attach(hapd, from, fromlen))
2353 3 : reply_len = -1;
2354 41472 : } else if (os_strcmp(buf, "DETACH") == 0) {
2355 2314 : if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
2356 1 : reply_len = -1;
2357 39158 : } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
2358 1 : if (hostapd_ctrl_iface_level(hapd, from, fromlen,
2359 : buf + 6))
2360 1 : reply_len = -1;
2361 39157 : } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
2362 3 : if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
2363 1 : reply_len = -1;
2364 39154 : } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
2365 19 : if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
2366 3 : reply_len = -1;
2367 39135 : } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
2368 8 : if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
2369 3 : reply_len = -1;
2370 : #ifdef CONFIG_TAXONOMY
2371 39127 : } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
2372 9 : reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
2373 : reply, reply_size);
2374 : #endif /* CONFIG_TAXONOMY */
2375 39118 : } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
2376 1 : if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
2377 0 : reply_len = -1;
2378 39117 : } else if (os_strcmp(buf, "STOP_AP") == 0) {
2379 1 : if (hostapd_ctrl_iface_stop_ap(hapd))
2380 0 : reply_len = -1;
2381 : #ifdef CONFIG_IEEE80211W
2382 : #ifdef NEED_AP_MLME
2383 39116 : } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
2384 3 : if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
2385 0 : reply_len = -1;
2386 : #endif /* NEED_AP_MLME */
2387 : #endif /* CONFIG_IEEE80211W */
2388 : #ifdef CONFIG_WPS
2389 39113 : } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
2390 117 : if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
2391 2 : reply_len = -1;
2392 38996 : } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
2393 10 : reply_len = hostapd_ctrl_iface_wps_check_pin(
2394 : hapd, buf + 14, reply, reply_size);
2395 38986 : } else if (os_strcmp(buf, "WPS_PBC") == 0) {
2396 85 : if (hostapd_wps_button_pushed(hapd, NULL))
2397 3 : reply_len = -1;
2398 38901 : } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
2399 7 : if (hostapd_wps_cancel(hapd))
2400 2 : reply_len = -1;
2401 38894 : } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
2402 19 : reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
2403 : reply, reply_size);
2404 38875 : } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
2405 4 : if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
2406 1 : reply_len = -1;
2407 38871 : } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
2408 6 : reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
2409 : reply_size);
2410 : #ifdef CONFIG_WPS_NFC
2411 38865 : } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
2412 3 : if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
2413 1 : reply_len = -1;
2414 38862 : } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
2415 4 : reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
2416 : hapd, buf + 21, reply, reply_size);
2417 38858 : } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
2418 9 : reply_len = hostapd_ctrl_iface_wps_nfc_token(
2419 : hapd, buf + 14, reply, reply_size);
2420 38849 : } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
2421 10 : reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
2422 : hapd, buf + 21, reply, reply_size);
2423 38839 : } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
2424 18 : if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
2425 11 : reply_len = -1;
2426 : #endif /* CONFIG_WPS_NFC */
2427 : #endif /* CONFIG_WPS */
2428 : #ifdef CONFIG_INTERWORKING
2429 38821 : } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
2430 8 : if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
2431 5 : reply_len = -1;
2432 38813 : } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
2433 5 : if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
2434 4 : reply_len = -1;
2435 : #endif /* CONFIG_INTERWORKING */
2436 : #ifdef CONFIG_HS20
2437 38808 : } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
2438 8 : if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
2439 5 : reply_len = -1;
2440 38800 : } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
2441 7 : if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
2442 3 : reply_len = -1;
2443 : #endif /* CONFIG_HS20 */
2444 : #ifdef CONFIG_WNM
2445 38793 : } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
2446 6 : if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
2447 3 : reply_len = -1;
2448 38787 : } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
2449 10 : if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
2450 5 : reply_len = -1;
2451 38777 : } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
2452 32 : if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
2453 2 : reply_len = -1;
2454 : #endif /* CONFIG_WNM */
2455 38745 : } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
2456 16 : reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
2457 : reply_size);
2458 38729 : } else if (os_strncmp(buf, "SET ", 4) == 0) {
2459 31291 : if (hostapd_ctrl_iface_set(hapd, buf + 4))
2460 177 : reply_len = -1;
2461 7438 : } else if (os_strncmp(buf, "GET ", 4) == 0) {
2462 14 : reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
2463 : reply_size);
2464 7424 : } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
2465 2004 : if (hostapd_ctrl_iface_enable(hapd->iface))
2466 37 : reply_len = -1;
2467 5420 : } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
2468 2 : if (hostapd_ctrl_iface_reload(hapd->iface))
2469 0 : reply_len = -1;
2470 5418 : } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
2471 198 : if (hostapd_ctrl_iface_disable(hapd->iface))
2472 6 : reply_len = -1;
2473 5220 : } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
2474 5 : if (ieee802_11_set_beacon(hapd))
2475 0 : reply_len = -1;
2476 : #ifdef CONFIG_TESTING_OPTIONS
2477 5215 : } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
2478 4 : if (hostapd_ctrl_iface_radar(hapd, buf + 6))
2479 0 : reply_len = -1;
2480 5211 : } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
2481 457 : if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
2482 0 : reply_len = -1;
2483 4754 : } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
2484 318 : if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
2485 0 : reply_len = -1;
2486 4436 : } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
2487 1330 : if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
2488 0 : reply_len = -1;
2489 3106 : } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
2490 1425 : if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
2491 0 : reply_len = -1;
2492 1681 : } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
2493 59 : if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
2494 0 : reply_len = -1;
2495 1622 : } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
2496 853 : if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
2497 0 : reply_len = -1;
2498 769 : } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
2499 611 : reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
2500 : reply_size);
2501 158 : } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
2502 9 : if (hostapd_ctrl_test_fail(hapd, buf + 10) < 0)
2503 0 : reply_len = -1;
2504 149 : } else if (os_strcmp(buf, "GET_FAIL") == 0) {
2505 9 : reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
2506 : #endif /* CONFIG_TESTING_OPTIONS */
2507 140 : } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
2508 33 : if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
2509 14 : reply_len = -1;
2510 107 : } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
2511 1 : reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
2512 : reply_size);
2513 106 : } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
2514 1 : ieee802_1x_erp_flush(hapd);
2515 : #ifdef RADIUS_SERVER
2516 1 : radius_server_erp_flush(hapd->radius_srv);
2517 : #endif /* RADIUS_SERVER */
2518 105 : } else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
2519 11 : if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
2520 0 : reply_len = -1;
2521 94 : } else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
2522 22 : if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
2523 9 : reply_len = -1;
2524 72 : } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
2525 20 : reply_len = hostapd_ctrl_iface_log_level(
2526 : hapd, buf + 9, reply, reply_size);
2527 : #ifdef NEED_AP_MLME
2528 52 : } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
2529 6 : reply_len = hostapd_ctrl_iface_track_sta_list(
2530 : hapd, reply, reply_size);
2531 : #endif /* NEED_AP_MLME */
2532 46 : } else if (os_strcmp(buf, "PMKSA") == 0) {
2533 4 : reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
2534 : reply_size);
2535 42 : } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
2536 2 : hostapd_ctrl_iface_pmksa_flush(hapd);
2537 40 : } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
2538 17 : if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
2539 6 : reply_len = -1;
2540 23 : } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
2541 6 : if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
2542 3 : reply_len = -1;
2543 17 : } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
2544 5 : if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
2545 4 : reply_len = -1;
2546 12 : } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
2547 9 : if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
2548 9 : reply_len = -1;
2549 3 : } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
2550 2 : reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
2551 : reply_size);
2552 : } else {
2553 1 : os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
2554 1 : reply_len = 16;
2555 : }
2556 :
2557 47232 : if (reply_len < 0) {
2558 354 : os_memcpy(reply, "FAIL\n", 5);
2559 354 : reply_len = 5;
2560 : }
2561 :
2562 47232 : return reply_len;
2563 : }
2564 :
2565 :
2566 47292 : static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
2567 : void *sock_ctx)
2568 : {
2569 47292 : struct hostapd_data *hapd = eloop_ctx;
2570 : char buf[4096];
2571 : int res;
2572 : struct sockaddr_storage from;
2573 47292 : socklen_t fromlen = sizeof(from);
2574 47292 : char *reply, *pos = buf;
2575 47292 : const int reply_size = 4096;
2576 : int reply_len;
2577 47292 : int level = MSG_DEBUG;
2578 : #ifdef CONFIG_CTRL_IFACE_UDP
2579 : unsigned char lcookie[COOKIE_LEN];
2580 : #endif /* CONFIG_CTRL_IFACE_UDP */
2581 :
2582 47292 : res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
2583 : (struct sockaddr *) &from, &fromlen);
2584 47292 : if (res < 0) {
2585 0 : wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
2586 0 : strerror(errno));
2587 0 : return;
2588 : }
2589 47292 : buf[res] = '\0';
2590 :
2591 47292 : reply = os_malloc(reply_size);
2592 47292 : if (reply == NULL) {
2593 62 : if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
2594 : fromlen) < 0) {
2595 0 : wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2596 0 : strerror(errno));
2597 : }
2598 62 : return;
2599 : }
2600 :
2601 : #ifdef CONFIG_CTRL_IFACE_UDP
2602 : if (os_strcmp(buf, "GET_COOKIE") == 0) {
2603 : os_memcpy(reply, "COOKIE=", 7);
2604 : wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
2605 : cookie, COOKIE_LEN);
2606 : reply_len = 7 + 2 * COOKIE_LEN;
2607 : goto done;
2608 : }
2609 :
2610 : if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
2611 : hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
2612 : wpa_printf(MSG_DEBUG,
2613 : "CTRL: No cookie in the request - drop request");
2614 : os_free(reply);
2615 : return;
2616 : }
2617 :
2618 : if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
2619 : wpa_printf(MSG_DEBUG,
2620 : "CTRL: Invalid cookie in the request - drop request");
2621 : os_free(reply);
2622 : return;
2623 : }
2624 :
2625 : pos = buf + 7 + 2 * COOKIE_LEN;
2626 : while (*pos == ' ')
2627 : pos++;
2628 : #endif /* CONFIG_CTRL_IFACE_UDP */
2629 :
2630 47230 : if (os_strcmp(pos, "PING") == 0)
2631 2308 : level = MSG_EXCESSIVE;
2632 47230 : wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
2633 :
2634 47230 : reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
2635 : reply, reply_size,
2636 : &from, fromlen);
2637 :
2638 : #ifdef CONFIG_CTRL_IFACE_UDP
2639 : done:
2640 : #endif /* CONFIG_CTRL_IFACE_UDP */
2641 47230 : if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
2642 : fromlen) < 0) {
2643 5 : wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2644 5 : strerror(errno));
2645 : }
2646 47230 : os_free(reply);
2647 : }
2648 :
2649 :
2650 : #ifndef CONFIG_CTRL_IFACE_UDP
2651 4182 : static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
2652 : {
2653 : char *buf;
2654 : size_t len;
2655 :
2656 4182 : if (hapd->conf->ctrl_interface == NULL)
2657 0 : return NULL;
2658 :
2659 8364 : len = os_strlen(hapd->conf->ctrl_interface) +
2660 4182 : os_strlen(hapd->conf->iface) + 2;
2661 4182 : buf = os_malloc(len);
2662 4182 : if (buf == NULL)
2663 9 : return NULL;
2664 :
2665 4173 : os_snprintf(buf, len, "%s/%s",
2666 4173 : hapd->conf->ctrl_interface, hapd->conf->iface);
2667 4173 : buf[len - 1] = '\0';
2668 4173 : return buf;
2669 : }
2670 : #endif /* CONFIG_CTRL_IFACE_UDP */
2671 :
2672 :
2673 122276 : static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
2674 : enum wpa_msg_type type,
2675 : const char *txt, size_t len)
2676 : {
2677 122276 : struct hostapd_data *hapd = ctx;
2678 122276 : if (hapd == NULL)
2679 122276 : return;
2680 122276 : hostapd_ctrl_iface_send(hapd, level, type, txt, len);
2681 : }
2682 :
2683 :
2684 4086 : int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
2685 : {
2686 : #ifdef CONFIG_CTRL_IFACE_UDP
2687 : int port = HOSTAPD_CTRL_IFACE_PORT;
2688 : char p[32] = { 0 };
2689 : char port_str[40], *tmp;
2690 : char *pos;
2691 : struct addrinfo hints = { 0 }, *res, *saveres;
2692 : int n;
2693 :
2694 : if (hapd->ctrl_sock > -1) {
2695 : wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
2696 : return 0;
2697 : }
2698 :
2699 : if (hapd->conf->ctrl_interface == NULL)
2700 : return 0;
2701 :
2702 : pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
2703 : if (pos) {
2704 : pos += 4;
2705 : port = atoi(pos);
2706 : if (port <= 0) {
2707 : wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
2708 : goto fail;
2709 : }
2710 : }
2711 :
2712 : dl_list_init(&hapd->ctrl_dst);
2713 : hapd->ctrl_sock = -1;
2714 : os_get_random(cookie, COOKIE_LEN);
2715 :
2716 : #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
2717 : hints.ai_flags = AI_PASSIVE;
2718 : #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
2719 :
2720 : #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
2721 : hints.ai_family = AF_INET6;
2722 : #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
2723 : hints.ai_family = AF_INET;
2724 : #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
2725 : hints.ai_socktype = SOCK_DGRAM;
2726 :
2727 : try_again:
2728 : os_snprintf(p, sizeof(p), "%d", port);
2729 : n = getaddrinfo(NULL, p, &hints, &res);
2730 : if (n) {
2731 : wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
2732 : goto fail;
2733 : }
2734 :
2735 : saveres = res;
2736 : hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
2737 : res->ai_protocol);
2738 : if (hapd->ctrl_sock < 0) {
2739 : wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
2740 : goto fail;
2741 : }
2742 :
2743 : if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
2744 : port--;
2745 : if ((HOSTAPD_CTRL_IFACE_PORT - port) <
2746 : HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
2747 : goto try_again;
2748 : wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
2749 : goto fail;
2750 : }
2751 :
2752 : freeaddrinfo(saveres);
2753 :
2754 : os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
2755 : tmp = os_strdup(port_str);
2756 : if (tmp) {
2757 : os_free(hapd->conf->ctrl_interface);
2758 : hapd->conf->ctrl_interface = tmp;
2759 : }
2760 : wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
2761 :
2762 : if (eloop_register_read_sock(hapd->ctrl_sock,
2763 : hostapd_ctrl_iface_receive, hapd, NULL) <
2764 : 0) {
2765 : hostapd_ctrl_iface_deinit(hapd);
2766 : return -1;
2767 : }
2768 :
2769 : hapd->msg_ctx = hapd;
2770 : wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
2771 :
2772 : return 0;
2773 :
2774 : fail:
2775 : if (hapd->ctrl_sock >= 0)
2776 : close(hapd->ctrl_sock);
2777 : return -1;
2778 : #else /* CONFIG_CTRL_IFACE_UDP */
2779 : struct sockaddr_un addr;
2780 4086 : int s = -1;
2781 4086 : char *fname = NULL;
2782 :
2783 4086 : if (hapd->ctrl_sock > -1) {
2784 1992 : wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
2785 1992 : return 0;
2786 : }
2787 :
2788 2094 : dl_list_init(&hapd->ctrl_dst);
2789 :
2790 2094 : if (hapd->conf->ctrl_interface == NULL)
2791 0 : return 0;
2792 :
2793 2094 : if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2794 2088 : if (errno == EEXIST) {
2795 2088 : wpa_printf(MSG_DEBUG, "Using existing control "
2796 : "interface directory.");
2797 : } else {
2798 0 : wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
2799 0 : strerror(errno));
2800 0 : goto fail;
2801 : }
2802 : }
2803 :
2804 2106 : if (hapd->conf->ctrl_interface_gid_set &&
2805 12 : chown(hapd->conf->ctrl_interface, -1,
2806 12 : hapd->conf->ctrl_interface_gid) < 0) {
2807 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2808 0 : strerror(errno));
2809 0 : return -1;
2810 : }
2811 :
2812 4176 : if (!hapd->conf->ctrl_interface_gid_set &&
2813 2082 : hapd->iface->interfaces->ctrl_iface_group &&
2814 0 : chown(hapd->conf->ctrl_interface, -1,
2815 0 : hapd->iface->interfaces->ctrl_iface_group) < 0) {
2816 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2817 0 : strerror(errno));
2818 0 : return -1;
2819 : }
2820 :
2821 : #ifdef ANDROID
2822 : /*
2823 : * Android is using umask 0077 which would leave the control interface
2824 : * directory without group access. This breaks things since Wi-Fi
2825 : * framework assumes that this directory can be accessed by other
2826 : * applications in the wifi group. Fix this by adding group access even
2827 : * if umask value would prevent this.
2828 : */
2829 : if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2830 : wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
2831 : strerror(errno));
2832 : /* Try to continue anyway */
2833 : }
2834 : #endif /* ANDROID */
2835 :
2836 4188 : if (os_strlen(hapd->conf->ctrl_interface) + 1 +
2837 2094 : os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
2838 0 : goto fail;
2839 :
2840 2094 : s = socket(PF_UNIX, SOCK_DGRAM, 0);
2841 2094 : if (s < 0) {
2842 0 : wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
2843 0 : goto fail;
2844 : }
2845 :
2846 2094 : os_memset(&addr, 0, sizeof(addr));
2847 : #ifdef __FreeBSD__
2848 : addr.sun_len = sizeof(addr);
2849 : #endif /* __FreeBSD__ */
2850 2094 : addr.sun_family = AF_UNIX;
2851 2094 : fname = hostapd_ctrl_iface_path(hapd);
2852 2094 : if (fname == NULL)
2853 6 : goto fail;
2854 2088 : os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
2855 2088 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2856 3 : wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
2857 3 : strerror(errno));
2858 3 : if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2859 3 : wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
2860 : " allow connections - assuming it was left"
2861 : "over from forced program termination");
2862 3 : if (unlink(fname) < 0) {
2863 0 : wpa_printf(MSG_ERROR,
2864 : "Could not unlink existing ctrl_iface socket '%s': %s",
2865 0 : fname, strerror(errno));
2866 0 : goto fail;
2867 : }
2868 3 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
2869 : 0) {
2870 0 : wpa_printf(MSG_ERROR,
2871 : "hostapd-ctrl-iface: bind(PF_UNIX): %s",
2872 0 : strerror(errno));
2873 0 : goto fail;
2874 : }
2875 3 : wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
2876 : "ctrl_iface socket '%s'", fname);
2877 : } else {
2878 0 : wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
2879 : "be in use - cannot override it");
2880 0 : wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
2881 : "not used anymore", fname);
2882 0 : os_free(fname);
2883 0 : fname = NULL;
2884 0 : goto fail;
2885 : }
2886 : }
2887 :
2888 2100 : if (hapd->conf->ctrl_interface_gid_set &&
2889 12 : chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
2890 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2891 0 : strerror(errno));
2892 0 : goto fail;
2893 : }
2894 :
2895 4164 : if (!hapd->conf->ctrl_interface_gid_set &&
2896 2076 : hapd->iface->interfaces->ctrl_iface_group &&
2897 0 : chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
2898 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2899 0 : strerror(errno));
2900 0 : goto fail;
2901 : }
2902 :
2903 2088 : if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
2904 0 : wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
2905 0 : strerror(errno));
2906 0 : goto fail;
2907 : }
2908 2088 : os_free(fname);
2909 :
2910 2088 : hapd->ctrl_sock = s;
2911 2088 : if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
2912 : NULL) < 0) {
2913 0 : hostapd_ctrl_iface_deinit(hapd);
2914 0 : return -1;
2915 : }
2916 2088 : hapd->msg_ctx = hapd;
2917 2088 : wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
2918 :
2919 2088 : return 0;
2920 :
2921 : fail:
2922 6 : if (s >= 0)
2923 6 : close(s);
2924 6 : if (fname) {
2925 0 : unlink(fname);
2926 0 : os_free(fname);
2927 : }
2928 6 : return -1;
2929 : #endif /* CONFIG_CTRL_IFACE_UDP */
2930 : }
2931 :
2932 :
2933 2110 : void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
2934 : {
2935 : struct wpa_ctrl_dst *dst, *prev;
2936 :
2937 2110 : if (hapd->ctrl_sock > -1) {
2938 : #ifndef CONFIG_CTRL_IFACE_UDP
2939 : char *fname;
2940 : #endif /* !CONFIG_CTRL_IFACE_UDP */
2941 :
2942 2088 : eloop_unregister_read_sock(hapd->ctrl_sock);
2943 2088 : close(hapd->ctrl_sock);
2944 2088 : hapd->ctrl_sock = -1;
2945 : #ifndef CONFIG_CTRL_IFACE_UDP
2946 2088 : fname = hostapd_ctrl_iface_path(hapd);
2947 2088 : if (fname)
2948 2085 : unlink(fname);
2949 2088 : os_free(fname);
2950 :
2951 4176 : if (hapd->conf->ctrl_interface &&
2952 2088 : rmdir(hapd->conf->ctrl_interface) < 0) {
2953 2082 : if (errno == ENOTEMPTY) {
2954 2082 : wpa_printf(MSG_DEBUG, "Control interface "
2955 : "directory not empty - leaving it "
2956 : "behind");
2957 : } else {
2958 0 : wpa_printf(MSG_ERROR,
2959 : "rmdir[ctrl_interface=%s]: %s",
2960 0 : hapd->conf->ctrl_interface,
2961 0 : strerror(errno));
2962 : }
2963 : }
2964 : #endif /* !CONFIG_CTRL_IFACE_UDP */
2965 : }
2966 :
2967 2233 : dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
2968 : list)
2969 123 : os_free(dst);
2970 :
2971 : #ifdef CONFIG_TESTING_OPTIONS
2972 2110 : l2_packet_deinit(hapd->l2_test);
2973 2110 : hapd->l2_test = NULL;
2974 : #endif /* CONFIG_TESTING_OPTIONS */
2975 2110 : }
2976 :
2977 :
2978 2107 : static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
2979 : char *buf)
2980 : {
2981 2107 : if (hostapd_add_iface(interfaces, buf) < 0) {
2982 48 : wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
2983 48 : return -1;
2984 : }
2985 2059 : return 0;
2986 : }
2987 :
2988 :
2989 10292 : static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
2990 : char *buf)
2991 : {
2992 10292 : if (hostapd_remove_iface(interfaces, buf) < 0) {
2993 8228 : wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
2994 8228 : return -1;
2995 : }
2996 2064 : return 0;
2997 : }
2998 :
2999 :
3000 6752 : static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
3001 : struct sockaddr_storage *from,
3002 : socklen_t fromlen)
3003 : {
3004 6752 : return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen);
3005 : }
3006 :
3007 :
3008 6747 : static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
3009 : struct sockaddr_storage *from,
3010 : socklen_t fromlen)
3011 : {
3012 6747 : return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
3013 : }
3014 :
3015 :
3016 2051 : static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
3017 : {
3018 : #ifdef CONFIG_WPS_TESTING
3019 2051 : wps_version_number = 0x20;
3020 2051 : wps_testing_dummy_cred = 0;
3021 2051 : wps_corrupt_pkhash = 0;
3022 : #endif /* CONFIG_WPS_TESTING */
3023 2051 : }
3024 :
3025 :
3026 : #ifdef CONFIG_FST
3027 :
3028 : static int
3029 274 : hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
3030 : const char *cmd)
3031 : {
3032 : char ifname[IFNAMSIZ + 1];
3033 : struct fst_iface_cfg cfg;
3034 : struct hostapd_data *hapd;
3035 : struct fst_wpa_obj iface_obj;
3036 :
3037 274 : if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
3038 272 : hapd = hostapd_get_iface(interfaces, ifname);
3039 272 : if (hapd) {
3040 271 : if (hapd->iface->fst) {
3041 6 : wpa_printf(MSG_INFO, "FST: Already attached");
3042 6 : return -1;
3043 : }
3044 265 : fst_hostapd_fill_iface_obj(hapd, &iface_obj);
3045 265 : hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
3046 : &iface_obj, &cfg);
3047 265 : if (hapd->iface->fst)
3048 262 : return 0;
3049 : }
3050 : }
3051 :
3052 6 : return -EINVAL;
3053 : }
3054 :
3055 :
3056 : static int
3057 260 : hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
3058 : const char *cmd)
3059 : {
3060 : char ifname[IFNAMSIZ + 1];
3061 : struct hostapd_data * hapd;
3062 :
3063 260 : if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
3064 259 : hapd = hostapd_get_iface(interfaces, ifname);
3065 259 : if (hapd) {
3066 258 : if (!fst_iface_detach(ifname)) {
3067 255 : hapd->iface->fst = NULL;
3068 255 : hapd->iface->fst_ies = NULL;
3069 255 : return 0;
3070 : }
3071 : }
3072 : }
3073 :
3074 5 : return -EINVAL;
3075 : }
3076 :
3077 : #endif /* CONFIG_FST */
3078 :
3079 :
3080 : static struct hostapd_data *
3081 18 : hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
3082 : const char *ifname)
3083 : {
3084 : size_t i, j;
3085 :
3086 26 : for (i = 0; i < interfaces->count; i++) {
3087 26 : struct hostapd_iface *iface = interfaces->iface[i];
3088 :
3089 34 : for (j = 0; j < iface->num_bss; j++) {
3090 : struct hostapd_data *hapd;
3091 :
3092 26 : hapd = iface->bss[j];
3093 26 : if (os_strcmp(ifname, hapd->conf->iface) == 0)
3094 18 : return hapd;
3095 : }
3096 : }
3097 :
3098 0 : return NULL;
3099 : }
3100 :
3101 :
3102 8 : static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
3103 : struct hostapd_data *dst_hapd,
3104 : const char *param)
3105 : {
3106 : int res;
3107 : char *value;
3108 :
3109 8 : value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
3110 8 : if (!value) {
3111 0 : wpa_printf(MSG_ERROR,
3112 : "DUP: cannot allocate buffer to stringify %s",
3113 : param);
3114 0 : goto error_return;
3115 : }
3116 :
3117 8 : if (os_strcmp(param, "wpa") == 0) {
3118 2 : os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
3119 2 : src_hapd->conf->wpa);
3120 8 : } else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
3121 2 : src_hapd->conf->wpa_key_mgmt) {
3122 2 : res = hostapd_ctrl_iface_get_key_mgmt(
3123 : src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
3124 4 : if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
3125 0 : goto error_stringify;
3126 5 : } else if (os_strcmp(param, "wpa_pairwise") == 0 &&
3127 1 : src_hapd->conf->wpa_pairwise) {
3128 1 : res = wpa_write_ciphers(value,
3129 : value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3130 1 : src_hapd->conf->wpa_pairwise, " ");
3131 2 : if (res < 0)
3132 0 : goto error_stringify;
3133 4 : } else if (os_strcmp(param, "rsn_pairwise") == 0 &&
3134 1 : src_hapd->conf->rsn_pairwise) {
3135 1 : res = wpa_write_ciphers(value,
3136 : value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3137 1 : src_hapd->conf->rsn_pairwise, " ");
3138 2 : if (res < 0)
3139 0 : goto error_stringify;
3140 3 : } else if (os_strcmp(param, "wpa_passphrase") == 0 &&
3141 1 : src_hapd->conf->ssid.wpa_passphrase) {
3142 1 : os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
3143 1 : src_hapd->conf->ssid.wpa_passphrase);
3144 2 : } else if (os_strcmp(param, "wpa_psk") == 0 &&
3145 1 : src_hapd->conf->ssid.wpa_psk_set) {
3146 1 : wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3147 1 : src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
3148 : } else {
3149 0 : wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
3150 0 : goto error_return;
3151 : }
3152 :
3153 8 : res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
3154 8 : os_free(value);
3155 8 : return res;
3156 :
3157 : error_stringify:
3158 0 : wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
3159 : error_return:
3160 0 : os_free(value);
3161 0 : return -1;
3162 : }
3163 :
3164 :
3165 : static int
3166 0 : hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
3167 : const char *input,
3168 : char *reply, int reply_size)
3169 : {
3170 : size_t i, j;
3171 : int res;
3172 : char *pos, *end;
3173 : struct hostapd_iface *iface;
3174 0 : int show_ctrl = 0;
3175 :
3176 0 : if (input)
3177 0 : show_ctrl = !!os_strstr(input, "ctrl");
3178 :
3179 0 : pos = reply;
3180 0 : end = reply + reply_size;
3181 :
3182 0 : for (i = 0; i < interfaces->count; i++) {
3183 0 : iface = interfaces->iface[i];
3184 :
3185 0 : for (j = 0; j < iface->num_bss; j++) {
3186 : struct hostapd_bss_config *conf;
3187 :
3188 0 : conf = iface->conf->bss[j];
3189 0 : if (show_ctrl)
3190 0 : res = os_snprintf(pos, end - pos,
3191 : "%s ctrl_iface=%s\n",
3192 0 : conf->iface,
3193 0 : conf->ctrl_interface ?
3194 : conf->ctrl_interface : "N/A");
3195 : else
3196 0 : res = os_snprintf(pos, end - pos, "%s\n",
3197 0 : conf->iface);
3198 0 : if (os_snprintf_error(end - pos, res)) {
3199 0 : *pos = '\0';
3200 0 : return pos - reply;
3201 : }
3202 0 : pos += res;
3203 : }
3204 : }
3205 :
3206 0 : return pos - reply;
3207 : }
3208 :
3209 :
3210 : static int
3211 8 : hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
3212 : char *cmd)
3213 : {
3214 8 : char *p_start = cmd, *p_end;
3215 : struct hostapd_data *src_hapd, *dst_hapd;
3216 :
3217 : /* cmd: "<src ifname> <dst ifname> <variable name> */
3218 :
3219 8 : p_end = os_strchr(p_start, ' ');
3220 8 : if (!p_end) {
3221 0 : wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
3222 : cmd);
3223 0 : return -1;
3224 : }
3225 :
3226 8 : *p_end = '\0';
3227 8 : src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
3228 8 : if (!src_hapd) {
3229 0 : wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
3230 : p_start);
3231 0 : return -1;
3232 : }
3233 :
3234 8 : p_start = p_end + 1;
3235 8 : p_end = os_strchr(p_start, ' ');
3236 8 : if (!p_end) {
3237 0 : wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
3238 : cmd);
3239 0 : return -1;
3240 : }
3241 :
3242 8 : *p_end = '\0';
3243 8 : dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
3244 8 : if (!dst_hapd) {
3245 0 : wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
3246 : p_start);
3247 0 : return -1;
3248 : }
3249 :
3250 8 : p_start = p_end + 1;
3251 8 : return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
3252 : }
3253 :
3254 :
3255 2 : static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
3256 : const char *ifname,
3257 : char *buf, char *reply,
3258 : int reply_size,
3259 : struct sockaddr_storage *from,
3260 : socklen_t fromlen)
3261 : {
3262 : struct hostapd_data *hapd;
3263 :
3264 2 : hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
3265 2 : if (hapd == NULL) {
3266 : int res;
3267 :
3268 0 : res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
3269 0 : if (os_snprintf_error(reply_size, res))
3270 0 : return -1;
3271 0 : return res;
3272 : }
3273 :
3274 2 : return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
3275 : from, fromlen);
3276 : }
3277 :
3278 :
3279 32123 : static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
3280 : void *sock_ctx)
3281 : {
3282 32123 : void *interfaces = eloop_ctx;
3283 32123 : char buffer[256], *buf = buffer;
3284 : int res;
3285 : struct sockaddr_storage from;
3286 32123 : socklen_t fromlen = sizeof(from);
3287 : char *reply;
3288 : int reply_len;
3289 32123 : const int reply_size = 4096;
3290 : #ifdef CONFIG_CTRL_IFACE_UDP
3291 : unsigned char lcookie[COOKIE_LEN];
3292 : #endif /* CONFIG_CTRL_IFACE_UDP */
3293 :
3294 32123 : res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
3295 : (struct sockaddr *) &from, &fromlen);
3296 32123 : if (res < 0) {
3297 0 : wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
3298 0 : strerror(errno));
3299 0 : return;
3300 : }
3301 32123 : buf[res] = '\0';
3302 32123 : wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
3303 :
3304 32123 : reply = os_malloc(reply_size);
3305 32123 : if (reply == NULL) {
3306 18 : if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
3307 : fromlen) < 0) {
3308 0 : wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
3309 0 : strerror(errno));
3310 : }
3311 18 : return;
3312 : }
3313 :
3314 32105 : os_memcpy(reply, "OK\n", 3);
3315 32105 : reply_len = 3;
3316 :
3317 : #ifdef CONFIG_CTRL_IFACE_UDP
3318 : if (os_strcmp(buf, "GET_COOKIE") == 0) {
3319 : os_memcpy(reply, "COOKIE=", 7);
3320 : wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
3321 : gcookie, COOKIE_LEN);
3322 : reply_len = 7 + 2 * COOKIE_LEN;
3323 : goto send_reply;
3324 : }
3325 :
3326 : if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
3327 : hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
3328 : wpa_printf(MSG_DEBUG,
3329 : "CTRL: No cookie in the request - drop request");
3330 : os_free(reply);
3331 : return;
3332 : }
3333 :
3334 : if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
3335 : wpa_printf(MSG_DEBUG,
3336 : "CTRL: Invalid cookie in the request - drop request");
3337 : os_free(reply);
3338 : return;
3339 : }
3340 :
3341 : buf += 7 + 2 * COOKIE_LEN;
3342 : while (*buf == ' ')
3343 : buf++;
3344 : #endif /* CONFIG_CTRL_IFACE_UDP */
3345 :
3346 32105 : if (os_strncmp(buf, "IFNAME=", 7) == 0) {
3347 2 : char *pos = os_strchr(buf + 7, ' ');
3348 :
3349 2 : if (pos) {
3350 2 : *pos++ = '\0';
3351 2 : reply_len = hostapd_global_ctrl_iface_ifname(
3352 : interfaces, buf + 7, pos, reply, reply_size,
3353 : &from, fromlen);
3354 2 : goto send_reply;
3355 : }
3356 : }
3357 :
3358 32103 : if (os_strcmp(buf, "PING") == 0) {
3359 6 : os_memcpy(reply, "PONG\n", 5);
3360 6 : reply_len = 5;
3361 32097 : } else if (os_strncmp(buf, "RELOG", 5) == 0) {
3362 2007 : if (wpa_debug_reopen_file() < 0)
3363 0 : reply_len = -1;
3364 30090 : } else if (os_strcmp(buf, "FLUSH") == 0) {
3365 2051 : hostapd_ctrl_iface_flush(interfaces);
3366 28039 : } else if (os_strncmp(buf, "ADD ", 4) == 0) {
3367 2107 : if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
3368 48 : reply_len = -1;
3369 25932 : } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
3370 10292 : if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
3371 8228 : reply_len = -1;
3372 15640 : } else if (os_strcmp(buf, "ATTACH") == 0) {
3373 6752 : if (hostapd_global_ctrl_iface_attach(interfaces, &from,
3374 : fromlen))
3375 5 : reply_len = -1;
3376 8888 : } else if (os_strcmp(buf, "DETACH") == 0) {
3377 6739 : if (hostapd_global_ctrl_iface_detach(interfaces, &from,
3378 : fromlen))
3379 0 : reply_len = -1;
3380 : #ifdef CONFIG_MODULE_TESTS
3381 2149 : } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
3382 1 : if (hapd_module_tests() < 0)
3383 0 : reply_len = -1;
3384 : #endif /* CONFIG_MODULE_TESTS */
3385 : #ifdef CONFIG_FST
3386 2148 : } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
3387 274 : if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
3388 262 : reply_len = os_snprintf(reply, reply_size, "OK\n");
3389 : else
3390 12 : reply_len = -1;
3391 1874 : } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
3392 260 : if (!hostapd_global_ctrl_iface_fst_detach(interfaces, buf + 11))
3393 255 : reply_len = os_snprintf(reply, reply_size, "OK\n");
3394 : else
3395 5 : reply_len = -1;
3396 1614 : } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
3397 1604 : reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
3398 : #endif /* CONFIG_FST */
3399 10 : } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
3400 8 : if (!hostapd_global_ctrl_iface_dup_network(interfaces,
3401 : buf + 12))
3402 8 : reply_len = os_snprintf(reply, reply_size, "OK\n");
3403 : else
3404 0 : reply_len = -1;
3405 2 : } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
3406 0 : reply_len = hostapd_global_ctrl_iface_interfaces(
3407 : interfaces, buf + 10, reply, sizeof(buffer));
3408 2 : } else if (os_strcmp(buf, "TERMINATE") == 0) {
3409 0 : eloop_terminate();
3410 : } else {
3411 2 : wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
3412 : "ignored");
3413 2 : reply_len = -1;
3414 : }
3415 :
3416 : send_reply:
3417 32105 : if (reply_len < 0) {
3418 8301 : os_memcpy(reply, "FAIL\n", 5);
3419 8301 : reply_len = 5;
3420 : }
3421 :
3422 32105 : if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
3423 : fromlen) < 0) {
3424 0 : wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
3425 0 : strerror(errno));
3426 : }
3427 32105 : os_free(reply);
3428 : }
3429 :
3430 :
3431 : #ifndef CONFIG_CTRL_IFACE_UDP
3432 20 : static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
3433 : {
3434 : char *buf;
3435 : size_t len;
3436 :
3437 20 : if (interface->global_iface_path == NULL)
3438 0 : return NULL;
3439 :
3440 40 : len = os_strlen(interface->global_iface_path) +
3441 20 : os_strlen(interface->global_iface_name) + 2;
3442 20 : buf = os_malloc(len);
3443 20 : if (buf == NULL)
3444 0 : return NULL;
3445 :
3446 20 : os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
3447 : interface->global_iface_name);
3448 20 : buf[len - 1] = '\0';
3449 20 : return buf;
3450 : }
3451 : #endif /* CONFIG_CTRL_IFACE_UDP */
3452 :
3453 :
3454 16 : int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
3455 : {
3456 : #ifdef CONFIG_CTRL_IFACE_UDP
3457 : int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
3458 : char p[32] = { 0 };
3459 : char *pos;
3460 : struct addrinfo hints = { 0 }, *res, *saveres;
3461 : int n;
3462 :
3463 : if (interface->global_ctrl_sock > -1) {
3464 : wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
3465 : return 0;
3466 : }
3467 :
3468 : if (interface->global_iface_path == NULL)
3469 : return 0;
3470 :
3471 : pos = os_strstr(interface->global_iface_path, "udp:");
3472 : if (pos) {
3473 : pos += 4;
3474 : port = atoi(pos);
3475 : if (port <= 0) {
3476 : wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
3477 : goto fail;
3478 : }
3479 : }
3480 :
3481 : dl_list_init(&interface->global_ctrl_dst);
3482 : interface->global_ctrl_sock = -1;
3483 : os_get_random(gcookie, COOKIE_LEN);
3484 :
3485 : #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3486 : hints.ai_flags = AI_PASSIVE;
3487 : #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3488 :
3489 : #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3490 : hints.ai_family = AF_INET6;
3491 : #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3492 : hints.ai_family = AF_INET;
3493 : #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3494 : hints.ai_socktype = SOCK_DGRAM;
3495 :
3496 : try_again:
3497 : os_snprintf(p, sizeof(p), "%d", port);
3498 : n = getaddrinfo(NULL, p, &hints, &res);
3499 : if (n) {
3500 : wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
3501 : goto fail;
3502 : }
3503 :
3504 : saveres = res;
3505 : interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
3506 : res->ai_protocol);
3507 : if (interface->global_ctrl_sock < 0) {
3508 : wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
3509 : goto fail;
3510 : }
3511 :
3512 : if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
3513 : 0) {
3514 : port++;
3515 : if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
3516 : HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
3517 : goto try_again;
3518 : wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
3519 : goto fail;
3520 : }
3521 :
3522 : freeaddrinfo(saveres);
3523 :
3524 : wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
3525 :
3526 : if (eloop_register_read_sock(interface->global_ctrl_sock,
3527 : hostapd_global_ctrl_iface_receive,
3528 : interface, NULL) < 0) {
3529 : hostapd_global_ctrl_iface_deinit(interface);
3530 : return -1;
3531 : }
3532 :
3533 : return 0;
3534 :
3535 : fail:
3536 : if (interface->global_ctrl_sock >= 0)
3537 : close(interface->global_ctrl_sock);
3538 : return -1;
3539 : #else /* CONFIG_CTRL_IFACE_UDP */
3540 : struct sockaddr_un addr;
3541 16 : int s = -1;
3542 16 : char *fname = NULL;
3543 :
3544 16 : if (interface->global_iface_path == NULL) {
3545 6 : wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
3546 6 : return 0;
3547 : }
3548 :
3549 10 : if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
3550 10 : if (errno == EEXIST) {
3551 10 : wpa_printf(MSG_DEBUG, "Using existing control "
3552 : "interface directory.");
3553 : } else {
3554 0 : wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
3555 0 : strerror(errno));
3556 0 : goto fail;
3557 : }
3558 0 : } else if (interface->ctrl_iface_group &&
3559 0 : chown(interface->global_iface_path, -1,
3560 : interface->ctrl_iface_group) < 0) {
3561 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
3562 0 : strerror(errno));
3563 0 : goto fail;
3564 : }
3565 :
3566 20 : if (os_strlen(interface->global_iface_path) + 1 +
3567 10 : os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
3568 0 : goto fail;
3569 :
3570 10 : s = socket(PF_UNIX, SOCK_DGRAM, 0);
3571 10 : if (s < 0) {
3572 0 : wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
3573 0 : goto fail;
3574 : }
3575 :
3576 10 : os_memset(&addr, 0, sizeof(addr));
3577 : #ifdef __FreeBSD__
3578 : addr.sun_len = sizeof(addr);
3579 : #endif /* __FreeBSD__ */
3580 10 : addr.sun_family = AF_UNIX;
3581 10 : fname = hostapd_global_ctrl_iface_path(interface);
3582 10 : if (fname == NULL)
3583 0 : goto fail;
3584 10 : os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
3585 10 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3586 0 : wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
3587 0 : strerror(errno));
3588 0 : if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3589 0 : wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
3590 : " allow connections - assuming it was left"
3591 : "over from forced program termination");
3592 0 : if (unlink(fname) < 0) {
3593 0 : wpa_printf(MSG_ERROR,
3594 : "Could not unlink existing ctrl_iface socket '%s': %s",
3595 0 : fname, strerror(errno));
3596 0 : goto fail;
3597 : }
3598 0 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
3599 : 0) {
3600 0 : wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
3601 0 : strerror(errno));
3602 0 : goto fail;
3603 : }
3604 0 : wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
3605 : "ctrl_iface socket '%s'", fname);
3606 : } else {
3607 0 : wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
3608 : "be in use - cannot override it");
3609 0 : wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
3610 : "not used anymore", fname);
3611 0 : os_free(fname);
3612 0 : fname = NULL;
3613 0 : goto fail;
3614 : }
3615 : }
3616 :
3617 10 : if (interface->ctrl_iface_group &&
3618 0 : chown(fname, -1, interface->ctrl_iface_group) < 0) {
3619 0 : wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
3620 0 : strerror(errno));
3621 0 : goto fail;
3622 : }
3623 :
3624 10 : if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
3625 0 : wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
3626 0 : strerror(errno));
3627 0 : goto fail;
3628 : }
3629 10 : os_free(fname);
3630 :
3631 10 : interface->global_ctrl_sock = s;
3632 10 : eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
3633 : interface, NULL);
3634 :
3635 10 : return 0;
3636 :
3637 : fail:
3638 0 : if (s >= 0)
3639 0 : close(s);
3640 0 : if (fname) {
3641 0 : unlink(fname);
3642 0 : os_free(fname);
3643 : }
3644 0 : return -1;
3645 : #endif /* CONFIG_CTRL_IFACE_UDP */
3646 : }
3647 :
3648 :
3649 25 : void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
3650 : {
3651 : #ifndef CONFIG_CTRL_IFACE_UDP
3652 25 : char *fname = NULL;
3653 : #endif /* CONFIG_CTRL_IFACE_UDP */
3654 : struct wpa_ctrl_dst *dst, *prev;
3655 :
3656 25 : if (interfaces->global_ctrl_sock > -1) {
3657 10 : eloop_unregister_read_sock(interfaces->global_ctrl_sock);
3658 10 : close(interfaces->global_ctrl_sock);
3659 10 : interfaces->global_ctrl_sock = -1;
3660 : #ifndef CONFIG_CTRL_IFACE_UDP
3661 10 : fname = hostapd_global_ctrl_iface_path(interfaces);
3662 10 : if (fname) {
3663 10 : unlink(fname);
3664 10 : os_free(fname);
3665 : }
3666 :
3667 20 : if (interfaces->global_iface_path &&
3668 10 : rmdir(interfaces->global_iface_path) < 0) {
3669 10 : if (errno == ENOTEMPTY) {
3670 0 : wpa_printf(MSG_DEBUG, "Control interface "
3671 : "directory not empty - leaving it "
3672 : "behind");
3673 : } else {
3674 10 : wpa_printf(MSG_ERROR,
3675 : "rmdir[ctrl_interface=%s]: %s",
3676 : interfaces->global_iface_path,
3677 10 : strerror(errno));
3678 : }
3679 : }
3680 : #endif /* CONFIG_CTRL_IFACE_UDP */
3681 : }
3682 :
3683 25 : os_free(interfaces->global_iface_path);
3684 25 : interfaces->global_iface_path = NULL;
3685 :
3686 25 : dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
3687 : struct wpa_ctrl_dst, list)
3688 0 : os_free(dst);
3689 25 : }
3690 :
3691 :
3692 122276 : static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
3693 : enum wpa_msg_type type,
3694 : const char *buf, size_t len)
3695 : {
3696 : struct wpa_ctrl_dst *dst, *next;
3697 : struct dl_list *ctrl_dst;
3698 : struct msghdr msg;
3699 : int idx;
3700 : struct iovec io[2];
3701 : char levelstr[10];
3702 : int s;
3703 :
3704 122276 : if (type != WPA_MSG_ONLY_GLOBAL) {
3705 120292 : s = hapd->ctrl_sock;
3706 120292 : ctrl_dst = &hapd->ctrl_dst;
3707 : } else {
3708 1984 : s = hapd->iface->interfaces->global_ctrl_sock;
3709 1984 : ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
3710 : }
3711 :
3712 122276 : if (s < 0 || dl_list_empty(ctrl_dst))
3713 161891 : return;
3714 :
3715 82661 : os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
3716 82661 : io[0].iov_base = levelstr;
3717 82661 : io[0].iov_len = os_strlen(levelstr);
3718 82661 : io[1].iov_base = (char *) buf;
3719 82661 : io[1].iov_len = len;
3720 82661 : os_memset(&msg, 0, sizeof(msg));
3721 82661 : msg.msg_iov = io;
3722 82661 : msg.msg_iovlen = 2;
3723 :
3724 82661 : idx = 0;
3725 168783 : dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
3726 86122 : if (level >= dst->debug_level) {
3727 18355 : sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
3728 : &dst->addr, dst->addrlen);
3729 18355 : msg.msg_name = &dst->addr;
3730 18355 : msg.msg_namelen = dst->addrlen;
3731 18355 : if (sendmsg(s, &msg, 0) < 0) {
3732 12 : int _errno = errno;
3733 24 : wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
3734 : "%d - %s",
3735 24 : idx, errno, strerror(errno));
3736 12 : dst->errors++;
3737 12 : if (dst->errors > 10 || _errno == ENOENT) {
3738 12 : if (type != WPA_MSG_ONLY_GLOBAL)
3739 4 : hostapd_ctrl_iface_detach(
3740 : hapd, &dst->addr,
3741 : dst->addrlen);
3742 : else
3743 16 : hostapd_global_ctrl_iface_detach(
3744 8 : hapd->iface->interfaces,
3745 : &dst->addr,
3746 : dst->addrlen);
3747 : }
3748 : } else
3749 18343 : dst->errors = 0;
3750 : }
3751 86122 : idx++;
3752 : }
3753 : }
3754 :
3755 : #endif /* CONFIG_NATIVE_WINDOWS */
|