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