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