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