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