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