ctrl_iface.c revision 8bae4138a0356709720a96f3e50b4d734e532c12
1/*
2 * hostapd / UNIX domain socket -based control interface
3 * Copyright (c) 2004-2012, 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#include <sys/un.h>
14#include <sys/stat.h>
15#include <stddef.h>
16
17#include "utils/common.h"
18#include "utils/eloop.h"
19#include "common/version.h"
20#include "common/ieee802_11_defs.h"
21#include "drivers/driver.h"
22#include "radius/radius_client.h"
23#include "ap/hostapd.h"
24#include "ap/ap_config.h"
25#include "ap/ieee802_1x.h"
26#include "ap/wpa_auth.h"
27#include "ap/ieee802_11.h"
28#include "ap/sta_info.h"
29#include "ap/wps_hostapd.h"
30#include "ap/ctrl_iface_ap.h"
31#include "ap/ap_drv_ops.h"
32#include "ap/wpa_auth.h"
33#include "wps/wps_defs.h"
34#include "wps/wps.h"
35#include "config_file.h"
36#include "ctrl_iface.h"
37
38
39struct wpa_ctrl_dst {
40	struct wpa_ctrl_dst *next;
41	struct sockaddr_un addr;
42	socklen_t addrlen;
43	int debug_level;
44	int errors;
45};
46
47
48static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
49				    const char *buf, size_t len);
50
51
52static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
53				     struct sockaddr_un *from,
54				     socklen_t fromlen)
55{
56	struct wpa_ctrl_dst *dst;
57
58	dst = os_zalloc(sizeof(*dst));
59	if (dst == NULL)
60		return -1;
61	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
62	dst->addrlen = fromlen;
63	dst->debug_level = MSG_INFO;
64	dst->next = hapd->ctrl_dst;
65	hapd->ctrl_dst = dst;
66	wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
67		    (u8 *) from->sun_path,
68		    fromlen - offsetof(struct sockaddr_un, sun_path));
69	return 0;
70}
71
72
73static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
74				     struct sockaddr_un *from,
75				     socklen_t fromlen)
76{
77	struct wpa_ctrl_dst *dst, *prev = NULL;
78
79	dst = hapd->ctrl_dst;
80	while (dst) {
81		if (fromlen == dst->addrlen &&
82		    os_memcmp(from->sun_path, dst->addr.sun_path,
83			      fromlen - offsetof(struct sockaddr_un, sun_path))
84		    == 0) {
85			if (prev == NULL)
86				hapd->ctrl_dst = dst->next;
87			else
88				prev->next = dst->next;
89			os_free(dst);
90			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
91				    (u8 *) from->sun_path,
92				    fromlen -
93				    offsetof(struct sockaddr_un, sun_path));
94			return 0;
95		}
96		prev = dst;
97		dst = dst->next;
98	}
99	return -1;
100}
101
102
103static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
104				    struct sockaddr_un *from,
105				    socklen_t fromlen,
106				    char *level)
107{
108	struct wpa_ctrl_dst *dst;
109
110	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
111
112	dst = hapd->ctrl_dst;
113	while (dst) {
114		if (fromlen == dst->addrlen &&
115		    os_memcmp(from->sun_path, dst->addr.sun_path,
116			      fromlen - offsetof(struct sockaddr_un, sun_path))
117		    == 0) {
118			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
119				    "level", (u8 *) from->sun_path, fromlen -
120				    offsetof(struct sockaddr_un, sun_path));
121			dst->debug_level = atoi(level);
122			return 0;
123		}
124		dst = dst->next;
125	}
126
127	return -1;
128}
129
130
131static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
132				      const char *txtaddr)
133{
134	u8 addr[ETH_ALEN];
135	struct sta_info *sta;
136
137	wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
138
139	if (hwaddr_aton(txtaddr, addr))
140		return -1;
141
142	sta = ap_get_sta(hapd, addr);
143	if (sta)
144		return 0;
145
146	wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
147		   "notification", MAC2STR(addr));
148	sta = ap_sta_add(hapd, addr);
149	if (sta == NULL)
150		return -1;
151
152	hostapd_new_assoc_sta(hapd, sta, 0);
153	return 0;
154}
155
156
157#ifdef CONFIG_IEEE80211W
158#ifdef NEED_AP_MLME
159static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
160				       const char *txtaddr)
161{
162	u8 addr[ETH_ALEN];
163	u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
164
165	wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
166
167	if (hwaddr_aton(txtaddr, addr) ||
168	    os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
169		return -1;
170
171	ieee802_11_send_sa_query_req(hapd, addr, trans_id);
172
173	return 0;
174}
175#endif /* NEED_AP_MLME */
176#endif /* CONFIG_IEEE80211W */
177
178
179#ifdef CONFIG_WPS
180static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
181{
182	char *pin = os_strchr(txt, ' ');
183	char *timeout_txt;
184	int timeout;
185	u8 addr_buf[ETH_ALEN], *addr = NULL;
186	char *pos;
187
188	if (pin == NULL)
189		return -1;
190	*pin++ = '\0';
191
192	timeout_txt = os_strchr(pin, ' ');
193	if (timeout_txt) {
194		*timeout_txt++ = '\0';
195		timeout = atoi(timeout_txt);
196		pos = os_strchr(timeout_txt, ' ');
197		if (pos) {
198			*pos++ = '\0';
199			if (hwaddr_aton(pos, addr_buf) == 0)
200				addr = addr_buf;
201		}
202	} else
203		timeout = 0;
204
205	return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
206}
207
208
209static int hostapd_ctrl_iface_wps_check_pin(
210	struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
211{
212	char pin[9];
213	size_t len;
214	char *pos;
215	int ret;
216
217	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
218			      (u8 *) cmd, os_strlen(cmd));
219	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
220		if (*pos < '0' || *pos > '9')
221			continue;
222		pin[len++] = *pos;
223		if (len == 9) {
224			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
225			return -1;
226		}
227	}
228	if (len != 4 && len != 8) {
229		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
230		return -1;
231	}
232	pin[len] = '\0';
233
234	if (len == 8) {
235		unsigned int pin_val;
236		pin_val = atoi(pin);
237		if (!wps_pin_valid(pin_val)) {
238			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
239			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
240			if (ret < 0 || (size_t) ret >= buflen)
241				return -1;
242			return ret;
243		}
244	}
245
246	ret = os_snprintf(buf, buflen, "%s", pin);
247	if (ret < 0 || (size_t) ret >= buflen)
248		return -1;
249
250	return ret;
251}
252
253
254#ifdef CONFIG_WPS_NFC
255static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
256					       char *pos)
257{
258	size_t len;
259	struct wpabuf *buf;
260	int ret;
261
262	len = os_strlen(pos);
263	if (len & 0x01)
264		return -1;
265	len /= 2;
266
267	buf = wpabuf_alloc(len);
268	if (buf == NULL)
269		return -1;
270	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
271		wpabuf_free(buf);
272		return -1;
273	}
274
275	ret = hostapd_wps_nfc_tag_read(hapd, buf);
276	wpabuf_free(buf);
277
278	return ret;
279}
280
281
282static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
283						   char *cmd, char *reply,
284						   size_t max_len)
285{
286	int ndef;
287	struct wpabuf *buf;
288	int res;
289
290	if (os_strcmp(cmd, "WPS") == 0)
291		ndef = 0;
292	else if (os_strcmp(cmd, "NDEF") == 0)
293		ndef = 1;
294	else
295		return -1;
296
297	buf = hostapd_wps_nfc_config_token(hapd, ndef);
298	if (buf == NULL)
299		return -1;
300
301	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
302					 wpabuf_len(buf));
303	reply[res++] = '\n';
304	reply[res] = '\0';
305
306	wpabuf_free(buf);
307
308	return res;
309}
310
311
312static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
313						char *reply, size_t max_len,
314						int ndef)
315{
316	struct wpabuf *buf;
317	int res;
318
319	buf = hostapd_wps_nfc_token_gen(hapd, ndef);
320	if (buf == NULL)
321		return -1;
322
323	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
324					 wpabuf_len(buf));
325	reply[res++] = '\n';
326	reply[res] = '\0';
327
328	wpabuf_free(buf);
329
330	return res;
331}
332
333
334static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
335					    char *cmd, char *reply,
336					    size_t max_len)
337{
338	if (os_strcmp(cmd, "WPS") == 0)
339		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
340							    max_len, 0);
341
342	if (os_strcmp(cmd, "NDEF") == 0)
343		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
344							    max_len, 1);
345
346	if (os_strcmp(cmd, "enable") == 0)
347		return hostapd_wps_nfc_token_enable(hapd);
348
349	if (os_strcmp(cmd, "disable") == 0) {
350		hostapd_wps_nfc_token_disable(hapd);
351		return 0;
352	}
353
354	return -1;
355}
356
357
358static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
359						   char *cmd, char *reply,
360						   size_t max_len)
361{
362	struct wpabuf *buf;
363	int res;
364	char *pos;
365	int ndef;
366
367	pos = os_strchr(cmd, ' ');
368	if (pos == NULL)
369		return -1;
370	*pos++ = '\0';
371
372	if (os_strcmp(cmd, "WPS") == 0)
373		ndef = 0;
374	else if (os_strcmp(cmd, "NDEF") == 0)
375		ndef = 1;
376	else
377		return -1;
378
379	if (os_strcmp(pos, "WPS-CR") == 0)
380		buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
381	else
382		buf = NULL;
383	if (buf == NULL)
384		return -1;
385
386	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
387					 wpabuf_len(buf));
388	reply[res++] = '\n';
389	reply[res] = '\0';
390
391	wpabuf_free(buf);
392
393	return res;
394}
395
396
397static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
398						  char *cmd)
399{
400	/*
401	 * Since NFC connection handover provided full WPS Credential, there is
402	 * no need for additional operations within hostapd. Just report this in
403	 * debug log.
404	 */
405	wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
406	return 0;
407}
408
409#endif /* CONFIG_WPS_NFC */
410
411
412static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
413					 char *buf, size_t buflen)
414{
415	int timeout = 300;
416	char *pos;
417	const char *pin_txt;
418
419	pos = os_strchr(txt, ' ');
420	if (pos)
421		*pos++ = '\0';
422
423	if (os_strcmp(txt, "disable") == 0) {
424		hostapd_wps_ap_pin_disable(hapd);
425		return os_snprintf(buf, buflen, "OK\n");
426	}
427
428	if (os_strcmp(txt, "random") == 0) {
429		if (pos)
430			timeout = atoi(pos);
431		pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
432		if (pin_txt == NULL)
433			return -1;
434		return os_snprintf(buf, buflen, "%s", pin_txt);
435	}
436
437	if (os_strcmp(txt, "get") == 0) {
438		pin_txt = hostapd_wps_ap_pin_get(hapd);
439		if (pin_txt == NULL)
440			return -1;
441		return os_snprintf(buf, buflen, "%s", pin_txt);
442	}
443
444	if (os_strcmp(txt, "set") == 0) {
445		char *pin;
446		if (pos == NULL)
447			return -1;
448		pin = pos;
449		pos = os_strchr(pos, ' ');
450		if (pos) {
451			*pos++ = '\0';
452			timeout = atoi(pos);
453		}
454		if (os_strlen(pin) > buflen)
455			return -1;
456		if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
457			return -1;
458		return os_snprintf(buf, buflen, "%s", pin);
459	}
460
461	return -1;
462}
463
464
465static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
466{
467	char *pos;
468	char *ssid, *auth, *encr = NULL, *key = NULL;
469
470	ssid = txt;
471	pos = os_strchr(txt, ' ');
472	if (!pos)
473		return -1;
474	*pos++ = '\0';
475
476	auth = pos;
477	pos = os_strchr(pos, ' ');
478	if (pos) {
479		*pos++ = '\0';
480		encr = pos;
481		pos = os_strchr(pos, ' ');
482		if (pos) {
483			*pos++ = '\0';
484			key = pos;
485		}
486	}
487
488	return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
489}
490#endif /* CONFIG_WPS */
491
492
493#ifdef CONFIG_WNM
494
495static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
496						const char *cmd)
497{
498	u8 addr[ETH_ALEN];
499	u8 buf[1000], *pos;
500	struct ieee80211_mgmt *mgmt;
501	int disassoc_timer;
502
503	if (hwaddr_aton(cmd, addr))
504		return -1;
505	if (cmd[17] != ' ')
506		return -1;
507	disassoc_timer = atoi(cmd + 17);
508
509	os_memset(buf, 0, sizeof(buf));
510	mgmt = (struct ieee80211_mgmt *) buf;
511	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
512					   WLAN_FC_STYPE_ACTION);
513	os_memcpy(mgmt->da, addr, ETH_ALEN);
514	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
515	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
516	mgmt->u.action.category = WLAN_ACTION_WNM;
517	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
518	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
519	mgmt->u.action.u.bss_tm_req.req_mode =
520		WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
521	mgmt->u.action.u.bss_tm_req.disassoc_timer =
522		host_to_le16(disassoc_timer);
523	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
524
525	pos = mgmt->u.action.u.bss_tm_req.variable;
526
527	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
528		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
529			   "Management Request frame");
530		return -1;
531	}
532
533	return 0;
534}
535
536
537static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
538					   const char *cmd)
539{
540	u8 addr[ETH_ALEN];
541	const char *url, *timerstr;
542	u8 buf[1000], *pos;
543	struct ieee80211_mgmt *mgmt;
544	size_t url_len;
545	int disassoc_timer;
546
547	if (hwaddr_aton(cmd, addr))
548		return -1;
549
550	timerstr = cmd + 17;
551	if (*timerstr != ' ')
552		return -1;
553	timerstr++;
554	disassoc_timer = atoi(timerstr);
555	if (disassoc_timer < 0 || disassoc_timer > 65535)
556		return -1;
557
558	url = os_strchr(timerstr, ' ');
559	if (url == NULL)
560		return -1;
561	url++;
562	url_len = os_strlen(url);
563	if (url_len > 255)
564		return -1;
565
566	os_memset(buf, 0, sizeof(buf));
567	mgmt = (struct ieee80211_mgmt *) buf;
568	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
569					   WLAN_FC_STYPE_ACTION);
570	os_memcpy(mgmt->da, addr, ETH_ALEN);
571	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
572	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
573	mgmt->u.action.category = WLAN_ACTION_WNM;
574	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
575	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
576	mgmt->u.action.u.bss_tm_req.req_mode =
577		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
578	mgmt->u.action.u.bss_tm_req.disassoc_timer =
579		host_to_le16(disassoc_timer);
580	mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
581
582	pos = mgmt->u.action.u.bss_tm_req.variable;
583
584	/* Session Information URL */
585	*pos++ = url_len;
586	os_memcpy(pos, url, url_len);
587	pos += url_len;
588
589	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
590		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
591			   "Management Request frame");
592		return -1;
593	}
594
595	/* send disassociation frame after time-out */
596	if (disassoc_timer) {
597		struct sta_info *sta;
598		int timeout, beacon_int;
599
600		/*
601		 * Prevent STA from reconnecting using cached PMKSA to force
602		 * full authentication with the authentication server (which may
603		 * decide to reject the connection),
604		 */
605		wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
606
607		sta = ap_get_sta(hapd, addr);
608		if (sta == NULL) {
609			wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
610				   "for ESS disassociation imminent message",
611				   MAC2STR(addr));
612			return -1;
613		}
614
615		beacon_int = hapd->iconf->beacon_int;
616		if (beacon_int < 1)
617			beacon_int = 100; /* best guess */
618		/* Calculate timeout in ms based on beacon_int in TU */
619		timeout = disassoc_timer * beacon_int * 128 / 125;
620		wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
621			   " set to %d ms", MAC2STR(addr), timeout);
622
623		sta->timeout_next = STA_DISASSOC_FROM_CLI;
624		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
625		eloop_register_timeout(timeout / 1000,
626				       timeout % 1000 * 1000,
627				       ap_handle_timer, hapd, sta);
628	}
629
630	return 0;
631}
632
633#endif /* CONFIG_WNM */
634
635
636static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
637					 char *buf, size_t buflen)
638{
639	int ret;
640	char *pos, *end;
641
642	pos = buf;
643	end = buf + buflen;
644
645	ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
646			  "ssid=%s\n",
647			  MAC2STR(hapd->own_addr),
648			  wpa_ssid_txt(hapd->conf->ssid.ssid,
649				       hapd->conf->ssid.ssid_len));
650	if (ret < 0 || ret >= end - pos)
651		return pos - buf;
652	pos += ret;
653
654#ifdef CONFIG_WPS
655	ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
656			  hapd->conf->wps_state == 0 ? "disabled" :
657			  (hapd->conf->wps_state == 1 ? "not configured" :
658			   "configured"));
659	if (ret < 0 || ret >= end - pos)
660		return pos - buf;
661	pos += ret;
662
663	if (hapd->conf->wps_state && hapd->conf->wpa &&
664	    hapd->conf->ssid.wpa_passphrase) {
665		ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
666				  hapd->conf->ssid.wpa_passphrase);
667		if (ret < 0 || ret >= end - pos)
668			return pos - buf;
669		pos += ret;
670	}
671
672	if (hapd->conf->wps_state && hapd->conf->wpa &&
673	    hapd->conf->ssid.wpa_psk &&
674	    hapd->conf->ssid.wpa_psk->group) {
675		char hex[PMK_LEN * 2 + 1];
676		wpa_snprintf_hex(hex, sizeof(hex),
677				 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
678		ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
679		if (ret < 0 || ret >= end - pos)
680			return pos - buf;
681		pos += ret;
682	}
683#endif /* CONFIG_WPS */
684
685	if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
686		ret = os_snprintf(pos, end - pos, "key_mgmt=");
687		if (ret < 0 || ret >= end - pos)
688			return pos - buf;
689		pos += ret;
690
691		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
692			ret = os_snprintf(pos, end - pos, "WPA-PSK ");
693			if (ret < 0 || ret >= end - pos)
694				return pos - buf;
695			pos += ret;
696		}
697		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
698			ret = os_snprintf(pos, end - pos, "WPA-EAP ");
699			if (ret < 0 || ret >= end - pos)
700				return pos - buf;
701			pos += ret;
702		}
703#ifdef CONFIG_IEEE80211R
704		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
705			ret = os_snprintf(pos, end - pos, "FT-PSK ");
706			if (ret < 0 || ret >= end - pos)
707				return pos - buf;
708			pos += ret;
709		}
710		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
711			ret = os_snprintf(pos, end - pos, "FT-EAP ");
712			if (ret < 0 || ret >= end - pos)
713				return pos - buf;
714			pos += ret;
715		}
716#endif /* CONFIG_IEEE80211R */
717#ifdef CONFIG_IEEE80211W
718		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
719			ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
720			if (ret < 0 || ret >= end - pos)
721				return pos - buf;
722			pos += ret;
723		}
724		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
725			ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
726			if (ret < 0 || ret >= end - pos)
727				return pos - buf;
728			pos += ret;
729		}
730#endif /* CONFIG_IEEE80211W */
731
732		ret = os_snprintf(pos, end - pos, "\n");
733		if (ret < 0 || ret >= end - pos)
734			return pos - buf;
735		pos += ret;
736	}
737
738	if (hapd->conf->wpa) {
739		ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
740				  wpa_cipher_txt(hapd->conf->wpa_group));
741		if (ret < 0 || ret >= end - pos)
742			return pos - buf;
743		pos += ret;
744	}
745
746	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
747		ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
748		if (ret < 0 || ret >= end - pos)
749			return pos - buf;
750		pos += ret;
751
752		ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
753					" ");
754		if (ret < 0)
755			return pos - buf;
756		pos += ret;
757
758		ret = os_snprintf(pos, end - pos, "\n");
759		if (ret < 0 || ret >= end - pos)
760			return pos - buf;
761		pos += ret;
762	}
763
764	if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
765		ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
766		if (ret < 0 || ret >= end - pos)
767			return pos - buf;
768		pos += ret;
769
770		ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
771					" ");
772		if (ret < 0)
773			return pos - buf;
774		pos += ret;
775
776		ret = os_snprintf(pos, end - pos, "\n");
777		if (ret < 0 || ret >= end - pos)
778			return pos - buf;
779		pos += ret;
780	}
781
782	return pos - buf;
783}
784
785
786static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
787{
788	char *value;
789	int ret = 0;
790
791	value = os_strchr(cmd, ' ');
792	if (value == NULL)
793		return -1;
794	*value++ = '\0';
795
796	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
797	if (0) {
798#ifdef CONFIG_WPS_TESTING
799	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
800		long int val;
801		val = strtol(value, NULL, 0);
802		if (val < 0 || val > 0xff) {
803			ret = -1;
804			wpa_printf(MSG_DEBUG, "WPS: Invalid "
805				   "wps_version_number %ld", val);
806		} else {
807			wps_version_number = val;
808			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
809				   "version %u.%u",
810				   (wps_version_number & 0xf0) >> 4,
811				   wps_version_number & 0x0f);
812			hostapd_wps_update_ie(hapd);
813		}
814	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
815		wps_testing_dummy_cred = atoi(value);
816		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
817			   wps_testing_dummy_cred);
818#endif /* CONFIG_WPS_TESTING */
819#ifdef CONFIG_INTERWORKING
820	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
821		int val = atoi(value);
822		if (val <= 0)
823			ret = -1;
824		else
825			hapd->gas_frag_limit = val;
826#endif /* CONFIG_INTERWORKING */
827	} else {
828		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
829	}
830
831	return ret;
832}
833
834
835static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
836				  char *buf, size_t buflen)
837{
838	int res;
839
840	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
841
842	if (os_strcmp(cmd, "version") == 0) {
843		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
844		if (res < 0 || (unsigned int) res >= buflen)
845			return -1;
846		return res;
847	}
848
849	return -1;
850}
851
852
853static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
854{
855	if (hostapd_enable_iface(iface) < 0) {
856		wpa_printf(MSG_ERROR, "Enabling of interface failed");
857		return -1;
858	}
859	return 0;
860}
861
862
863static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
864{
865	if (hostapd_reload_iface(iface) < 0) {
866		wpa_printf(MSG_ERROR, "Reloading of interface failed");
867		return -1;
868	}
869	return 0;
870}
871
872
873static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
874{
875	if (hostapd_disable_iface(iface) < 0) {
876		wpa_printf(MSG_ERROR, "Disabling of interface failed");
877		return -1;
878	}
879	return 0;
880}
881
882
883static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
884				       void *sock_ctx)
885{
886	struct hostapd_data *hapd = eloop_ctx;
887	char buf[256];
888	int res;
889	struct sockaddr_un from;
890	socklen_t fromlen = sizeof(from);
891	char *reply;
892	const int reply_size = 4096;
893	int reply_len;
894	int level = MSG_DEBUG;
895
896	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
897		       (struct sockaddr *) &from, &fromlen);
898	if (res < 0) {
899		perror("recvfrom(ctrl_iface)");
900		return;
901	}
902	buf[res] = '\0';
903	if (os_strcmp(buf, "PING") == 0)
904		level = MSG_EXCESSIVE;
905	wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
906
907	reply = os_malloc(reply_size);
908	if (reply == NULL) {
909		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
910		       fromlen);
911		return;
912	}
913
914	os_memcpy(reply, "OK\n", 3);
915	reply_len = 3;
916
917	if (os_strcmp(buf, "PING") == 0) {
918		os_memcpy(reply, "PONG\n", 5);
919		reply_len = 5;
920	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
921		if (wpa_debug_reopen_file() < 0)
922			reply_len = -1;
923	} else if (os_strcmp(buf, "MIB") == 0) {
924		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
925		if (reply_len >= 0) {
926			res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
927					  reply_size - reply_len);
928			if (res < 0)
929				reply_len = -1;
930			else
931				reply_len += res;
932		}
933		if (reply_len >= 0) {
934			res = ieee802_1x_get_mib(hapd, reply + reply_len,
935						 reply_size - reply_len);
936			if (res < 0)
937				reply_len = -1;
938			else
939				reply_len += res;
940		}
941#ifndef CONFIG_NO_RADIUS
942		if (reply_len >= 0) {
943			res = radius_client_get_mib(hapd->radius,
944						    reply + reply_len,
945						    reply_size - reply_len);
946			if (res < 0)
947				reply_len = -1;
948			else
949				reply_len += res;
950		}
951#endif /* CONFIG_NO_RADIUS */
952	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
953		reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
954							 reply_size);
955	} else if (os_strncmp(buf, "STA ", 4) == 0) {
956		reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
957						   reply_size);
958	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
959		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
960							reply_size);
961	} else if (os_strcmp(buf, "ATTACH") == 0) {
962		if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
963			reply_len = -1;
964	} else if (os_strcmp(buf, "DETACH") == 0) {
965		if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
966			reply_len = -1;
967	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
968		if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
969						    buf + 6))
970			reply_len = -1;
971	} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
972		if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
973			reply_len = -1;
974	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
975		if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
976			reply_len = -1;
977	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
978		if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
979			reply_len = -1;
980#ifdef CONFIG_IEEE80211W
981#ifdef NEED_AP_MLME
982	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
983		if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
984			reply_len = -1;
985#endif /* NEED_AP_MLME */
986#endif /* CONFIG_IEEE80211W */
987#ifdef CONFIG_WPS
988	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
989		if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
990			reply_len = -1;
991	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
992		reply_len = hostapd_ctrl_iface_wps_check_pin(
993			hapd, buf + 14, reply, reply_size);
994	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
995		if (hostapd_wps_button_pushed(hapd, NULL))
996			reply_len = -1;
997	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
998		if (hostapd_wps_cancel(hapd))
999			reply_len = -1;
1000	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
1001		reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
1002							  reply, reply_size);
1003	} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
1004		if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
1005			reply_len = -1;
1006#ifdef CONFIG_WPS_NFC
1007	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
1008		if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
1009			reply_len = -1;
1010	} else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
1011		reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
1012			hapd, buf + 21, reply, reply_size);
1013	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
1014		reply_len = hostapd_ctrl_iface_wps_nfc_token(
1015			hapd, buf + 14, reply, reply_size);
1016	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
1017		reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
1018			hapd, buf + 21, reply, reply_size);
1019	} else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
1020		if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
1021			reply_len = -1;
1022#endif /* CONFIG_WPS_NFC */
1023#endif /* CONFIG_WPS */
1024#ifdef CONFIG_WNM
1025	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
1026		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
1027			reply_len = -1;
1028	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
1029		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
1030			reply_len = -1;
1031#endif /* CONFIG_WNM */
1032	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
1033		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
1034							  reply_size);
1035	} else if (os_strncmp(buf, "SET ", 4) == 0) {
1036		if (hostapd_ctrl_iface_set(hapd, buf + 4))
1037			reply_len = -1;
1038	} else if (os_strncmp(buf, "GET ", 4) == 0) {
1039		reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
1040						   reply_size);
1041	} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
1042		if (hostapd_ctrl_iface_enable(hapd->iface))
1043			reply_len = -1;
1044	} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
1045		if (hostapd_ctrl_iface_reload(hapd->iface))
1046			reply_len = -1;
1047	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
1048		if (hostapd_ctrl_iface_disable(hapd->iface))
1049			reply_len = -1;
1050	} else {
1051		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1052		reply_len = 16;
1053	}
1054
1055	if (reply_len < 0) {
1056		os_memcpy(reply, "FAIL\n", 5);
1057		reply_len = 5;
1058	}
1059	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1060	os_free(reply);
1061}
1062
1063
1064static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
1065{
1066	char *buf;
1067	size_t len;
1068
1069	if (hapd->conf->ctrl_interface == NULL)
1070		return NULL;
1071
1072	len = os_strlen(hapd->conf->ctrl_interface) +
1073		os_strlen(hapd->conf->iface) + 2;
1074	buf = os_malloc(len);
1075	if (buf == NULL)
1076		return NULL;
1077
1078	os_snprintf(buf, len, "%s/%s",
1079		    hapd->conf->ctrl_interface, hapd->conf->iface);
1080	buf[len - 1] = '\0';
1081	return buf;
1082}
1083
1084
1085static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
1086				      const char *txt, size_t len)
1087{
1088	struct hostapd_data *hapd = ctx;
1089	if (hapd == NULL)
1090		return;
1091	hostapd_ctrl_iface_send(hapd, level, txt, len);
1092}
1093
1094
1095int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
1096{
1097	struct sockaddr_un addr;
1098	int s = -1;
1099	char *fname = NULL;
1100
1101	if (hapd->ctrl_sock > -1) {
1102		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
1103		return 0;
1104	}
1105
1106	if (hapd->conf->ctrl_interface == NULL)
1107		return 0;
1108
1109	if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1110		if (errno == EEXIST) {
1111			wpa_printf(MSG_DEBUG, "Using existing control "
1112				   "interface directory.");
1113		} else {
1114			perror("mkdir[ctrl_interface]");
1115			goto fail;
1116		}
1117	}
1118
1119	if (hapd->conf->ctrl_interface_gid_set &&
1120	    chown(hapd->conf->ctrl_interface, -1,
1121		  hapd->conf->ctrl_interface_gid) < 0) {
1122		perror("chown[ctrl_interface]");
1123		return -1;
1124	}
1125
1126	if (!hapd->conf->ctrl_interface_gid_set &&
1127	    hapd->iface->interfaces->ctrl_iface_group &&
1128	    chown(hapd->conf->ctrl_interface, -1,
1129		  hapd->iface->interfaces->ctrl_iface_group) < 0) {
1130		perror("chown[ctrl_interface]");
1131		return -1;
1132	}
1133
1134#ifdef ANDROID
1135	/*
1136	 * Android is using umask 0077 which would leave the control interface
1137	 * directory without group access. This breaks things since Wi-Fi
1138	 * framework assumes that this directory can be accessed by other
1139	 * applications in the wifi group. Fix this by adding group access even
1140	 * if umask value would prevent this.
1141	 */
1142	if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1143		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
1144			   strerror(errno));
1145		/* Try to continue anyway */
1146	}
1147#endif /* ANDROID */
1148
1149	if (os_strlen(hapd->conf->ctrl_interface) + 1 +
1150	    os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
1151		goto fail;
1152
1153	s = socket(PF_UNIX, SOCK_DGRAM, 0);
1154	if (s < 0) {
1155		perror("socket(PF_UNIX)");
1156		goto fail;
1157	}
1158
1159	os_memset(&addr, 0, sizeof(addr));
1160#ifdef __FreeBSD__
1161	addr.sun_len = sizeof(addr);
1162#endif /* __FreeBSD__ */
1163	addr.sun_family = AF_UNIX;
1164	fname = hostapd_ctrl_iface_path(hapd);
1165	if (fname == NULL)
1166		goto fail;
1167	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1168	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1169		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1170			   strerror(errno));
1171		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1172			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1173				   " allow connections - assuming it was left"
1174				   "over from forced program termination");
1175			if (unlink(fname) < 0) {
1176				perror("unlink[ctrl_iface]");
1177				wpa_printf(MSG_ERROR, "Could not unlink "
1178					   "existing ctrl_iface socket '%s'",
1179					   fname);
1180				goto fail;
1181			}
1182			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1183			    0) {
1184				perror("hostapd-ctrl-iface: bind(PF_UNIX)");
1185				goto fail;
1186			}
1187			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1188				   "ctrl_iface socket '%s'", fname);
1189		} else {
1190			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1191				   "be in use - cannot override it");
1192			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1193				   "not used anymore", fname);
1194			os_free(fname);
1195			fname = NULL;
1196			goto fail;
1197		}
1198	}
1199
1200	if (hapd->conf->ctrl_interface_gid_set &&
1201	    chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
1202		perror("chown[ctrl_interface/ifname]");
1203		goto fail;
1204	}
1205
1206	if (!hapd->conf->ctrl_interface_gid_set &&
1207	    hapd->iface->interfaces->ctrl_iface_group &&
1208	    chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
1209		perror("chown[ctrl_interface/ifname]");
1210		goto fail;
1211	}
1212
1213	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1214		perror("chmod[ctrl_interface/ifname]");
1215		goto fail;
1216	}
1217	os_free(fname);
1218
1219	hapd->ctrl_sock = s;
1220	eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
1221				 NULL);
1222	hapd->msg_ctx = hapd;
1223	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
1224
1225	return 0;
1226
1227fail:
1228	if (s >= 0)
1229		close(s);
1230	if (fname) {
1231		unlink(fname);
1232		os_free(fname);
1233	}
1234	return -1;
1235}
1236
1237
1238void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
1239{
1240	struct wpa_ctrl_dst *dst, *prev;
1241
1242	if (hapd->ctrl_sock > -1) {
1243		char *fname;
1244		eloop_unregister_read_sock(hapd->ctrl_sock);
1245		close(hapd->ctrl_sock);
1246		hapd->ctrl_sock = -1;
1247		fname = hostapd_ctrl_iface_path(hapd);
1248		if (fname)
1249			unlink(fname);
1250		os_free(fname);
1251
1252		if (hapd->conf->ctrl_interface &&
1253		    rmdir(hapd->conf->ctrl_interface) < 0) {
1254			if (errno == ENOTEMPTY) {
1255				wpa_printf(MSG_DEBUG, "Control interface "
1256					   "directory not empty - leaving it "
1257					   "behind");
1258			} else {
1259				perror("rmdir[ctrl_interface]");
1260			}
1261		}
1262	}
1263
1264	dst = hapd->ctrl_dst;
1265	while (dst) {
1266		prev = dst;
1267		dst = dst->next;
1268		os_free(prev);
1269	}
1270}
1271
1272
1273static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
1274				  char *buf)
1275{
1276	if (hostapd_add_iface(interfaces, buf) < 0) {
1277		wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
1278		return -1;
1279	}
1280	return 0;
1281}
1282
1283
1284static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
1285				     char *buf)
1286{
1287	if (hostapd_remove_iface(interfaces, buf) < 0) {
1288		wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
1289		return -1;
1290	}
1291	return 0;
1292}
1293
1294
1295static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
1296					      void *sock_ctx)
1297{
1298	void *interfaces = eloop_ctx;
1299	char buf[256];
1300	int res;
1301	struct sockaddr_un from;
1302	socklen_t fromlen = sizeof(from);
1303	char reply[24];
1304	int reply_len;
1305
1306	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1307		       (struct sockaddr *) &from, &fromlen);
1308	if (res < 0) {
1309		perror("recvfrom(ctrl_iface)");
1310		return;
1311	}
1312	buf[res] = '\0';
1313
1314	os_memcpy(reply, "OK\n", 3);
1315	reply_len = 3;
1316
1317	if (os_strcmp(buf, "PING") == 0) {
1318		os_memcpy(reply, "PONG\n", 5);
1319		reply_len = 5;
1320	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
1321		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
1322			reply_len = -1;
1323	} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
1324		if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
1325			reply_len = -1;
1326	} else {
1327		wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
1328			   "ignored");
1329		reply_len = -1;
1330	}
1331
1332	if (reply_len < 0) {
1333		os_memcpy(reply, "FAIL\n", 5);
1334		reply_len = 5;
1335	}
1336
1337	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1338}
1339
1340
1341static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
1342{
1343	char *buf;
1344	size_t len;
1345
1346	if (interface->global_iface_path == NULL)
1347		return NULL;
1348
1349	len = os_strlen(interface->global_iface_path) +
1350		os_strlen(interface->global_iface_name) + 2;
1351	buf = os_malloc(len);
1352	if (buf == NULL)
1353		return NULL;
1354
1355	os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
1356		    interface->global_iface_name);
1357	buf[len - 1] = '\0';
1358	return buf;
1359}
1360
1361
1362int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
1363{
1364	struct sockaddr_un addr;
1365	int s = -1;
1366	char *fname = NULL;
1367
1368	if (interface->global_iface_path == NULL) {
1369		wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
1370		return 0;
1371	}
1372
1373	if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
1374		if (errno == EEXIST) {
1375			wpa_printf(MSG_DEBUG, "Using existing control "
1376				   "interface directory.");
1377		} else {
1378			perror("mkdir[ctrl_interface]");
1379			goto fail;
1380		}
1381	} else if (interface->ctrl_iface_group &&
1382		   chown(interface->global_iface_path, -1,
1383			 interface->ctrl_iface_group) < 0) {
1384		perror("chown[ctrl_interface]");
1385		goto fail;
1386	}
1387
1388	if (os_strlen(interface->global_iface_path) + 1 +
1389	    os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
1390		goto fail;
1391
1392	s = socket(PF_UNIX, SOCK_DGRAM, 0);
1393	if (s < 0) {
1394		perror("socket(PF_UNIX)");
1395		goto fail;
1396	}
1397
1398	os_memset(&addr, 0, sizeof(addr));
1399#ifdef __FreeBSD__
1400	addr.sun_len = sizeof(addr);
1401#endif /* __FreeBSD__ */
1402	addr.sun_family = AF_UNIX;
1403	fname = hostapd_global_ctrl_iface_path(interface);
1404	if (fname == NULL)
1405		goto fail;
1406	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1407	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1408		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1409			   strerror(errno));
1410		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1411			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1412				   " allow connections - assuming it was left"
1413				   "over from forced program termination");
1414			if (unlink(fname) < 0) {
1415				perror("unlink[ctrl_iface]");
1416				wpa_printf(MSG_ERROR, "Could not unlink "
1417					   "existing ctrl_iface socket '%s'",
1418					   fname);
1419				goto fail;
1420			}
1421			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1422			    0) {
1423				perror("bind(PF_UNIX)");
1424				goto fail;
1425			}
1426			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1427				   "ctrl_iface socket '%s'", fname);
1428		} else {
1429			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1430				   "be in use - cannot override it");
1431			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1432				   "not used anymore", fname);
1433			os_free(fname);
1434			fname = NULL;
1435			goto fail;
1436		}
1437	}
1438
1439	if (interface->ctrl_iface_group &&
1440	    chown(fname, -1, interface->ctrl_iface_group) < 0) {
1441		perror("chown[ctrl_interface]");
1442		goto fail;
1443	}
1444
1445	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1446		perror("chmod[ctrl_interface/ifname]");
1447		goto fail;
1448	}
1449	os_free(fname);
1450
1451	interface->global_ctrl_sock = s;
1452	eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
1453				 interface, NULL);
1454
1455	return 0;
1456
1457fail:
1458	if (s >= 0)
1459		close(s);
1460	if (fname) {
1461		unlink(fname);
1462		os_free(fname);
1463	}
1464	return -1;
1465}
1466
1467
1468void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
1469{
1470	char *fname = NULL;
1471
1472	if (interfaces->global_ctrl_sock > -1) {
1473		eloop_unregister_read_sock(interfaces->global_ctrl_sock);
1474		close(interfaces->global_ctrl_sock);
1475		interfaces->global_ctrl_sock = -1;
1476		fname = hostapd_global_ctrl_iface_path(interfaces);
1477		if (fname) {
1478			unlink(fname);
1479			os_free(fname);
1480		}
1481
1482		if (interfaces->global_iface_path &&
1483		    rmdir(interfaces->global_iface_path) < 0) {
1484			if (errno == ENOTEMPTY) {
1485				wpa_printf(MSG_DEBUG, "Control interface "
1486					   "directory not empty - leaving it "
1487					   "behind");
1488			} else {
1489				perror("rmdir[ctrl_interface]");
1490			}
1491		}
1492		os_free(interfaces->global_iface_path);
1493		interfaces->global_iface_path = NULL;
1494	}
1495}
1496
1497
1498static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1499				    const char *buf, size_t len)
1500{
1501	struct wpa_ctrl_dst *dst, *next;
1502	struct msghdr msg;
1503	int idx;
1504	struct iovec io[2];
1505	char levelstr[10];
1506
1507	dst = hapd->ctrl_dst;
1508	if (hapd->ctrl_sock < 0 || dst == NULL)
1509		return;
1510
1511	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1512	io[0].iov_base = levelstr;
1513	io[0].iov_len = os_strlen(levelstr);
1514	io[1].iov_base = (char *) buf;
1515	io[1].iov_len = len;
1516	os_memset(&msg, 0, sizeof(msg));
1517	msg.msg_iov = io;
1518	msg.msg_iovlen = 2;
1519
1520	idx = 0;
1521	while (dst) {
1522		next = dst->next;
1523		if (level >= dst->debug_level) {
1524			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1525				    (u8 *) dst->addr.sun_path, dst->addrlen -
1526				    offsetof(struct sockaddr_un, sun_path));
1527			msg.msg_name = &dst->addr;
1528			msg.msg_namelen = dst->addrlen;
1529			if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1530				int _errno = errno;
1531				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1532					   "%d - %s",
1533					   idx, errno, strerror(errno));
1534				dst->errors++;
1535				if (dst->errors > 10 || _errno == ENOENT) {
1536					hostapd_ctrl_iface_detach(
1537						hapd, &dst->addr,
1538						dst->addrlen);
1539				}
1540			} else
1541				dst->errors = 0;
1542		}
1543		idx++;
1544		dst = next;
1545	}
1546}
1547
1548#endif /* CONFIG_NATIVE_WINDOWS */
1549