ctrl_iface.c revision 7d17530e229db79208e99741071df97ea4faeec6
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	} else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
2371		if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
2372			reply_len = -1;
2373	} else if (os_strcmp(buf, "STOP_AP") == 0) {
2374		if (hostapd_ctrl_iface_stop_ap(hapd))
2375			reply_len = -1;
2376#ifdef CONFIG_IEEE80211W
2377#ifdef NEED_AP_MLME
2378	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
2379		if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
2380			reply_len = -1;
2381#endif /* NEED_AP_MLME */
2382#endif /* CONFIG_IEEE80211W */
2383#ifdef CONFIG_WPS
2384	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
2385		if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
2386			reply_len = -1;
2387	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
2388		reply_len = hostapd_ctrl_iface_wps_check_pin(
2389			hapd, buf + 14, reply, reply_size);
2390	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
2391		if (hostapd_wps_button_pushed(hapd, NULL))
2392			reply_len = -1;
2393	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
2394		if (hostapd_wps_cancel(hapd))
2395			reply_len = -1;
2396	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
2397		reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
2398							  reply, reply_size);
2399	} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
2400		if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
2401			reply_len = -1;
2402	} else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
2403		reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
2404							      reply_size);
2405#ifdef CONFIG_WPS_NFC
2406	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
2407		if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
2408			reply_len = -1;
2409	} else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
2410		reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
2411			hapd, buf + 21, reply, reply_size);
2412	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
2413		reply_len = hostapd_ctrl_iface_wps_nfc_token(
2414			hapd, buf + 14, reply, reply_size);
2415	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
2416		reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
2417			hapd, buf + 21, reply, reply_size);
2418	} else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
2419		if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
2420			reply_len = -1;
2421#endif /* CONFIG_WPS_NFC */
2422#endif /* CONFIG_WPS */
2423#ifdef CONFIG_INTERWORKING
2424	} else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
2425		if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
2426			reply_len = -1;
2427	} else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
2428		if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
2429			reply_len = -1;
2430#endif /* CONFIG_INTERWORKING */
2431#ifdef CONFIG_HS20
2432	} else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
2433		if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
2434			reply_len = -1;
2435	} else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
2436		if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
2437			reply_len = -1;
2438#endif /* CONFIG_HS20 */
2439#ifdef CONFIG_WNM
2440	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
2441		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
2442			reply_len = -1;
2443	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
2444		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
2445			reply_len = -1;
2446	} else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
2447		if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
2448			reply_len = -1;
2449#endif /* CONFIG_WNM */
2450	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
2451		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
2452							  reply_size);
2453	} else if (os_strncmp(buf, "SET ", 4) == 0) {
2454		if (hostapd_ctrl_iface_set(hapd, buf + 4))
2455			reply_len = -1;
2456	} else if (os_strncmp(buf, "GET ", 4) == 0) {
2457		reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
2458						   reply_size);
2459	} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
2460		if (hostapd_ctrl_iface_enable(hapd->iface))
2461			reply_len = -1;
2462	} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
2463		if (hostapd_ctrl_iface_reload(hapd->iface))
2464			reply_len = -1;
2465	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
2466		if (hostapd_ctrl_iface_disable(hapd->iface))
2467			reply_len = -1;
2468	} else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
2469		if (ieee802_11_set_beacon(hapd))
2470			reply_len = -1;
2471#ifdef CONFIG_TESTING_OPTIONS
2472	} else if (os_strncmp(buf, "RADAR ", 6) == 0) {
2473		if (hostapd_ctrl_iface_radar(hapd, buf + 6))
2474			reply_len = -1;
2475	} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
2476		if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
2477			reply_len = -1;
2478	} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
2479		if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
2480			reply_len = -1;
2481	} else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
2482		if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
2483			reply_len = -1;
2484	} else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
2485		if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
2486			reply_len = -1;
2487	} else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
2488		if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
2489			reply_len = -1;
2490	} else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
2491		if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
2492			reply_len = -1;
2493	} else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
2494		reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
2495							reply_size);
2496	} else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
2497		if (hostapd_ctrl_test_fail(hapd, buf + 10) < 0)
2498			reply_len = -1;
2499	} else if (os_strcmp(buf, "GET_FAIL") == 0) {
2500		reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
2501#endif /* CONFIG_TESTING_OPTIONS */
2502	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
2503		if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
2504			reply_len = -1;
2505	} else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
2506		reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
2507						      reply_size);
2508	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
2509		ieee802_1x_erp_flush(hapd);
2510#ifdef RADIUS_SERVER
2511		radius_server_erp_flush(hapd->radius_srv);
2512#endif /* RADIUS_SERVER */
2513	} else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
2514		if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
2515			reply_len = -1;
2516	} else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
2517		if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
2518			reply_len = -1;
2519	} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
2520		reply_len = hostapd_ctrl_iface_log_level(
2521			hapd, buf + 9, reply, reply_size);
2522#ifdef NEED_AP_MLME
2523	} else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
2524		reply_len = hostapd_ctrl_iface_track_sta_list(
2525			hapd, reply, reply_size);
2526#endif /* NEED_AP_MLME */
2527	} else if (os_strcmp(buf, "PMKSA") == 0) {
2528		reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
2529							  reply_size);
2530	} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
2531		hostapd_ctrl_iface_pmksa_flush(hapd);
2532	} else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
2533		if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
2534			reply_len = -1;
2535	} else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
2536		if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
2537			reply_len = -1;
2538	} else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
2539		if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
2540			reply_len = -1;
2541	} else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
2542		if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
2543			reply_len = -1;
2544	} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
2545		reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
2546						      reply_size);
2547	} else {
2548		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
2549		reply_len = 16;
2550	}
2551
2552	if (reply_len < 0) {
2553		os_memcpy(reply, "FAIL\n", 5);
2554		reply_len = 5;
2555	}
2556
2557	return reply_len;
2558}
2559
2560
2561static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
2562				       void *sock_ctx)
2563{
2564	struct hostapd_data *hapd = eloop_ctx;
2565	char buf[4096];
2566	int res;
2567	struct sockaddr_storage from;
2568	socklen_t fromlen = sizeof(from);
2569	char *reply, *pos = buf;
2570	const int reply_size = 4096;
2571	int reply_len;
2572	int level = MSG_DEBUG;
2573#ifdef CONFIG_CTRL_IFACE_UDP
2574	unsigned char lcookie[COOKIE_LEN];
2575#endif /* CONFIG_CTRL_IFACE_UDP */
2576
2577	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
2578		       (struct sockaddr *) &from, &fromlen);
2579	if (res < 0) {
2580		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
2581			   strerror(errno));
2582		return;
2583	}
2584	buf[res] = '\0';
2585
2586	reply = os_malloc(reply_size);
2587	if (reply == NULL) {
2588		if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
2589			   fromlen) < 0) {
2590			wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2591				   strerror(errno));
2592		}
2593		return;
2594	}
2595
2596#ifdef CONFIG_CTRL_IFACE_UDP
2597	if (os_strcmp(buf, "GET_COOKIE") == 0) {
2598		os_memcpy(reply, "COOKIE=", 7);
2599		wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
2600				 cookie, COOKIE_LEN);
2601		reply_len = 7 + 2 * COOKIE_LEN;
2602		goto done;
2603	}
2604
2605	if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
2606	    hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
2607		wpa_printf(MSG_DEBUG,
2608			   "CTRL: No cookie in the request - drop request");
2609		os_free(reply);
2610		return;
2611	}
2612
2613	if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
2614		wpa_printf(MSG_DEBUG,
2615			   "CTRL: Invalid cookie in the request - drop request");
2616		os_free(reply);
2617		return;
2618	}
2619
2620	pos = buf + 7 + 2 * COOKIE_LEN;
2621	while (*pos == ' ')
2622		pos++;
2623#endif /* CONFIG_CTRL_IFACE_UDP */
2624
2625	if (os_strcmp(pos, "PING") == 0)
2626		level = MSG_EXCESSIVE;
2627	wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
2628
2629	reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
2630						       reply, reply_size,
2631						       &from, fromlen);
2632
2633#ifdef CONFIG_CTRL_IFACE_UDP
2634done:
2635#endif /* CONFIG_CTRL_IFACE_UDP */
2636	if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
2637		   fromlen) < 0) {
2638		wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
2639			   strerror(errno));
2640	}
2641	os_free(reply);
2642}
2643
2644
2645#ifndef CONFIG_CTRL_IFACE_UDP
2646static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
2647{
2648	char *buf;
2649	size_t len;
2650
2651	if (hapd->conf->ctrl_interface == NULL)
2652		return NULL;
2653
2654	len = os_strlen(hapd->conf->ctrl_interface) +
2655		os_strlen(hapd->conf->iface) + 2;
2656	buf = os_malloc(len);
2657	if (buf == NULL)
2658		return NULL;
2659
2660	os_snprintf(buf, len, "%s/%s",
2661		    hapd->conf->ctrl_interface, hapd->conf->iface);
2662	buf[len - 1] = '\0';
2663	return buf;
2664}
2665#endif /* CONFIG_CTRL_IFACE_UDP */
2666
2667
2668static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
2669				      enum wpa_msg_type type,
2670				      const char *txt, size_t len)
2671{
2672	struct hostapd_data *hapd = ctx;
2673	if (hapd == NULL)
2674		return;
2675	hostapd_ctrl_iface_send(hapd, level, type, txt, len);
2676}
2677
2678
2679int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
2680{
2681#ifdef CONFIG_CTRL_IFACE_UDP
2682	int port = HOSTAPD_CTRL_IFACE_PORT;
2683	char p[32] = { 0 };
2684	char port_str[40], *tmp;
2685	char *pos;
2686	struct addrinfo hints = { 0 }, *res, *saveres;
2687	int n;
2688
2689	if (hapd->ctrl_sock > -1) {
2690		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
2691		return 0;
2692	}
2693
2694	if (hapd->conf->ctrl_interface == NULL)
2695		return 0;
2696
2697	pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
2698	if (pos) {
2699		pos += 4;
2700		port = atoi(pos);
2701		if (port <= 0) {
2702			wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
2703			goto fail;
2704		}
2705	}
2706
2707	dl_list_init(&hapd->ctrl_dst);
2708	hapd->ctrl_sock = -1;
2709	os_get_random(cookie, COOKIE_LEN);
2710
2711#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
2712	hints.ai_flags = AI_PASSIVE;
2713#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
2714
2715#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
2716	hints.ai_family = AF_INET6;
2717#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
2718	hints.ai_family = AF_INET;
2719#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
2720	hints.ai_socktype = SOCK_DGRAM;
2721
2722try_again:
2723	os_snprintf(p, sizeof(p), "%d", port);
2724	n = getaddrinfo(NULL, p, &hints, &res);
2725	if (n) {
2726		wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
2727		goto fail;
2728	}
2729
2730	saveres = res;
2731	hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
2732				 res->ai_protocol);
2733	if (hapd->ctrl_sock < 0) {
2734		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
2735		goto fail;
2736	}
2737
2738	if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
2739		port--;
2740		if ((HOSTAPD_CTRL_IFACE_PORT - port) <
2741		    HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
2742			goto try_again;
2743		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
2744		goto fail;
2745	}
2746
2747	freeaddrinfo(saveres);
2748
2749	os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
2750	tmp = os_strdup(port_str);
2751	if (tmp) {
2752		os_free(hapd->conf->ctrl_interface);
2753		hapd->conf->ctrl_interface = tmp;
2754	}
2755	wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
2756
2757	if (eloop_register_read_sock(hapd->ctrl_sock,
2758				     hostapd_ctrl_iface_receive, hapd, NULL) <
2759	    0) {
2760		hostapd_ctrl_iface_deinit(hapd);
2761		return -1;
2762	}
2763
2764	hapd->msg_ctx = hapd;
2765	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
2766
2767	return 0;
2768
2769fail:
2770	if (hapd->ctrl_sock >= 0)
2771		close(hapd->ctrl_sock);
2772	return -1;
2773#else /* CONFIG_CTRL_IFACE_UDP */
2774	struct sockaddr_un addr;
2775	int s = -1;
2776	char *fname = NULL;
2777
2778	if (hapd->ctrl_sock > -1) {
2779		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
2780		return 0;
2781	}
2782
2783	dl_list_init(&hapd->ctrl_dst);
2784
2785	if (hapd->conf->ctrl_interface == NULL)
2786		return 0;
2787
2788	if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2789		if (errno == EEXIST) {
2790			wpa_printf(MSG_DEBUG, "Using existing control "
2791				   "interface directory.");
2792		} else {
2793			wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
2794				   strerror(errno));
2795			goto fail;
2796		}
2797	}
2798
2799	if (hapd->conf->ctrl_interface_gid_set &&
2800	    chown(hapd->conf->ctrl_interface, -1,
2801		  hapd->conf->ctrl_interface_gid) < 0) {
2802		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2803			   strerror(errno));
2804		return -1;
2805	}
2806
2807	if (!hapd->conf->ctrl_interface_gid_set &&
2808	    hapd->iface->interfaces->ctrl_iface_group &&
2809	    chown(hapd->conf->ctrl_interface, -1,
2810		  hapd->iface->interfaces->ctrl_iface_group) < 0) {
2811		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
2812			   strerror(errno));
2813		return -1;
2814	}
2815
2816#ifdef ANDROID
2817	/*
2818	 * Android is using umask 0077 which would leave the control interface
2819	 * directory without group access. This breaks things since Wi-Fi
2820	 * framework assumes that this directory can be accessed by other
2821	 * applications in the wifi group. Fix this by adding group access even
2822	 * if umask value would prevent this.
2823	 */
2824	if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
2825		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
2826			   strerror(errno));
2827		/* Try to continue anyway */
2828	}
2829#endif /* ANDROID */
2830
2831	if (os_strlen(hapd->conf->ctrl_interface) + 1 +
2832	    os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
2833		goto fail;
2834
2835	s = socket(PF_UNIX, SOCK_DGRAM, 0);
2836	if (s < 0) {
2837		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
2838		goto fail;
2839	}
2840
2841	os_memset(&addr, 0, sizeof(addr));
2842#ifdef __FreeBSD__
2843	addr.sun_len = sizeof(addr);
2844#endif /* __FreeBSD__ */
2845	addr.sun_family = AF_UNIX;
2846	fname = hostapd_ctrl_iface_path(hapd);
2847	if (fname == NULL)
2848		goto fail;
2849	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
2850	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2851		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
2852			   strerror(errno));
2853		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2854			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
2855				   " allow connections - assuming it was left"
2856				   "over from forced program termination");
2857			if (unlink(fname) < 0) {
2858				wpa_printf(MSG_ERROR,
2859					   "Could not unlink existing ctrl_iface socket '%s': %s",
2860					   fname, strerror(errno));
2861				goto fail;
2862			}
2863			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
2864			    0) {
2865				wpa_printf(MSG_ERROR,
2866					   "hostapd-ctrl-iface: bind(PF_UNIX): %s",
2867					   strerror(errno));
2868				goto fail;
2869			}
2870			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
2871				   "ctrl_iface socket '%s'", fname);
2872		} else {
2873			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
2874				   "be in use - cannot override it");
2875			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
2876				   "not used anymore", fname);
2877			os_free(fname);
2878			fname = NULL;
2879			goto fail;
2880		}
2881	}
2882
2883	if (hapd->conf->ctrl_interface_gid_set &&
2884	    chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
2885		wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2886			   strerror(errno));
2887		goto fail;
2888	}
2889
2890	if (!hapd->conf->ctrl_interface_gid_set &&
2891	    hapd->iface->interfaces->ctrl_iface_group &&
2892	    chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
2893		wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
2894			   strerror(errno));
2895		goto fail;
2896	}
2897
2898	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
2899		wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
2900			   strerror(errno));
2901		goto fail;
2902	}
2903	os_free(fname);
2904
2905	hapd->ctrl_sock = s;
2906	if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
2907				     NULL) < 0) {
2908		hostapd_ctrl_iface_deinit(hapd);
2909		return -1;
2910	}
2911	hapd->msg_ctx = hapd;
2912	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
2913
2914	return 0;
2915
2916fail:
2917	if (s >= 0)
2918		close(s);
2919	if (fname) {
2920		unlink(fname);
2921		os_free(fname);
2922	}
2923	return -1;
2924#endif /* CONFIG_CTRL_IFACE_UDP */
2925}
2926
2927
2928void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
2929{
2930	struct wpa_ctrl_dst *dst, *prev;
2931
2932	if (hapd->ctrl_sock > -1) {
2933#ifndef CONFIG_CTRL_IFACE_UDP
2934		char *fname;
2935#endif /* !CONFIG_CTRL_IFACE_UDP */
2936
2937		eloop_unregister_read_sock(hapd->ctrl_sock);
2938		close(hapd->ctrl_sock);
2939		hapd->ctrl_sock = -1;
2940#ifndef CONFIG_CTRL_IFACE_UDP
2941		fname = hostapd_ctrl_iface_path(hapd);
2942		if (fname)
2943			unlink(fname);
2944		os_free(fname);
2945
2946		if (hapd->conf->ctrl_interface &&
2947		    rmdir(hapd->conf->ctrl_interface) < 0) {
2948			if (errno == ENOTEMPTY) {
2949				wpa_printf(MSG_DEBUG, "Control interface "
2950					   "directory not empty - leaving it "
2951					   "behind");
2952			} else {
2953				wpa_printf(MSG_ERROR,
2954					   "rmdir[ctrl_interface=%s]: %s",
2955					   hapd->conf->ctrl_interface,
2956					   strerror(errno));
2957			}
2958		}
2959#endif /* !CONFIG_CTRL_IFACE_UDP */
2960	}
2961
2962	dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
2963			      list)
2964		os_free(dst);
2965
2966#ifdef CONFIG_TESTING_OPTIONS
2967	l2_packet_deinit(hapd->l2_test);
2968	hapd->l2_test = NULL;
2969#endif /* CONFIG_TESTING_OPTIONS */
2970}
2971
2972
2973static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
2974				  char *buf)
2975{
2976	if (hostapd_add_iface(interfaces, buf) < 0) {
2977		wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
2978		return -1;
2979	}
2980	return 0;
2981}
2982
2983
2984static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
2985				     char *buf)
2986{
2987	if (hostapd_remove_iface(interfaces, buf) < 0) {
2988		wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
2989		return -1;
2990	}
2991	return 0;
2992}
2993
2994
2995static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
2996					    struct sockaddr_storage *from,
2997					    socklen_t fromlen)
2998{
2999	return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen);
3000}
3001
3002
3003static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
3004					    struct sockaddr_storage *from,
3005					    socklen_t fromlen)
3006{
3007	return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
3008}
3009
3010
3011static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
3012{
3013#ifdef CONFIG_WPS_TESTING
3014	wps_version_number = 0x20;
3015	wps_testing_dummy_cred = 0;
3016	wps_corrupt_pkhash = 0;
3017#endif /* CONFIG_WPS_TESTING */
3018}
3019
3020
3021#ifdef CONFIG_FST
3022
3023static int
3024hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
3025				     const char *cmd)
3026{
3027	char ifname[IFNAMSIZ + 1];
3028	struct fst_iface_cfg cfg;
3029	struct hostapd_data *hapd;
3030	struct fst_wpa_obj iface_obj;
3031
3032	if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
3033		hapd = hostapd_get_iface(interfaces, ifname);
3034		if (hapd) {
3035			if (hapd->iface->fst) {
3036				wpa_printf(MSG_INFO, "FST: Already attached");
3037				return -1;
3038			}
3039			fst_hostapd_fill_iface_obj(hapd, &iface_obj);
3040			hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
3041						      &iface_obj, &cfg);
3042			if (hapd->iface->fst)
3043				return 0;
3044		}
3045	}
3046
3047	return -EINVAL;
3048}
3049
3050
3051static int
3052hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
3053				     const char *cmd)
3054{
3055	char ifname[IFNAMSIZ + 1];
3056	struct hostapd_data * hapd;
3057
3058	if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
3059		hapd = hostapd_get_iface(interfaces, ifname);
3060		if (hapd) {
3061			if (!fst_iface_detach(ifname)) {
3062				hapd->iface->fst = NULL;
3063				hapd->iface->fst_ies = NULL;
3064				return 0;
3065			}
3066		}
3067	}
3068
3069	return -EINVAL;
3070}
3071
3072#endif /* CONFIG_FST */
3073
3074
3075static struct hostapd_data *
3076hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
3077			    const char *ifname)
3078{
3079	size_t i, j;
3080
3081	for (i = 0; i < interfaces->count; i++) {
3082		struct hostapd_iface *iface = interfaces->iface[i];
3083
3084		for (j = 0; j < iface->num_bss; j++) {
3085			struct hostapd_data *hapd;
3086
3087			hapd = iface->bss[j];
3088			if (os_strcmp(ifname, hapd->conf->iface) == 0)
3089				return hapd;
3090		}
3091	}
3092
3093	return NULL;
3094}
3095
3096
3097static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
3098					struct hostapd_data *dst_hapd,
3099					const char *param)
3100{
3101	int res;
3102	char *value;
3103
3104	value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
3105	if (!value) {
3106		wpa_printf(MSG_ERROR,
3107			   "DUP: cannot allocate buffer to stringify %s",
3108			   param);
3109		goto error_return;
3110	}
3111
3112	if (os_strcmp(param, "wpa") == 0) {
3113		os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
3114			    src_hapd->conf->wpa);
3115	} else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
3116		   src_hapd->conf->wpa_key_mgmt) {
3117		res = hostapd_ctrl_iface_get_key_mgmt(
3118			src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
3119		if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
3120			goto error_stringify;
3121	} else if (os_strcmp(param, "wpa_pairwise") == 0 &&
3122		   src_hapd->conf->wpa_pairwise) {
3123		res = wpa_write_ciphers(value,
3124					value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3125					src_hapd->conf->wpa_pairwise, " ");
3126		if (res < 0)
3127			goto error_stringify;
3128	} else if (os_strcmp(param, "rsn_pairwise") == 0 &&
3129		   src_hapd->conf->rsn_pairwise) {
3130		res = wpa_write_ciphers(value,
3131					value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3132					src_hapd->conf->rsn_pairwise, " ");
3133		if (res < 0)
3134			goto error_stringify;
3135	} else if (os_strcmp(param, "wpa_passphrase") == 0 &&
3136		   src_hapd->conf->ssid.wpa_passphrase) {
3137		os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
3138			    src_hapd->conf->ssid.wpa_passphrase);
3139	} else if (os_strcmp(param, "wpa_psk") == 0 &&
3140		   src_hapd->conf->ssid.wpa_psk_set) {
3141		wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3142			src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
3143	} else {
3144		wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
3145		goto error_return;
3146	}
3147
3148	res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
3149	os_free(value);
3150	return res;
3151
3152error_stringify:
3153	wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
3154error_return:
3155	os_free(value);
3156	return -1;
3157}
3158
3159
3160static int
3161hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
3162				     const char *input,
3163				     char *reply, int reply_size)
3164{
3165	size_t i, j;
3166	int res;
3167	char *pos, *end;
3168	struct hostapd_iface *iface;
3169	int show_ctrl = 0;
3170
3171	if (input)
3172		show_ctrl = !!os_strstr(input, "ctrl");
3173
3174	pos = reply;
3175	end = reply + reply_size;
3176
3177	for (i = 0; i < interfaces->count; i++) {
3178		iface = interfaces->iface[i];
3179
3180		for (j = 0; j < iface->num_bss; j++) {
3181			struct hostapd_bss_config *conf;
3182
3183			conf = iface->conf->bss[j];
3184			if (show_ctrl)
3185				res = os_snprintf(pos, end - pos,
3186						  "%s ctrl_iface=%s\n",
3187						  conf->iface,
3188						  conf->ctrl_interface ?
3189						  conf->ctrl_interface : "N/A");
3190			else
3191				res = os_snprintf(pos, end - pos, "%s\n",
3192						  conf->iface);
3193			if (os_snprintf_error(end - pos, res)) {
3194				*pos = '\0';
3195				return pos - reply;
3196			}
3197			pos += res;
3198		}
3199	}
3200
3201	return pos - reply;
3202}
3203
3204
3205static int
3206hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
3207				      char *cmd)
3208{
3209	char *p_start = cmd, *p_end;
3210	struct hostapd_data *src_hapd, *dst_hapd;
3211
3212	/* cmd: "<src ifname> <dst ifname> <variable name> */
3213
3214	p_end = os_strchr(p_start, ' ');
3215	if (!p_end) {
3216		wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
3217			   cmd);
3218		return -1;
3219	}
3220
3221	*p_end = '\0';
3222	src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
3223	if (!src_hapd) {
3224		wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
3225			   p_start);
3226		return -1;
3227	}
3228
3229	p_start = p_end + 1;
3230	p_end = os_strchr(p_start, ' ');
3231	if (!p_end) {
3232		wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
3233			   cmd);
3234		return -1;
3235	}
3236
3237	*p_end = '\0';
3238	dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
3239	if (!dst_hapd) {
3240		wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
3241			   p_start);
3242		return -1;
3243	}
3244
3245	p_start = p_end + 1;
3246	return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
3247}
3248
3249
3250static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
3251					    const char *ifname,
3252					    char *buf, char *reply,
3253					    int reply_size,
3254					    struct sockaddr_storage *from,
3255					    socklen_t fromlen)
3256{
3257	struct hostapd_data *hapd;
3258
3259	hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
3260	if (hapd == NULL) {
3261		int res;
3262
3263		res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
3264		if (os_snprintf_error(reply_size, res))
3265			return -1;
3266		return res;
3267	}
3268
3269	return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
3270						  from, fromlen);
3271}
3272
3273
3274static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
3275					      void *sock_ctx)
3276{
3277	void *interfaces = eloop_ctx;
3278	char buffer[256], *buf = buffer;
3279	int res;
3280	struct sockaddr_storage from;
3281	socklen_t fromlen = sizeof(from);
3282	char *reply;
3283	int reply_len;
3284	const int reply_size = 4096;
3285#ifdef CONFIG_CTRL_IFACE_UDP
3286	unsigned char lcookie[COOKIE_LEN];
3287#endif /* CONFIG_CTRL_IFACE_UDP */
3288
3289	res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
3290		       (struct sockaddr *) &from, &fromlen);
3291	if (res < 0) {
3292		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
3293			   strerror(errno));
3294		return;
3295	}
3296	buf[res] = '\0';
3297	wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
3298
3299	reply = os_malloc(reply_size);
3300	if (reply == NULL) {
3301		if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
3302			   fromlen) < 0) {
3303			wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
3304				   strerror(errno));
3305		}
3306		return;
3307	}
3308
3309	os_memcpy(reply, "OK\n", 3);
3310	reply_len = 3;
3311
3312#ifdef CONFIG_CTRL_IFACE_UDP
3313	if (os_strcmp(buf, "GET_COOKIE") == 0) {
3314		os_memcpy(reply, "COOKIE=", 7);
3315		wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
3316				 gcookie, COOKIE_LEN);
3317		reply_len = 7 + 2 * COOKIE_LEN;
3318		goto send_reply;
3319	}
3320
3321	if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
3322	    hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
3323		wpa_printf(MSG_DEBUG,
3324			   "CTRL: No cookie in the request - drop request");
3325		os_free(reply);
3326		return;
3327	}
3328
3329	if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
3330		wpa_printf(MSG_DEBUG,
3331			   "CTRL: Invalid cookie in the request - drop request");
3332		os_free(reply);
3333		return;
3334	}
3335
3336	buf += 7 + 2 * COOKIE_LEN;
3337	while (*buf == ' ')
3338		buf++;
3339#endif /* CONFIG_CTRL_IFACE_UDP */
3340
3341	if (os_strncmp(buf, "IFNAME=", 7) == 0) {
3342		char *pos = os_strchr(buf + 7, ' ');
3343
3344		if (pos) {
3345			*pos++ = '\0';
3346			reply_len = hostapd_global_ctrl_iface_ifname(
3347				interfaces, buf + 7, pos, reply, reply_size,
3348				&from, fromlen);
3349			goto send_reply;
3350		}
3351	}
3352
3353	if (os_strcmp(buf, "PING") == 0) {
3354		os_memcpy(reply, "PONG\n", 5);
3355		reply_len = 5;
3356	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
3357		if (wpa_debug_reopen_file() < 0)
3358			reply_len = -1;
3359	} else if (os_strcmp(buf, "FLUSH") == 0) {
3360		hostapd_ctrl_iface_flush(interfaces);
3361	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
3362		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
3363			reply_len = -1;
3364	} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
3365		if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
3366			reply_len = -1;
3367	} else if (os_strcmp(buf, "ATTACH") == 0) {
3368		if (hostapd_global_ctrl_iface_attach(interfaces, &from,
3369						     fromlen))
3370			reply_len = -1;
3371	} else if (os_strcmp(buf, "DETACH") == 0) {
3372		if (hostapd_global_ctrl_iface_detach(interfaces, &from,
3373			fromlen))
3374			reply_len = -1;
3375#ifdef CONFIG_MODULE_TESTS
3376	} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
3377		if (hapd_module_tests() < 0)
3378			reply_len = -1;
3379#endif /* CONFIG_MODULE_TESTS */
3380#ifdef CONFIG_FST
3381	} else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
3382		if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
3383			reply_len = os_snprintf(reply, reply_size, "OK\n");
3384		else
3385			reply_len = -1;
3386	} else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
3387		if (!hostapd_global_ctrl_iface_fst_detach(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-MANAGER ", 12) == 0) {
3392		reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
3393#endif /* CONFIG_FST */
3394	} else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
3395		if (!hostapd_global_ctrl_iface_dup_network(interfaces,
3396							   buf + 12))
3397			reply_len = os_snprintf(reply, reply_size, "OK\n");
3398		else
3399			reply_len = -1;
3400	} else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
3401		reply_len = hostapd_global_ctrl_iface_interfaces(
3402			interfaces, buf + 10, reply, sizeof(buffer));
3403	} else if (os_strcmp(buf, "TERMINATE") == 0) {
3404		eloop_terminate();
3405	} else {
3406		wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
3407			   "ignored");
3408		reply_len = -1;
3409	}
3410
3411send_reply:
3412	if (reply_len < 0) {
3413		os_memcpy(reply, "FAIL\n", 5);
3414		reply_len = 5;
3415	}
3416
3417	if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
3418		   fromlen) < 0) {
3419		wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
3420			   strerror(errno));
3421	}
3422	os_free(reply);
3423}
3424
3425
3426#ifndef CONFIG_CTRL_IFACE_UDP
3427static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
3428{
3429	char *buf;
3430	size_t len;
3431
3432	if (interface->global_iface_path == NULL)
3433		return NULL;
3434
3435	len = os_strlen(interface->global_iface_path) +
3436		os_strlen(interface->global_iface_name) + 2;
3437	buf = os_malloc(len);
3438	if (buf == NULL)
3439		return NULL;
3440
3441	os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
3442		    interface->global_iface_name);
3443	buf[len - 1] = '\0';
3444	return buf;
3445}
3446#endif /* CONFIG_CTRL_IFACE_UDP */
3447
3448
3449int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
3450{
3451#ifdef CONFIG_CTRL_IFACE_UDP
3452	int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
3453	char p[32] = { 0 };
3454	char *pos;
3455	struct addrinfo hints = { 0 }, *res, *saveres;
3456	int n;
3457
3458	if (interface->global_ctrl_sock > -1) {
3459		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
3460		return 0;
3461	}
3462
3463	if (interface->global_iface_path == NULL)
3464		return 0;
3465
3466	pos = os_strstr(interface->global_iface_path, "udp:");
3467	if (pos) {
3468		pos += 4;
3469		port = atoi(pos);
3470		if (port <= 0) {
3471			wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
3472			goto fail;
3473		}
3474	}
3475
3476	dl_list_init(&interface->global_ctrl_dst);
3477	interface->global_ctrl_sock = -1;
3478	os_get_random(gcookie, COOKIE_LEN);
3479
3480#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3481	hints.ai_flags = AI_PASSIVE;
3482#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3483
3484#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3485	hints.ai_family = AF_INET6;
3486#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3487	hints.ai_family = AF_INET;
3488#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3489	hints.ai_socktype = SOCK_DGRAM;
3490
3491try_again:
3492	os_snprintf(p, sizeof(p), "%d", port);
3493	n = getaddrinfo(NULL, p, &hints, &res);
3494	if (n) {
3495		wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
3496		goto fail;
3497	}
3498
3499	saveres = res;
3500	interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
3501					     res->ai_protocol);
3502	if (interface->global_ctrl_sock < 0) {
3503		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
3504		goto fail;
3505	}
3506
3507	if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
3508	    0) {
3509		port++;
3510		if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
3511		    HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
3512			goto try_again;
3513		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
3514		goto fail;
3515	}
3516
3517	freeaddrinfo(saveres);
3518
3519	wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
3520
3521	if (eloop_register_read_sock(interface->global_ctrl_sock,
3522				     hostapd_global_ctrl_iface_receive,
3523				     interface, NULL) < 0) {
3524		hostapd_global_ctrl_iface_deinit(interface);
3525		return -1;
3526	}
3527
3528	return 0;
3529
3530fail:
3531	if (interface->global_ctrl_sock >= 0)
3532		close(interface->global_ctrl_sock);
3533	return -1;
3534#else /* CONFIG_CTRL_IFACE_UDP */
3535	struct sockaddr_un addr;
3536	int s = -1;
3537	char *fname = NULL;
3538
3539	if (interface->global_iface_path == NULL) {
3540		wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
3541		return 0;
3542	}
3543
3544	if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
3545		if (errno == EEXIST) {
3546			wpa_printf(MSG_DEBUG, "Using existing control "
3547				   "interface directory.");
3548		} else {
3549			wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
3550				   strerror(errno));
3551			goto fail;
3552		}
3553	} else if (interface->ctrl_iface_group &&
3554		   chown(interface->global_iface_path, -1,
3555			 interface->ctrl_iface_group) < 0) {
3556		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
3557			   strerror(errno));
3558		goto fail;
3559	}
3560
3561	if (os_strlen(interface->global_iface_path) + 1 +
3562	    os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
3563		goto fail;
3564
3565	s = socket(PF_UNIX, SOCK_DGRAM, 0);
3566	if (s < 0) {
3567		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
3568		goto fail;
3569	}
3570
3571	os_memset(&addr, 0, sizeof(addr));
3572#ifdef __FreeBSD__
3573	addr.sun_len = sizeof(addr);
3574#endif /* __FreeBSD__ */
3575	addr.sun_family = AF_UNIX;
3576	fname = hostapd_global_ctrl_iface_path(interface);
3577	if (fname == NULL)
3578		goto fail;
3579	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
3580	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3581		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
3582			   strerror(errno));
3583		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3584			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
3585				   " allow connections - assuming it was left"
3586				   "over from forced program termination");
3587			if (unlink(fname) < 0) {
3588				wpa_printf(MSG_ERROR,
3589					   "Could not unlink existing ctrl_iface socket '%s': %s",
3590					   fname, strerror(errno));
3591				goto fail;
3592			}
3593			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
3594			    0) {
3595				wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
3596					   strerror(errno));
3597				goto fail;
3598			}
3599			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
3600				   "ctrl_iface socket '%s'", fname);
3601		} else {
3602			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
3603				   "be in use - cannot override it");
3604			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
3605				   "not used anymore", fname);
3606			os_free(fname);
3607			fname = NULL;
3608			goto fail;
3609		}
3610	}
3611
3612	if (interface->ctrl_iface_group &&
3613	    chown(fname, -1, interface->ctrl_iface_group) < 0) {
3614		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
3615			   strerror(errno));
3616		goto fail;
3617	}
3618
3619	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
3620		wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
3621			   strerror(errno));
3622		goto fail;
3623	}
3624	os_free(fname);
3625
3626	interface->global_ctrl_sock = s;
3627	eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
3628				 interface, NULL);
3629
3630	return 0;
3631
3632fail:
3633	if (s >= 0)
3634		close(s);
3635	if (fname) {
3636		unlink(fname);
3637		os_free(fname);
3638	}
3639	return -1;
3640#endif /* CONFIG_CTRL_IFACE_UDP */
3641}
3642
3643
3644void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
3645{
3646#ifndef CONFIG_CTRL_IFACE_UDP
3647	char *fname = NULL;
3648#endif /* CONFIG_CTRL_IFACE_UDP */
3649	struct wpa_ctrl_dst *dst, *prev;
3650
3651	if (interfaces->global_ctrl_sock > -1) {
3652		eloop_unregister_read_sock(interfaces->global_ctrl_sock);
3653		close(interfaces->global_ctrl_sock);
3654		interfaces->global_ctrl_sock = -1;
3655#ifndef CONFIG_CTRL_IFACE_UDP
3656		fname = hostapd_global_ctrl_iface_path(interfaces);
3657		if (fname) {
3658			unlink(fname);
3659			os_free(fname);
3660		}
3661
3662		if (interfaces->global_iface_path &&
3663		    rmdir(interfaces->global_iface_path) < 0) {
3664			if (errno == ENOTEMPTY) {
3665				wpa_printf(MSG_DEBUG, "Control interface "
3666					   "directory not empty - leaving it "
3667					   "behind");
3668			} else {
3669				wpa_printf(MSG_ERROR,
3670					   "rmdir[ctrl_interface=%s]: %s",
3671					   interfaces->global_iface_path,
3672					   strerror(errno));
3673			}
3674		}
3675#endif /* CONFIG_CTRL_IFACE_UDP */
3676	}
3677
3678	os_free(interfaces->global_iface_path);
3679	interfaces->global_iface_path = NULL;
3680
3681	dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
3682			      struct wpa_ctrl_dst, list)
3683		os_free(dst);
3684}
3685
3686
3687static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
3688				    enum wpa_msg_type type,
3689				    const char *buf, size_t len)
3690{
3691	struct wpa_ctrl_dst *dst, *next;
3692	struct dl_list *ctrl_dst;
3693	struct msghdr msg;
3694	int idx;
3695	struct iovec io[2];
3696	char levelstr[10];
3697	int s;
3698
3699	if (type != WPA_MSG_ONLY_GLOBAL) {
3700		s = hapd->ctrl_sock;
3701		ctrl_dst = &hapd->ctrl_dst;
3702	} else {
3703		s = hapd->iface->interfaces->global_ctrl_sock;
3704		ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
3705	}
3706
3707	if (s < 0 || dl_list_empty(ctrl_dst))
3708		return;
3709
3710	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
3711	io[0].iov_base = levelstr;
3712	io[0].iov_len = os_strlen(levelstr);
3713	io[1].iov_base = (char *) buf;
3714	io[1].iov_len = len;
3715	os_memset(&msg, 0, sizeof(msg));
3716	msg.msg_iov = io;
3717	msg.msg_iovlen = 2;
3718
3719	idx = 0;
3720	dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
3721		if (level >= dst->debug_level) {
3722			sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
3723				       &dst->addr, dst->addrlen);
3724			msg.msg_name = &dst->addr;
3725			msg.msg_namelen = dst->addrlen;
3726			if (sendmsg(s, &msg, 0) < 0) {
3727				int _errno = errno;
3728				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
3729					   "%d - %s",
3730					   idx, errno, strerror(errno));
3731				dst->errors++;
3732				if (dst->errors > 10 || _errno == ENOENT) {
3733					if (type != WPA_MSG_ONLY_GLOBAL)
3734						hostapd_ctrl_iface_detach(
3735							hapd, &dst->addr,
3736							dst->addrlen);
3737					else
3738						hostapd_global_ctrl_iface_detach(
3739							hapd->iface->interfaces,
3740							&dst->addr,
3741							dst->addrlen);
3742				}
3743			} else
3744				dst->errors = 0;
3745		}
3746		idx++;
3747	}
3748}
3749
3750#endif /* CONFIG_NATIVE_WINDOWS */
3751