1214503Srpaulo/*
2214503Srpaulo * hostapd / UNIX domain socket -based control interface
3252726Srpaulo * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4214503Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214503Srpaulo */
8214503Srpaulo
9214503Srpaulo#include "utils/includes.h"
10214503Srpaulo
11214503Srpaulo#ifndef CONFIG_NATIVE_WINDOWS
12214503Srpaulo
13214503Srpaulo#include <sys/un.h>
14214503Srpaulo#include <sys/stat.h>
15214503Srpaulo#include <stddef.h>
16214503Srpaulo
17214503Srpaulo#include "utils/common.h"
18214503Srpaulo#include "utils/eloop.h"
19252726Srpaulo#include "common/version.h"
20214503Srpaulo#include "common/ieee802_11_defs.h"
21214503Srpaulo#include "drivers/driver.h"
22214503Srpaulo#include "radius/radius_client.h"
23214503Srpaulo#include "ap/hostapd.h"
24214503Srpaulo#include "ap/ap_config.h"
25214503Srpaulo#include "ap/ieee802_1x.h"
26214503Srpaulo#include "ap/wpa_auth.h"
27214503Srpaulo#include "ap/ieee802_11.h"
28214503Srpaulo#include "ap/sta_info.h"
29214503Srpaulo#include "ap/wps_hostapd.h"
30214503Srpaulo#include "ap/ctrl_iface_ap.h"
31252726Srpaulo#include "ap/ap_drv_ops.h"
32252726Srpaulo#include "wps/wps_defs.h"
33252726Srpaulo#include "wps/wps.h"
34252726Srpaulo#include "config_file.h"
35214503Srpaulo#include "ctrl_iface.h"
36214503Srpaulo
37214503Srpaulo
38214503Srpaulostruct wpa_ctrl_dst {
39214503Srpaulo	struct wpa_ctrl_dst *next;
40214503Srpaulo	struct sockaddr_un addr;
41214503Srpaulo	socklen_t addrlen;
42214503Srpaulo	int debug_level;
43214503Srpaulo	int errors;
44214503Srpaulo};
45214503Srpaulo
46214503Srpaulo
47214503Srpaulostatic void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
48214503Srpaulo				    const char *buf, size_t len);
49214503Srpaulo
50214503Srpaulo
51214503Srpaulostatic int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
52214503Srpaulo				     struct sockaddr_un *from,
53214503Srpaulo				     socklen_t fromlen)
54214503Srpaulo{
55214503Srpaulo	struct wpa_ctrl_dst *dst;
56214503Srpaulo
57214503Srpaulo	dst = os_zalloc(sizeof(*dst));
58214503Srpaulo	if (dst == NULL)
59214503Srpaulo		return -1;
60214503Srpaulo	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
61214503Srpaulo	dst->addrlen = fromlen;
62214503Srpaulo	dst->debug_level = MSG_INFO;
63214503Srpaulo	dst->next = hapd->ctrl_dst;
64214503Srpaulo	hapd->ctrl_dst = dst;
65214503Srpaulo	wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
66214503Srpaulo		    (u8 *) from->sun_path,
67214503Srpaulo		    fromlen - offsetof(struct sockaddr_un, sun_path));
68214503Srpaulo	return 0;
69214503Srpaulo}
70214503Srpaulo
71214503Srpaulo
72214503Srpaulostatic int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
73214503Srpaulo				     struct sockaddr_un *from,
74214503Srpaulo				     socklen_t fromlen)
75214503Srpaulo{
76214503Srpaulo	struct wpa_ctrl_dst *dst, *prev = NULL;
77214503Srpaulo
78214503Srpaulo	dst = hapd->ctrl_dst;
79214503Srpaulo	while (dst) {
80214503Srpaulo		if (fromlen == dst->addrlen &&
81214503Srpaulo		    os_memcmp(from->sun_path, dst->addr.sun_path,
82214503Srpaulo			      fromlen - offsetof(struct sockaddr_un, sun_path))
83214503Srpaulo		    == 0) {
84214503Srpaulo			if (prev == NULL)
85214503Srpaulo				hapd->ctrl_dst = dst->next;
86214503Srpaulo			else
87214503Srpaulo				prev->next = dst->next;
88214503Srpaulo			os_free(dst);
89214503Srpaulo			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
90214503Srpaulo				    (u8 *) from->sun_path,
91214503Srpaulo				    fromlen -
92214503Srpaulo				    offsetof(struct sockaddr_un, sun_path));
93214503Srpaulo			return 0;
94214503Srpaulo		}
95214503Srpaulo		prev = dst;
96214503Srpaulo		dst = dst->next;
97214503Srpaulo	}
98214503Srpaulo	return -1;
99214503Srpaulo}
100214503Srpaulo
101214503Srpaulo
102214503Srpaulostatic int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
103214503Srpaulo				    struct sockaddr_un *from,
104214503Srpaulo				    socklen_t fromlen,
105214503Srpaulo				    char *level)
106214503Srpaulo{
107214503Srpaulo	struct wpa_ctrl_dst *dst;
108214503Srpaulo
109214503Srpaulo	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
110214503Srpaulo
111214503Srpaulo	dst = hapd->ctrl_dst;
112214503Srpaulo	while (dst) {
113214503Srpaulo		if (fromlen == dst->addrlen &&
114214503Srpaulo		    os_memcmp(from->sun_path, dst->addr.sun_path,
115214503Srpaulo			      fromlen - offsetof(struct sockaddr_un, sun_path))
116214503Srpaulo		    == 0) {
117214503Srpaulo			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
118214503Srpaulo				    "level", (u8 *) from->sun_path, fromlen -
119214503Srpaulo				    offsetof(struct sockaddr_un, sun_path));
120214503Srpaulo			dst->debug_level = atoi(level);
121214503Srpaulo			return 0;
122214503Srpaulo		}
123214503Srpaulo		dst = dst->next;
124214503Srpaulo	}
125214503Srpaulo
126214503Srpaulo	return -1;
127214503Srpaulo}
128214503Srpaulo
129214503Srpaulo
130214503Srpaulostatic int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
131214503Srpaulo				      const char *txtaddr)
132214503Srpaulo{
133214503Srpaulo	u8 addr[ETH_ALEN];
134214503Srpaulo	struct sta_info *sta;
135214503Srpaulo
136214503Srpaulo	wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
137214503Srpaulo
138214503Srpaulo	if (hwaddr_aton(txtaddr, addr))
139214503Srpaulo		return -1;
140214503Srpaulo
141214503Srpaulo	sta = ap_get_sta(hapd, addr);
142214503Srpaulo	if (sta)
143214503Srpaulo		return 0;
144214503Srpaulo
145214503Srpaulo	wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
146214503Srpaulo		   "notification", MAC2STR(addr));
147214503Srpaulo	sta = ap_sta_add(hapd, addr);
148214503Srpaulo	if (sta == NULL)
149214503Srpaulo		return -1;
150214503Srpaulo
151214503Srpaulo	hostapd_new_assoc_sta(hapd, sta, 0);
152214503Srpaulo	return 0;
153214503Srpaulo}
154214503Srpaulo
155214503Srpaulo
156214503Srpaulo#ifdef CONFIG_IEEE80211W
157214503Srpaulo#ifdef NEED_AP_MLME
158214503Srpaulostatic int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
159214503Srpaulo				       const char *txtaddr)
160214503Srpaulo{
161214503Srpaulo	u8 addr[ETH_ALEN];
162214503Srpaulo	u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
163214503Srpaulo
164214503Srpaulo	wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
165214503Srpaulo
166214503Srpaulo	if (hwaddr_aton(txtaddr, addr) ||
167214503Srpaulo	    os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
168214503Srpaulo		return -1;
169214503Srpaulo
170214503Srpaulo	ieee802_11_send_sa_query_req(hapd, addr, trans_id);
171214503Srpaulo
172214503Srpaulo	return 0;
173214503Srpaulo}
174214503Srpaulo#endif /* NEED_AP_MLME */
175214503Srpaulo#endif /* CONFIG_IEEE80211W */
176214503Srpaulo
177214503Srpaulo
178214503Srpaulo#ifdef CONFIG_WPS
179214503Srpaulostatic int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
180214503Srpaulo{
181214503Srpaulo	char *pin = os_strchr(txt, ' ');
182214503Srpaulo	char *timeout_txt;
183214503Srpaulo	int timeout;
184252726Srpaulo	u8 addr_buf[ETH_ALEN], *addr = NULL;
185252726Srpaulo	char *pos;
186214503Srpaulo
187214503Srpaulo	if (pin == NULL)
188214503Srpaulo		return -1;
189214503Srpaulo	*pin++ = '\0';
190214503Srpaulo
191214503Srpaulo	timeout_txt = os_strchr(pin, ' ');
192214503Srpaulo	if (timeout_txt) {
193214503Srpaulo		*timeout_txt++ = '\0';
194214503Srpaulo		timeout = atoi(timeout_txt);
195252726Srpaulo		pos = os_strchr(timeout_txt, ' ');
196252726Srpaulo		if (pos) {
197252726Srpaulo			*pos++ = '\0';
198252726Srpaulo			if (hwaddr_aton(pos, addr_buf) == 0)
199252726Srpaulo				addr = addr_buf;
200252726Srpaulo		}
201214503Srpaulo	} else
202214503Srpaulo		timeout = 0;
203214503Srpaulo
204252726Srpaulo	return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
205214503Srpaulo}
206214503Srpaulo
207214503Srpaulo
208252726Srpaulostatic int hostapd_ctrl_iface_wps_check_pin(
209252726Srpaulo	struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
210214503Srpaulo{
211252726Srpaulo	char pin[9];
212252726Srpaulo	size_t len;
213252726Srpaulo	char *pos;
214252726Srpaulo	int ret;
215214503Srpaulo
216252726Srpaulo	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
217252726Srpaulo			      (u8 *) cmd, os_strlen(cmd));
218252726Srpaulo	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
219252726Srpaulo		if (*pos < '0' || *pos > '9')
220252726Srpaulo			continue;
221252726Srpaulo		pin[len++] = *pos;
222252726Srpaulo		if (len == 9) {
223252726Srpaulo			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
224252726Srpaulo			return -1;
225252726Srpaulo		}
226252726Srpaulo	}
227252726Srpaulo	if (len != 4 && len != 8) {
228252726Srpaulo		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
229214503Srpaulo		return -1;
230252726Srpaulo	}
231252726Srpaulo	pin[len] = '\0';
232214503Srpaulo
233252726Srpaulo	if (len == 8) {
234252726Srpaulo		unsigned int pin_val;
235252726Srpaulo		pin_val = atoi(pin);
236252726Srpaulo		if (!wps_pin_valid(pin_val)) {
237252726Srpaulo			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
238252726Srpaulo			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
239252726Srpaulo			if (ret < 0 || (size_t) ret >= buflen)
240252726Srpaulo				return -1;
241252726Srpaulo			return ret;
242252726Srpaulo		}
243252726Srpaulo	}
244252726Srpaulo
245252726Srpaulo	ret = os_snprintf(buf, buflen, "%s", pin);
246252726Srpaulo	if (ret < 0 || (size_t) ret >= buflen)
247214503Srpaulo		return -1;
248214503Srpaulo
249252726Srpaulo	return ret;
250252726Srpaulo}
251214503Srpaulo
252252726Srpaulo
253252726Srpaulo#ifdef CONFIG_WPS_NFC
254252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
255252726Srpaulo					       char *pos)
256252726Srpaulo{
257252726Srpaulo	size_t len;
258252726Srpaulo	struct wpabuf *buf;
259252726Srpaulo	int ret;
260252726Srpaulo
261252726Srpaulo	len = os_strlen(pos);
262252726Srpaulo	if (len & 0x01)
263252726Srpaulo		return -1;
264252726Srpaulo	len /= 2;
265252726Srpaulo
266252726Srpaulo	buf = wpabuf_alloc(len);
267252726Srpaulo	if (buf == NULL)
268252726Srpaulo		return -1;
269252726Srpaulo	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
270252726Srpaulo		wpabuf_free(buf);
271252726Srpaulo		return -1;
272252726Srpaulo	}
273252726Srpaulo
274252726Srpaulo	ret = hostapd_wps_nfc_tag_read(hapd, buf);
275252726Srpaulo	wpabuf_free(buf);
276252726Srpaulo
277252726Srpaulo	return ret;
278214503Srpaulo}
279214503Srpaulo
280214503Srpaulo
281252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
282252726Srpaulo						   char *cmd, char *reply,
283252726Srpaulo						   size_t max_len)
284252726Srpaulo{
285252726Srpaulo	int ndef;
286252726Srpaulo	struct wpabuf *buf;
287252726Srpaulo	int res;
288252726Srpaulo
289252726Srpaulo	if (os_strcmp(cmd, "WPS") == 0)
290252726Srpaulo		ndef = 0;
291252726Srpaulo	else if (os_strcmp(cmd, "NDEF") == 0)
292252726Srpaulo		ndef = 1;
293252726Srpaulo	else
294252726Srpaulo		return -1;
295252726Srpaulo
296252726Srpaulo	buf = hostapd_wps_nfc_config_token(hapd, ndef);
297252726Srpaulo	if (buf == NULL)
298252726Srpaulo		return -1;
299252726Srpaulo
300252726Srpaulo	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
301252726Srpaulo					 wpabuf_len(buf));
302252726Srpaulo	reply[res++] = '\n';
303252726Srpaulo	reply[res] = '\0';
304252726Srpaulo
305252726Srpaulo	wpabuf_free(buf);
306252726Srpaulo
307252726Srpaulo	return res;
308252726Srpaulo}
309252726Srpaulo
310252726Srpaulo
311252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
312252726Srpaulo						char *reply, size_t max_len,
313252726Srpaulo						int ndef)
314252726Srpaulo{
315252726Srpaulo	struct wpabuf *buf;
316252726Srpaulo	int res;
317252726Srpaulo
318252726Srpaulo	buf = hostapd_wps_nfc_token_gen(hapd, ndef);
319252726Srpaulo	if (buf == NULL)
320252726Srpaulo		return -1;
321252726Srpaulo
322252726Srpaulo	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
323252726Srpaulo					 wpabuf_len(buf));
324252726Srpaulo	reply[res++] = '\n';
325252726Srpaulo	reply[res] = '\0';
326252726Srpaulo
327252726Srpaulo	wpabuf_free(buf);
328252726Srpaulo
329252726Srpaulo	return res;
330252726Srpaulo}
331252726Srpaulo
332252726Srpaulo
333252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
334252726Srpaulo					    char *cmd, char *reply,
335252726Srpaulo					    size_t max_len)
336252726Srpaulo{
337252726Srpaulo	if (os_strcmp(cmd, "WPS") == 0)
338252726Srpaulo		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
339252726Srpaulo							    max_len, 0);
340252726Srpaulo
341252726Srpaulo	if (os_strcmp(cmd, "NDEF") == 0)
342252726Srpaulo		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
343252726Srpaulo							    max_len, 1);
344252726Srpaulo
345252726Srpaulo	if (os_strcmp(cmd, "enable") == 0)
346252726Srpaulo		return hostapd_wps_nfc_token_enable(hapd);
347252726Srpaulo
348252726Srpaulo	if (os_strcmp(cmd, "disable") == 0) {
349252726Srpaulo		hostapd_wps_nfc_token_disable(hapd);
350252726Srpaulo		return 0;
351252726Srpaulo	}
352252726Srpaulo
353252726Srpaulo	return -1;
354252726Srpaulo}
355252726Srpaulo#endif /* CONFIG_WPS_NFC */
356252726Srpaulo
357252726Srpaulo
358214503Srpaulostatic int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
359214503Srpaulo					 char *buf, size_t buflen)
360214503Srpaulo{
361214503Srpaulo	int timeout = 300;
362214503Srpaulo	char *pos;
363214503Srpaulo	const char *pin_txt;
364214503Srpaulo
365214503Srpaulo	pos = os_strchr(txt, ' ');
366214503Srpaulo	if (pos)
367214503Srpaulo		*pos++ = '\0';
368214503Srpaulo
369214503Srpaulo	if (os_strcmp(txt, "disable") == 0) {
370214503Srpaulo		hostapd_wps_ap_pin_disable(hapd);
371214503Srpaulo		return os_snprintf(buf, buflen, "OK\n");
372214503Srpaulo	}
373214503Srpaulo
374214503Srpaulo	if (os_strcmp(txt, "random") == 0) {
375214503Srpaulo		if (pos)
376214503Srpaulo			timeout = atoi(pos);
377214503Srpaulo		pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
378214503Srpaulo		if (pin_txt == NULL)
379214503Srpaulo			return -1;
380214503Srpaulo		return os_snprintf(buf, buflen, "%s", pin_txt);
381214503Srpaulo	}
382214503Srpaulo
383214503Srpaulo	if (os_strcmp(txt, "get") == 0) {
384214503Srpaulo		pin_txt = hostapd_wps_ap_pin_get(hapd);
385214503Srpaulo		if (pin_txt == NULL)
386214503Srpaulo			return -1;
387214503Srpaulo		return os_snprintf(buf, buflen, "%s", pin_txt);
388214503Srpaulo	}
389214503Srpaulo
390214503Srpaulo	if (os_strcmp(txt, "set") == 0) {
391214503Srpaulo		char *pin;
392214503Srpaulo		if (pos == NULL)
393214503Srpaulo			return -1;
394214503Srpaulo		pin = pos;
395214503Srpaulo		pos = os_strchr(pos, ' ');
396214503Srpaulo		if (pos) {
397214503Srpaulo			*pos++ = '\0';
398214503Srpaulo			timeout = atoi(pos);
399214503Srpaulo		}
400214503Srpaulo		if (os_strlen(pin) > buflen)
401214503Srpaulo			return -1;
402214503Srpaulo		if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
403214503Srpaulo			return -1;
404214503Srpaulo		return os_snprintf(buf, buflen, "%s", pin);
405214503Srpaulo	}
406214503Srpaulo
407214503Srpaulo	return -1;
408214503Srpaulo}
409252726Srpaulo
410252726Srpaulo
411252726Srpaulostatic int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
412252726Srpaulo{
413252726Srpaulo	char *pos;
414252726Srpaulo	char *ssid, *auth, *encr = NULL, *key = NULL;
415252726Srpaulo
416252726Srpaulo	ssid = txt;
417252726Srpaulo	pos = os_strchr(txt, ' ');
418252726Srpaulo	if (!pos)
419252726Srpaulo		return -1;
420252726Srpaulo	*pos++ = '\0';
421252726Srpaulo
422252726Srpaulo	auth = pos;
423252726Srpaulo	pos = os_strchr(pos, ' ');
424252726Srpaulo	if (pos) {
425252726Srpaulo		*pos++ = '\0';
426252726Srpaulo		encr = pos;
427252726Srpaulo		pos = os_strchr(pos, ' ');
428252726Srpaulo		if (pos) {
429252726Srpaulo			*pos++ = '\0';
430252726Srpaulo			key = pos;
431252726Srpaulo		}
432252726Srpaulo	}
433252726Srpaulo
434252726Srpaulo	return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
435252726Srpaulo}
436214503Srpaulo#endif /* CONFIG_WPS */
437214503Srpaulo
438214503Srpaulo
439252726Srpaulo#ifdef CONFIG_WNM
440252726Srpaulo
441252726Srpaulostatic int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
442252726Srpaulo						const char *cmd)
443252726Srpaulo{
444252726Srpaulo	u8 addr[ETH_ALEN];
445252726Srpaulo	u8 buf[1000], *pos;
446252726Srpaulo	struct ieee80211_mgmt *mgmt;
447252726Srpaulo	int disassoc_timer;
448252726Srpaulo
449252726Srpaulo	if (hwaddr_aton(cmd, addr))
450252726Srpaulo		return -1;
451252726Srpaulo	if (cmd[17] != ' ')
452252726Srpaulo		return -1;
453252726Srpaulo	disassoc_timer = atoi(cmd + 17);
454252726Srpaulo
455252726Srpaulo	os_memset(buf, 0, sizeof(buf));
456252726Srpaulo	mgmt = (struct ieee80211_mgmt *) buf;
457252726Srpaulo	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
458252726Srpaulo					   WLAN_FC_STYPE_ACTION);
459252726Srpaulo	os_memcpy(mgmt->da, addr, ETH_ALEN);
460252726Srpaulo	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
461252726Srpaulo	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
462252726Srpaulo	mgmt->u.action.category = WLAN_ACTION_WNM;
463252726Srpaulo	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
464252726Srpaulo	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
465252726Srpaulo	mgmt->u.action.u.bss_tm_req.req_mode =
466252726Srpaulo		WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
467252726Srpaulo	mgmt->u.action.u.bss_tm_req.disassoc_timer =
468252726Srpaulo		host_to_le16(disassoc_timer);
469252726Srpaulo	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
470252726Srpaulo
471252726Srpaulo	pos = mgmt->u.action.u.bss_tm_req.variable;
472252726Srpaulo
473252726Srpaulo	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
474252726Srpaulo		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
475252726Srpaulo			   "Management Request frame");
476252726Srpaulo		return -1;
477252726Srpaulo	}
478252726Srpaulo
479252726Srpaulo	return 0;
480252726Srpaulo}
481252726Srpaulo
482252726Srpaulo
483252726Srpaulostatic int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
484252726Srpaulo					   const char *cmd)
485252726Srpaulo{
486252726Srpaulo	u8 addr[ETH_ALEN];
487252726Srpaulo	const char *url;
488252726Srpaulo	u8 buf[1000], *pos;
489252726Srpaulo	struct ieee80211_mgmt *mgmt;
490252726Srpaulo	size_t url_len;
491252726Srpaulo
492252726Srpaulo	if (hwaddr_aton(cmd, addr))
493252726Srpaulo		return -1;
494252726Srpaulo	url = cmd + 17;
495252726Srpaulo	if (*url != ' ')
496252726Srpaulo		return -1;
497252726Srpaulo	url++;
498252726Srpaulo	url_len = os_strlen(url);
499252726Srpaulo	if (url_len > 255)
500252726Srpaulo		return -1;
501252726Srpaulo
502252726Srpaulo	os_memset(buf, 0, sizeof(buf));
503252726Srpaulo	mgmt = (struct ieee80211_mgmt *) buf;
504252726Srpaulo	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
505252726Srpaulo					   WLAN_FC_STYPE_ACTION);
506252726Srpaulo	os_memcpy(mgmt->da, addr, ETH_ALEN);
507252726Srpaulo	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
508252726Srpaulo	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
509252726Srpaulo	mgmt->u.action.category = WLAN_ACTION_WNM;
510252726Srpaulo	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
511252726Srpaulo	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
512252726Srpaulo	mgmt->u.action.u.bss_tm_req.req_mode =
513252726Srpaulo		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
514252726Srpaulo	mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
515252726Srpaulo	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
516252726Srpaulo
517252726Srpaulo	pos = mgmt->u.action.u.bss_tm_req.variable;
518252726Srpaulo
519252726Srpaulo	/* Session Information URL */
520252726Srpaulo	*pos++ = url_len;
521252726Srpaulo	os_memcpy(pos, url, url_len);
522252726Srpaulo	pos += url_len;
523252726Srpaulo
524252726Srpaulo	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
525252726Srpaulo		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
526252726Srpaulo			   "Management Request frame");
527252726Srpaulo		return -1;
528252726Srpaulo	}
529252726Srpaulo
530252726Srpaulo	return 0;
531252726Srpaulo}
532252726Srpaulo
533252726Srpaulo#endif /* CONFIG_WNM */
534252726Srpaulo
535252726Srpaulo
536252726Srpaulostatic int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
537252726Srpaulo					 char *buf, size_t buflen)
538252726Srpaulo{
539252726Srpaulo	int ret;
540252726Srpaulo	char *pos, *end;
541252726Srpaulo
542252726Srpaulo	pos = buf;
543252726Srpaulo	end = buf + buflen;
544252726Srpaulo
545252726Srpaulo	ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
546252726Srpaulo			  "ssid=%s\n",
547252726Srpaulo			  MAC2STR(hapd->own_addr),
548252726Srpaulo			  wpa_ssid_txt(hapd->conf->ssid.ssid,
549252726Srpaulo				       hapd->conf->ssid.ssid_len));
550252726Srpaulo	if (ret < 0 || ret >= end - pos)
551252726Srpaulo		return pos - buf;
552252726Srpaulo	pos += ret;
553252726Srpaulo
554252726Srpaulo#ifdef CONFIG_WPS
555252726Srpaulo	ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
556252726Srpaulo			  hapd->conf->wps_state == 0 ? "disabled" :
557252726Srpaulo			  (hapd->conf->wps_state == 1 ? "not configured" :
558252726Srpaulo			   "configured"));
559252726Srpaulo	if (ret < 0 || ret >= end - pos)
560252726Srpaulo		return pos - buf;
561252726Srpaulo	pos += ret;
562252726Srpaulo
563252726Srpaulo	if (hapd->conf->wps_state && hapd->conf->wpa &&
564252726Srpaulo	    hapd->conf->ssid.wpa_passphrase) {
565252726Srpaulo		ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
566252726Srpaulo				  hapd->conf->ssid.wpa_passphrase);
567252726Srpaulo		if (ret < 0 || ret >= end - pos)
568252726Srpaulo			return pos - buf;
569252726Srpaulo		pos += ret;
570252726Srpaulo	}
571252726Srpaulo
572252726Srpaulo	if (hapd->conf->wps_state && hapd->conf->wpa &&
573252726Srpaulo	    hapd->conf->ssid.wpa_psk &&
574252726Srpaulo	    hapd->conf->ssid.wpa_psk->group) {
575252726Srpaulo		char hex[PMK_LEN * 2 + 1];
576252726Srpaulo		wpa_snprintf_hex(hex, sizeof(hex),
577252726Srpaulo				 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
578252726Srpaulo		ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
579252726Srpaulo		if (ret < 0 || ret >= end - pos)
580252726Srpaulo			return pos - buf;
581252726Srpaulo		pos += ret;
582252726Srpaulo	}
583252726Srpaulo#endif /* CONFIG_WPS */
584252726Srpaulo
585252726Srpaulo	if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
586252726Srpaulo		ret = os_snprintf(pos, end - pos, "key_mgmt=");
587252726Srpaulo		if (ret < 0 || ret >= end - pos)
588252726Srpaulo			return pos - buf;
589252726Srpaulo		pos += ret;
590252726Srpaulo
591252726Srpaulo		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
592252726Srpaulo			ret = os_snprintf(pos, end - pos, "WPA-PSK ");
593252726Srpaulo			if (ret < 0 || ret >= end - pos)
594252726Srpaulo				return pos - buf;
595252726Srpaulo			pos += ret;
596252726Srpaulo		}
597252726Srpaulo		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
598252726Srpaulo			ret = os_snprintf(pos, end - pos, "WPA-EAP ");
599252726Srpaulo			if (ret < 0 || ret >= end - pos)
600252726Srpaulo				return pos - buf;
601252726Srpaulo			pos += ret;
602252726Srpaulo		}
603252726Srpaulo#ifdef CONFIG_IEEE80211R
604252726Srpaulo		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
605252726Srpaulo			ret = os_snprintf(pos, end - pos, "FT-PSK ");
606252726Srpaulo			if (ret < 0 || ret >= end - pos)
607252726Srpaulo				return pos - buf;
608252726Srpaulo			pos += ret;
609252726Srpaulo		}
610252726Srpaulo		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
611252726Srpaulo			ret = os_snprintf(pos, end - pos, "FT-EAP ");
612252726Srpaulo			if (ret < 0 || ret >= end - pos)
613252726Srpaulo				return pos - buf;
614252726Srpaulo			pos += ret;
615252726Srpaulo		}
616252726Srpaulo#endif /* CONFIG_IEEE80211R */
617252726Srpaulo#ifdef CONFIG_IEEE80211W
618252726Srpaulo		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
619252726Srpaulo			ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
620252726Srpaulo			if (ret < 0 || ret >= end - pos)
621252726Srpaulo				return pos - buf;
622252726Srpaulo			pos += ret;
623252726Srpaulo		}
624252726Srpaulo		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
625252726Srpaulo			ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
626252726Srpaulo			if (ret < 0 || ret >= end - pos)
627252726Srpaulo				return pos - buf;
628252726Srpaulo			pos += ret;
629252726Srpaulo		}
630252726Srpaulo#endif /* CONFIG_IEEE80211W */
631252726Srpaulo
632252726Srpaulo		ret = os_snprintf(pos, end - pos, "\n");
633252726Srpaulo		if (ret < 0 || ret >= end - pos)
634252726Srpaulo			return pos - buf;
635252726Srpaulo		pos += ret;
636252726Srpaulo	}
637252726Srpaulo
638252726Srpaulo	if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
639252726Srpaulo		ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
640252726Srpaulo		if (ret < 0 || ret >= end - pos)
641252726Srpaulo			return pos - buf;
642252726Srpaulo		pos += ret;
643252726Srpaulo	} else if (hapd->conf->wpa &&
644252726Srpaulo		   hapd->conf->wpa_group == WPA_CIPHER_GCMP) {
645252726Srpaulo		ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n");
646252726Srpaulo		if (ret < 0 || ret >= end - pos)
647252726Srpaulo			return pos - buf;
648252726Srpaulo		pos += ret;
649252726Srpaulo	} else if (hapd->conf->wpa &&
650252726Srpaulo		   hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
651252726Srpaulo		ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
652252726Srpaulo		if (ret < 0 || ret >= end - pos)
653252726Srpaulo			return pos - buf;
654252726Srpaulo		pos += ret;
655252726Srpaulo	}
656252726Srpaulo
657252726Srpaulo	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
658252726Srpaulo		ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
659252726Srpaulo		if (ret < 0 || ret >= end - pos)
660252726Srpaulo			return pos - buf;
661252726Srpaulo		pos += ret;
662252726Srpaulo
663252726Srpaulo		if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
664252726Srpaulo			ret = os_snprintf(pos, end - pos, "CCMP ");
665252726Srpaulo			if (ret < 0 || ret >= end - pos)
666252726Srpaulo				return pos - buf;
667252726Srpaulo			pos += ret;
668252726Srpaulo		}
669252726Srpaulo		if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) {
670252726Srpaulo			ret = os_snprintf(pos, end - pos, "GCMP ");
671252726Srpaulo			if (ret < 0 || ret >= end - pos)
672252726Srpaulo				return pos - buf;
673252726Srpaulo			pos += ret;
674252726Srpaulo		}
675252726Srpaulo		if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
676252726Srpaulo			ret = os_snprintf(pos, end - pos, "TKIP ");
677252726Srpaulo			if (ret < 0 || ret >= end - pos)
678252726Srpaulo				return pos - buf;
679252726Srpaulo			pos += ret;
680252726Srpaulo		}
681252726Srpaulo
682252726Srpaulo		ret = os_snprintf(pos, end - pos, "\n");
683252726Srpaulo		if (ret < 0 || ret >= end - pos)
684252726Srpaulo			return pos - buf;
685252726Srpaulo		pos += ret;
686252726Srpaulo	}
687252726Srpaulo
688252726Srpaulo	if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
689252726Srpaulo		ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
690252726Srpaulo		if (ret < 0 || ret >= end - pos)
691252726Srpaulo			return pos - buf;
692252726Srpaulo		pos += ret;
693252726Srpaulo
694252726Srpaulo		if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
695252726Srpaulo			ret = os_snprintf(pos, end - pos, "CCMP ");
696252726Srpaulo			if (ret < 0 || ret >= end - pos)
697252726Srpaulo				return pos - buf;
698252726Srpaulo			pos += ret;
699252726Srpaulo		}
700252726Srpaulo		if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) {
701252726Srpaulo			ret = os_snprintf(pos, end - pos, "GCMP ");
702252726Srpaulo			if (ret < 0 || ret >= end - pos)
703252726Srpaulo				return pos - buf;
704252726Srpaulo			pos += ret;
705252726Srpaulo		}
706252726Srpaulo		if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
707252726Srpaulo			ret = os_snprintf(pos, end - pos, "TKIP ");
708252726Srpaulo			if (ret < 0 || ret >= end - pos)
709252726Srpaulo				return pos - buf;
710252726Srpaulo			pos += ret;
711252726Srpaulo		}
712252726Srpaulo
713252726Srpaulo		ret = os_snprintf(pos, end - pos, "\n");
714252726Srpaulo		if (ret < 0 || ret >= end - pos)
715252726Srpaulo			return pos - buf;
716252726Srpaulo		pos += ret;
717252726Srpaulo	}
718252726Srpaulo
719252726Srpaulo	return pos - buf;
720252726Srpaulo}
721252726Srpaulo
722252726Srpaulo
723252726Srpaulostatic int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
724252726Srpaulo{
725252726Srpaulo	char *value;
726252726Srpaulo	int ret = 0;
727252726Srpaulo
728252726Srpaulo	value = os_strchr(cmd, ' ');
729252726Srpaulo	if (value == NULL)
730252726Srpaulo		return -1;
731252726Srpaulo	*value++ = '\0';
732252726Srpaulo
733252726Srpaulo	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
734252726Srpaulo	if (0) {
735252726Srpaulo#ifdef CONFIG_WPS_TESTING
736252726Srpaulo	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
737252726Srpaulo		long int val;
738252726Srpaulo		val = strtol(value, NULL, 0);
739252726Srpaulo		if (val < 0 || val > 0xff) {
740252726Srpaulo			ret = -1;
741252726Srpaulo			wpa_printf(MSG_DEBUG, "WPS: Invalid "
742252726Srpaulo				   "wps_version_number %ld", val);
743252726Srpaulo		} else {
744252726Srpaulo			wps_version_number = val;
745252726Srpaulo			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
746252726Srpaulo				   "version %u.%u",
747252726Srpaulo				   (wps_version_number & 0xf0) >> 4,
748252726Srpaulo				   wps_version_number & 0x0f);
749252726Srpaulo			hostapd_wps_update_ie(hapd);
750252726Srpaulo		}
751252726Srpaulo	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
752252726Srpaulo		wps_testing_dummy_cred = atoi(value);
753252726Srpaulo		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
754252726Srpaulo			   wps_testing_dummy_cred);
755252726Srpaulo#endif /* CONFIG_WPS_TESTING */
756252726Srpaulo#ifdef CONFIG_INTERWORKING
757252726Srpaulo	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
758252726Srpaulo		int val = atoi(value);
759252726Srpaulo		if (val <= 0)
760252726Srpaulo			ret = -1;
761252726Srpaulo		else
762252726Srpaulo			hapd->gas_frag_limit = val;
763252726Srpaulo#endif /* CONFIG_INTERWORKING */
764252726Srpaulo	} else {
765252726Srpaulo		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
766252726Srpaulo	}
767252726Srpaulo
768252726Srpaulo	return ret;
769252726Srpaulo}
770252726Srpaulo
771252726Srpaulo
772252726Srpaulostatic int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
773252726Srpaulo				  char *buf, size_t buflen)
774252726Srpaulo{
775252726Srpaulo	int res;
776252726Srpaulo
777252726Srpaulo	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
778252726Srpaulo
779252726Srpaulo	if (os_strcmp(cmd, "version") == 0) {
780252726Srpaulo		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
781252726Srpaulo		if (res < 0 || (unsigned int) res >= buflen)
782252726Srpaulo			return -1;
783252726Srpaulo		return res;
784252726Srpaulo	}
785252726Srpaulo
786252726Srpaulo	return -1;
787252726Srpaulo}
788252726Srpaulo
789252726Srpaulo
790252726Srpaulostatic int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
791252726Srpaulo{
792252726Srpaulo	if (hostapd_enable_iface(iface) < 0) {
793252726Srpaulo		wpa_printf(MSG_ERROR, "Enabling of interface failed");
794252726Srpaulo		return -1;
795252726Srpaulo	}
796252726Srpaulo	return 0;
797252726Srpaulo}
798252726Srpaulo
799252726Srpaulo
800252726Srpaulostatic int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
801252726Srpaulo{
802252726Srpaulo	if (hostapd_reload_iface(iface) < 0) {
803252726Srpaulo		wpa_printf(MSG_ERROR, "Reloading of interface failed");
804252726Srpaulo		return -1;
805252726Srpaulo	}
806252726Srpaulo	return 0;
807252726Srpaulo}
808252726Srpaulo
809252726Srpaulo
810252726Srpaulostatic int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
811252726Srpaulo{
812252726Srpaulo	if (hostapd_disable_iface(iface) < 0) {
813252726Srpaulo		wpa_printf(MSG_ERROR, "Disabling of interface failed");
814252726Srpaulo		return -1;
815252726Srpaulo	}
816252726Srpaulo	return 0;
817252726Srpaulo}
818252726Srpaulo
819252726Srpaulo
820214503Srpaulostatic void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
821214503Srpaulo				       void *sock_ctx)
822214503Srpaulo{
823214503Srpaulo	struct hostapd_data *hapd = eloop_ctx;
824214503Srpaulo	char buf[256];
825214503Srpaulo	int res;
826214503Srpaulo	struct sockaddr_un from;
827214503Srpaulo	socklen_t fromlen = sizeof(from);
828214503Srpaulo	char *reply;
829214503Srpaulo	const int reply_size = 4096;
830214503Srpaulo	int reply_len;
831252726Srpaulo	int level = MSG_DEBUG;
832214503Srpaulo
833214503Srpaulo	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
834214503Srpaulo		       (struct sockaddr *) &from, &fromlen);
835214503Srpaulo	if (res < 0) {
836214503Srpaulo		perror("recvfrom(ctrl_iface)");
837214503Srpaulo		return;
838214503Srpaulo	}
839214503Srpaulo	buf[res] = '\0';
840252726Srpaulo	if (os_strcmp(buf, "PING") == 0)
841252726Srpaulo		level = MSG_EXCESSIVE;
842252726Srpaulo	wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
843214503Srpaulo
844214503Srpaulo	reply = os_malloc(reply_size);
845214503Srpaulo	if (reply == NULL) {
846214503Srpaulo		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
847214503Srpaulo		       fromlen);
848214503Srpaulo		return;
849214503Srpaulo	}
850214503Srpaulo
851214503Srpaulo	os_memcpy(reply, "OK\n", 3);
852214503Srpaulo	reply_len = 3;
853214503Srpaulo
854214503Srpaulo	if (os_strcmp(buf, "PING") == 0) {
855214503Srpaulo		os_memcpy(reply, "PONG\n", 5);
856214503Srpaulo		reply_len = 5;
857252726Srpaulo	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
858252726Srpaulo		if (wpa_debug_reopen_file() < 0)
859252726Srpaulo			reply_len = -1;
860214503Srpaulo	} else if (os_strcmp(buf, "MIB") == 0) {
861214503Srpaulo		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
862214503Srpaulo		if (reply_len >= 0) {
863214503Srpaulo			res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
864214503Srpaulo					  reply_size - reply_len);
865214503Srpaulo			if (res < 0)
866214503Srpaulo				reply_len = -1;
867214503Srpaulo			else
868214503Srpaulo				reply_len += res;
869214503Srpaulo		}
870214503Srpaulo		if (reply_len >= 0) {
871214503Srpaulo			res = ieee802_1x_get_mib(hapd, reply + reply_len,
872214503Srpaulo						 reply_size - reply_len);
873214503Srpaulo			if (res < 0)
874214503Srpaulo				reply_len = -1;
875214503Srpaulo			else
876214503Srpaulo				reply_len += res;
877214503Srpaulo		}
878214503Srpaulo#ifndef CONFIG_NO_RADIUS
879214503Srpaulo		if (reply_len >= 0) {
880214503Srpaulo			res = radius_client_get_mib(hapd->radius,
881214503Srpaulo						    reply + reply_len,
882214503Srpaulo						    reply_size - reply_len);
883214503Srpaulo			if (res < 0)
884214503Srpaulo				reply_len = -1;
885214503Srpaulo			else
886214503Srpaulo				reply_len += res;
887214503Srpaulo		}
888214503Srpaulo#endif /* CONFIG_NO_RADIUS */
889214503Srpaulo	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
890214503Srpaulo		reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
891214503Srpaulo							 reply_size);
892214503Srpaulo	} else if (os_strncmp(buf, "STA ", 4) == 0) {
893214503Srpaulo		reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
894214503Srpaulo						   reply_size);
895214503Srpaulo	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
896214503Srpaulo		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
897214503Srpaulo							reply_size);
898214503Srpaulo	} else if (os_strcmp(buf, "ATTACH") == 0) {
899214503Srpaulo		if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
900214503Srpaulo			reply_len = -1;
901214503Srpaulo	} else if (os_strcmp(buf, "DETACH") == 0) {
902214503Srpaulo		if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
903214503Srpaulo			reply_len = -1;
904214503Srpaulo	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
905214503Srpaulo		if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
906214503Srpaulo						    buf + 6))
907214503Srpaulo			reply_len = -1;
908214503Srpaulo	} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
909214503Srpaulo		if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
910214503Srpaulo			reply_len = -1;
911214503Srpaulo	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
912214503Srpaulo		if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
913214503Srpaulo			reply_len = -1;
914214503Srpaulo	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
915214503Srpaulo		if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
916214503Srpaulo			reply_len = -1;
917214503Srpaulo#ifdef CONFIG_IEEE80211W
918214503Srpaulo#ifdef NEED_AP_MLME
919214503Srpaulo	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
920214503Srpaulo		if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
921214503Srpaulo			reply_len = -1;
922214503Srpaulo#endif /* NEED_AP_MLME */
923214503Srpaulo#endif /* CONFIG_IEEE80211W */
924214503Srpaulo#ifdef CONFIG_WPS
925214503Srpaulo	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
926214503Srpaulo		if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
927214503Srpaulo			reply_len = -1;
928252726Srpaulo	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
929252726Srpaulo		reply_len = hostapd_ctrl_iface_wps_check_pin(
930252726Srpaulo			hapd, buf + 14, reply, reply_size);
931214503Srpaulo	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
932252726Srpaulo		if (hostapd_wps_button_pushed(hapd, NULL))
933214503Srpaulo			reply_len = -1;
934252726Srpaulo	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
935252726Srpaulo		if (hostapd_wps_cancel(hapd))
936214503Srpaulo			reply_len = -1;
937214503Srpaulo	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
938214503Srpaulo		reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
939214503Srpaulo							  reply, reply_size);
940252726Srpaulo	} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
941252726Srpaulo		if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
942252726Srpaulo			reply_len = -1;
943252726Srpaulo#ifdef CONFIG_WPS_NFC
944252726Srpaulo	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
945252726Srpaulo		if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
946252726Srpaulo			reply_len = -1;
947252726Srpaulo	} else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
948252726Srpaulo		reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
949252726Srpaulo			hapd, buf + 21, reply, reply_size);
950252726Srpaulo	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
951252726Srpaulo		reply_len = hostapd_ctrl_iface_wps_nfc_token(
952252726Srpaulo			hapd, buf + 14, reply, reply_size);
953252726Srpaulo#endif /* CONFIG_WPS_NFC */
954214503Srpaulo#endif /* CONFIG_WPS */
955252726Srpaulo#ifdef CONFIG_WNM
956252726Srpaulo	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
957252726Srpaulo		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
958252726Srpaulo			reply_len = -1;
959252726Srpaulo	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
960252726Srpaulo		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
961252726Srpaulo			reply_len = -1;
962252726Srpaulo#endif /* CONFIG_WNM */
963252726Srpaulo	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
964252726Srpaulo		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
965252726Srpaulo							  reply_size);
966252726Srpaulo	} else if (os_strncmp(buf, "SET ", 4) == 0) {
967252726Srpaulo		if (hostapd_ctrl_iface_set(hapd, buf + 4))
968252726Srpaulo			reply_len = -1;
969252726Srpaulo	} else if (os_strncmp(buf, "GET ", 4) == 0) {
970252726Srpaulo		reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
971252726Srpaulo						   reply_size);
972252726Srpaulo	} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
973252726Srpaulo		if (hostapd_ctrl_iface_enable(hapd->iface))
974252726Srpaulo			reply_len = -1;
975252726Srpaulo	} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
976252726Srpaulo		if (hostapd_ctrl_iface_reload(hapd->iface))
977252726Srpaulo			reply_len = -1;
978252726Srpaulo	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
979252726Srpaulo		if (hostapd_ctrl_iface_disable(hapd->iface))
980252726Srpaulo			reply_len = -1;
981214503Srpaulo	} else {
982214503Srpaulo		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
983214503Srpaulo		reply_len = 16;
984214503Srpaulo	}
985214503Srpaulo
986214503Srpaulo	if (reply_len < 0) {
987214503Srpaulo		os_memcpy(reply, "FAIL\n", 5);
988214503Srpaulo		reply_len = 5;
989214503Srpaulo	}
990214503Srpaulo	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
991214503Srpaulo	os_free(reply);
992214503Srpaulo}
993214503Srpaulo
994214503Srpaulo
995214503Srpaulostatic char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
996214503Srpaulo{
997214503Srpaulo	char *buf;
998214503Srpaulo	size_t len;
999214503Srpaulo
1000214503Srpaulo	if (hapd->conf->ctrl_interface == NULL)
1001214503Srpaulo		return NULL;
1002214503Srpaulo
1003214503Srpaulo	len = os_strlen(hapd->conf->ctrl_interface) +
1004214503Srpaulo		os_strlen(hapd->conf->iface) + 2;
1005214503Srpaulo	buf = os_malloc(len);
1006214503Srpaulo	if (buf == NULL)
1007214503Srpaulo		return NULL;
1008214503Srpaulo
1009214503Srpaulo	os_snprintf(buf, len, "%s/%s",
1010214503Srpaulo		    hapd->conf->ctrl_interface, hapd->conf->iface);
1011214503Srpaulo	buf[len - 1] = '\0';
1012214503Srpaulo	return buf;
1013214503Srpaulo}
1014214503Srpaulo
1015214503Srpaulo
1016214503Srpaulostatic void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
1017214503Srpaulo				      const char *txt, size_t len)
1018214503Srpaulo{
1019214503Srpaulo	struct hostapd_data *hapd = ctx;
1020214503Srpaulo	if (hapd == NULL)
1021214503Srpaulo		return;
1022214503Srpaulo	hostapd_ctrl_iface_send(hapd, level, txt, len);
1023214503Srpaulo}
1024214503Srpaulo
1025214503Srpaulo
1026214503Srpauloint hostapd_ctrl_iface_init(struct hostapd_data *hapd)
1027214503Srpaulo{
1028214503Srpaulo	struct sockaddr_un addr;
1029214503Srpaulo	int s = -1;
1030214503Srpaulo	char *fname = NULL;
1031214503Srpaulo
1032252726Srpaulo	if (hapd->ctrl_sock > -1) {
1033252726Srpaulo		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
1034252726Srpaulo		return 0;
1035252726Srpaulo	}
1036214503Srpaulo
1037214503Srpaulo	if (hapd->conf->ctrl_interface == NULL)
1038214503Srpaulo		return 0;
1039214503Srpaulo
1040214503Srpaulo	if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1041214503Srpaulo		if (errno == EEXIST) {
1042214503Srpaulo			wpa_printf(MSG_DEBUG, "Using existing control "
1043214503Srpaulo				   "interface directory.");
1044214503Srpaulo		} else {
1045214503Srpaulo			perror("mkdir[ctrl_interface]");
1046214503Srpaulo			goto fail;
1047214503Srpaulo		}
1048214503Srpaulo	}
1049214503Srpaulo
1050214503Srpaulo	if (hapd->conf->ctrl_interface_gid_set &&
1051252726Srpaulo	    chown(hapd->conf->ctrl_interface, -1,
1052214503Srpaulo		  hapd->conf->ctrl_interface_gid) < 0) {
1053214503Srpaulo		perror("chown[ctrl_interface]");
1054214503Srpaulo		return -1;
1055214503Srpaulo	}
1056214503Srpaulo
1057252726Srpaulo#ifdef ANDROID
1058252726Srpaulo	/*
1059252726Srpaulo	 * Android is using umask 0077 which would leave the control interface
1060252726Srpaulo	 * directory without group access. This breaks things since Wi-Fi
1061252726Srpaulo	 * framework assumes that this directory can be accessed by other
1062252726Srpaulo	 * applications in the wifi group. Fix this by adding group access even
1063252726Srpaulo	 * if umask value would prevent this.
1064252726Srpaulo	 */
1065252726Srpaulo	if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1066252726Srpaulo		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
1067252726Srpaulo			   strerror(errno));
1068252726Srpaulo		/* Try to continue anyway */
1069252726Srpaulo	}
1070252726Srpaulo#endif /* ANDROID */
1071252726Srpaulo
1072214503Srpaulo	if (os_strlen(hapd->conf->ctrl_interface) + 1 +
1073214503Srpaulo	    os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
1074214503Srpaulo		goto fail;
1075214503Srpaulo
1076214503Srpaulo	s = socket(PF_UNIX, SOCK_DGRAM, 0);
1077214503Srpaulo	if (s < 0) {
1078214503Srpaulo		perror("socket(PF_UNIX)");
1079214503Srpaulo		goto fail;
1080214503Srpaulo	}
1081214503Srpaulo
1082214503Srpaulo	os_memset(&addr, 0, sizeof(addr));
1083214503Srpaulo#ifdef __FreeBSD__
1084214503Srpaulo	addr.sun_len = sizeof(addr);
1085214503Srpaulo#endif /* __FreeBSD__ */
1086214503Srpaulo	addr.sun_family = AF_UNIX;
1087214503Srpaulo	fname = hostapd_ctrl_iface_path(hapd);
1088214503Srpaulo	if (fname == NULL)
1089214503Srpaulo		goto fail;
1090214503Srpaulo	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1091214503Srpaulo	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1092214503Srpaulo		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1093214503Srpaulo			   strerror(errno));
1094214503Srpaulo		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1095214503Srpaulo			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1096214503Srpaulo				   " allow connections - assuming it was left"
1097214503Srpaulo				   "over from forced program termination");
1098214503Srpaulo			if (unlink(fname) < 0) {
1099214503Srpaulo				perror("unlink[ctrl_iface]");
1100214503Srpaulo				wpa_printf(MSG_ERROR, "Could not unlink "
1101214503Srpaulo					   "existing ctrl_iface socket '%s'",
1102214503Srpaulo					   fname);
1103214503Srpaulo				goto fail;
1104214503Srpaulo			}
1105214503Srpaulo			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1106214503Srpaulo			    0) {
1107252726Srpaulo				perror("hostapd-ctrl-iface: bind(PF_UNIX)");
1108214503Srpaulo				goto fail;
1109214503Srpaulo			}
1110214503Srpaulo			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1111214503Srpaulo				   "ctrl_iface socket '%s'", fname);
1112214503Srpaulo		} else {
1113214503Srpaulo			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1114214503Srpaulo				   "be in use - cannot override it");
1115214503Srpaulo			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1116214503Srpaulo				   "not used anymore", fname);
1117214503Srpaulo			os_free(fname);
1118214503Srpaulo			fname = NULL;
1119214503Srpaulo			goto fail;
1120214503Srpaulo		}
1121214503Srpaulo	}
1122214503Srpaulo
1123214503Srpaulo	if (hapd->conf->ctrl_interface_gid_set &&
1124252726Srpaulo	    chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
1125214503Srpaulo		perror("chown[ctrl_interface/ifname]");
1126214503Srpaulo		goto fail;
1127214503Srpaulo	}
1128214503Srpaulo
1129214503Srpaulo	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1130214503Srpaulo		perror("chmod[ctrl_interface/ifname]");
1131214503Srpaulo		goto fail;
1132214503Srpaulo	}
1133214503Srpaulo	os_free(fname);
1134214503Srpaulo
1135214503Srpaulo	hapd->ctrl_sock = s;
1136214503Srpaulo	eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
1137214503Srpaulo				 NULL);
1138214503Srpaulo	hapd->msg_ctx = hapd;
1139214503Srpaulo	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
1140214503Srpaulo
1141214503Srpaulo	return 0;
1142214503Srpaulo
1143214503Srpaulofail:
1144214503Srpaulo	if (s >= 0)
1145214503Srpaulo		close(s);
1146214503Srpaulo	if (fname) {
1147214503Srpaulo		unlink(fname);
1148214503Srpaulo		os_free(fname);
1149214503Srpaulo	}
1150214503Srpaulo	return -1;
1151214503Srpaulo}
1152214503Srpaulo
1153214503Srpaulo
1154214503Srpaulovoid hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
1155214503Srpaulo{
1156214503Srpaulo	struct wpa_ctrl_dst *dst, *prev;
1157214503Srpaulo
1158214503Srpaulo	if (hapd->ctrl_sock > -1) {
1159214503Srpaulo		char *fname;
1160214503Srpaulo		eloop_unregister_read_sock(hapd->ctrl_sock);
1161214503Srpaulo		close(hapd->ctrl_sock);
1162214503Srpaulo		hapd->ctrl_sock = -1;
1163214503Srpaulo		fname = hostapd_ctrl_iface_path(hapd);
1164214503Srpaulo		if (fname)
1165214503Srpaulo			unlink(fname);
1166214503Srpaulo		os_free(fname);
1167214503Srpaulo
1168214503Srpaulo		if (hapd->conf->ctrl_interface &&
1169214503Srpaulo		    rmdir(hapd->conf->ctrl_interface) < 0) {
1170214503Srpaulo			if (errno == ENOTEMPTY) {
1171214503Srpaulo				wpa_printf(MSG_DEBUG, "Control interface "
1172214503Srpaulo					   "directory not empty - leaving it "
1173214503Srpaulo					   "behind");
1174214503Srpaulo			} else {
1175214503Srpaulo				perror("rmdir[ctrl_interface]");
1176214503Srpaulo			}
1177214503Srpaulo		}
1178214503Srpaulo	}
1179214503Srpaulo
1180214503Srpaulo	dst = hapd->ctrl_dst;
1181214503Srpaulo	while (dst) {
1182214503Srpaulo		prev = dst;
1183214503Srpaulo		dst = dst->next;
1184214503Srpaulo		os_free(prev);
1185214503Srpaulo	}
1186214503Srpaulo}
1187214503Srpaulo
1188214503Srpaulo
1189252726Srpaulostatic int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
1190252726Srpaulo				  char *buf)
1191252726Srpaulo{
1192252726Srpaulo	if (hostapd_add_iface(interfaces, buf) < 0) {
1193252726Srpaulo		wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
1194252726Srpaulo		return -1;
1195252726Srpaulo	}
1196252726Srpaulo	return 0;
1197252726Srpaulo}
1198252726Srpaulo
1199252726Srpaulo
1200252726Srpaulostatic int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
1201252726Srpaulo				     char *buf)
1202252726Srpaulo{
1203252726Srpaulo	if (hostapd_remove_iface(interfaces, buf) < 0) {
1204252726Srpaulo		wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
1205252726Srpaulo		return -1;
1206252726Srpaulo	}
1207252726Srpaulo	return 0;
1208252726Srpaulo}
1209252726Srpaulo
1210252726Srpaulo
1211252726Srpaulostatic void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
1212252726Srpaulo					      void *sock_ctx)
1213252726Srpaulo{
1214252726Srpaulo	void *interfaces = eloop_ctx;
1215252726Srpaulo	char buf[256];
1216252726Srpaulo	int res;
1217252726Srpaulo	struct sockaddr_un from;
1218252726Srpaulo	socklen_t fromlen = sizeof(from);
1219252726Srpaulo	char reply[24];
1220252726Srpaulo	int reply_len;
1221252726Srpaulo
1222252726Srpaulo	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1223252726Srpaulo		       (struct sockaddr *) &from, &fromlen);
1224252726Srpaulo	if (res < 0) {
1225252726Srpaulo		perror("recvfrom(ctrl_iface)");
1226252726Srpaulo		return;
1227252726Srpaulo	}
1228252726Srpaulo	buf[res] = '\0';
1229252726Srpaulo
1230252726Srpaulo	os_memcpy(reply, "OK\n", 3);
1231252726Srpaulo	reply_len = 3;
1232252726Srpaulo
1233252726Srpaulo	if (os_strcmp(buf, "PING") == 0) {
1234252726Srpaulo		os_memcpy(reply, "PONG\n", 5);
1235252726Srpaulo		reply_len = 5;
1236252726Srpaulo	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
1237252726Srpaulo		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
1238252726Srpaulo			reply_len = -1;
1239252726Srpaulo	} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
1240252726Srpaulo		if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
1241252726Srpaulo			reply_len = -1;
1242252726Srpaulo	} else {
1243252726Srpaulo		wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
1244252726Srpaulo			   "ignored");
1245252726Srpaulo		reply_len = -1;
1246252726Srpaulo	}
1247252726Srpaulo
1248252726Srpaulo	if (reply_len < 0) {
1249252726Srpaulo		os_memcpy(reply, "FAIL\n", 5);
1250252726Srpaulo		reply_len = 5;
1251252726Srpaulo	}
1252252726Srpaulo
1253252726Srpaulo	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1254252726Srpaulo}
1255252726Srpaulo
1256252726Srpaulo
1257252726Srpaulostatic char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
1258252726Srpaulo{
1259252726Srpaulo	char *buf;
1260252726Srpaulo	size_t len;
1261252726Srpaulo
1262252726Srpaulo	if (interface->global_iface_path == NULL)
1263252726Srpaulo		return NULL;
1264252726Srpaulo
1265252726Srpaulo	len = os_strlen(interface->global_iface_path) +
1266252726Srpaulo		os_strlen(interface->global_iface_name) + 2;
1267252726Srpaulo	buf = os_malloc(len);
1268252726Srpaulo	if (buf == NULL)
1269252726Srpaulo		return NULL;
1270252726Srpaulo
1271252726Srpaulo	os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
1272252726Srpaulo		    interface->global_iface_name);
1273252726Srpaulo	buf[len - 1] = '\0';
1274252726Srpaulo	return buf;
1275252726Srpaulo}
1276252726Srpaulo
1277252726Srpaulo
1278252726Srpauloint hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
1279252726Srpaulo{
1280252726Srpaulo	struct sockaddr_un addr;
1281252726Srpaulo	int s = -1;
1282252726Srpaulo	char *fname = NULL;
1283252726Srpaulo
1284252726Srpaulo	if (interface->global_iface_path == NULL) {
1285252726Srpaulo		wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
1286252726Srpaulo		return 0;
1287252726Srpaulo	}
1288252726Srpaulo
1289252726Srpaulo	if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
1290252726Srpaulo		if (errno == EEXIST) {
1291252726Srpaulo			wpa_printf(MSG_DEBUG, "Using existing control "
1292252726Srpaulo				   "interface directory.");
1293252726Srpaulo		} else {
1294252726Srpaulo			perror("mkdir[ctrl_interface]");
1295252726Srpaulo			goto fail;
1296252726Srpaulo		}
1297252726Srpaulo	}
1298252726Srpaulo
1299252726Srpaulo	if (os_strlen(interface->global_iface_path) + 1 +
1300252726Srpaulo	    os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
1301252726Srpaulo		goto fail;
1302252726Srpaulo
1303252726Srpaulo	s = socket(PF_UNIX, SOCK_DGRAM, 0);
1304252726Srpaulo	if (s < 0) {
1305252726Srpaulo		perror("socket(PF_UNIX)");
1306252726Srpaulo		goto fail;
1307252726Srpaulo	}
1308252726Srpaulo
1309252726Srpaulo	os_memset(&addr, 0, sizeof(addr));
1310252726Srpaulo#ifdef __FreeBSD__
1311252726Srpaulo	addr.sun_len = sizeof(addr);
1312252726Srpaulo#endif /* __FreeBSD__ */
1313252726Srpaulo	addr.sun_family = AF_UNIX;
1314252726Srpaulo	fname = hostapd_global_ctrl_iface_path(interface);
1315252726Srpaulo	if (fname == NULL)
1316252726Srpaulo		goto fail;
1317252726Srpaulo	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1318252726Srpaulo	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1319252726Srpaulo		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1320252726Srpaulo			   strerror(errno));
1321252726Srpaulo		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1322252726Srpaulo			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1323252726Srpaulo				   " allow connections - assuming it was left"
1324252726Srpaulo				   "over from forced program termination");
1325252726Srpaulo			if (unlink(fname) < 0) {
1326252726Srpaulo				perror("unlink[ctrl_iface]");
1327252726Srpaulo				wpa_printf(MSG_ERROR, "Could not unlink "
1328252726Srpaulo					   "existing ctrl_iface socket '%s'",
1329252726Srpaulo					   fname);
1330252726Srpaulo				goto fail;
1331252726Srpaulo			}
1332252726Srpaulo			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1333252726Srpaulo			    0) {
1334252726Srpaulo				perror("bind(PF_UNIX)");
1335252726Srpaulo				goto fail;
1336252726Srpaulo			}
1337252726Srpaulo			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1338252726Srpaulo				   "ctrl_iface socket '%s'", fname);
1339252726Srpaulo		} else {
1340252726Srpaulo			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1341252726Srpaulo				   "be in use - cannot override it");
1342252726Srpaulo			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1343252726Srpaulo				   "not used anymore", fname);
1344252726Srpaulo			os_free(fname);
1345252726Srpaulo			fname = NULL;
1346252726Srpaulo			goto fail;
1347252726Srpaulo		}
1348252726Srpaulo	}
1349252726Srpaulo
1350252726Srpaulo	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1351252726Srpaulo		perror("chmod[ctrl_interface/ifname]");
1352252726Srpaulo		goto fail;
1353252726Srpaulo	}
1354252726Srpaulo	os_free(fname);
1355252726Srpaulo
1356252726Srpaulo	interface->global_ctrl_sock = s;
1357252726Srpaulo	eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
1358252726Srpaulo				 interface, NULL);
1359252726Srpaulo
1360252726Srpaulo	return 0;
1361252726Srpaulo
1362252726Srpaulofail:
1363252726Srpaulo	if (s >= 0)
1364252726Srpaulo		close(s);
1365252726Srpaulo	if (fname) {
1366252726Srpaulo		unlink(fname);
1367252726Srpaulo		os_free(fname);
1368252726Srpaulo	}
1369252726Srpaulo	return -1;
1370252726Srpaulo}
1371252726Srpaulo
1372252726Srpaulo
1373252726Srpaulovoid hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
1374252726Srpaulo{
1375252726Srpaulo	char *fname = NULL;
1376252726Srpaulo
1377252726Srpaulo	if (interfaces->global_ctrl_sock > -1) {
1378252726Srpaulo		eloop_unregister_read_sock(interfaces->global_ctrl_sock);
1379252726Srpaulo		close(interfaces->global_ctrl_sock);
1380252726Srpaulo		interfaces->global_ctrl_sock = -1;
1381252726Srpaulo		fname = hostapd_global_ctrl_iface_path(interfaces);
1382252726Srpaulo		if (fname) {
1383252726Srpaulo			unlink(fname);
1384252726Srpaulo			os_free(fname);
1385252726Srpaulo		}
1386252726Srpaulo
1387252726Srpaulo		if (interfaces->global_iface_path &&
1388252726Srpaulo		    rmdir(interfaces->global_iface_path) < 0) {
1389252726Srpaulo			if (errno == ENOTEMPTY) {
1390252726Srpaulo				wpa_printf(MSG_DEBUG, "Control interface "
1391252726Srpaulo					   "directory not empty - leaving it "
1392252726Srpaulo					   "behind");
1393252726Srpaulo			} else {
1394252726Srpaulo				perror("rmdir[ctrl_interface]");
1395252726Srpaulo			}
1396252726Srpaulo		}
1397252726Srpaulo		os_free(interfaces->global_iface_path);
1398252726Srpaulo		interfaces->global_iface_path = NULL;
1399252726Srpaulo	}
1400252726Srpaulo}
1401252726Srpaulo
1402252726Srpaulo
1403214503Srpaulostatic void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1404214503Srpaulo				    const char *buf, size_t len)
1405214503Srpaulo{
1406214503Srpaulo	struct wpa_ctrl_dst *dst, *next;
1407214503Srpaulo	struct msghdr msg;
1408214503Srpaulo	int idx;
1409214503Srpaulo	struct iovec io[2];
1410214503Srpaulo	char levelstr[10];
1411214503Srpaulo
1412214503Srpaulo	dst = hapd->ctrl_dst;
1413214503Srpaulo	if (hapd->ctrl_sock < 0 || dst == NULL)
1414214503Srpaulo		return;
1415214503Srpaulo
1416214503Srpaulo	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1417214503Srpaulo	io[0].iov_base = levelstr;
1418214503Srpaulo	io[0].iov_len = os_strlen(levelstr);
1419214503Srpaulo	io[1].iov_base = (char *) buf;
1420214503Srpaulo	io[1].iov_len = len;
1421214503Srpaulo	os_memset(&msg, 0, sizeof(msg));
1422214503Srpaulo	msg.msg_iov = io;
1423214503Srpaulo	msg.msg_iovlen = 2;
1424214503Srpaulo
1425214503Srpaulo	idx = 0;
1426214503Srpaulo	while (dst) {
1427214503Srpaulo		next = dst->next;
1428214503Srpaulo		if (level >= dst->debug_level) {
1429214503Srpaulo			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1430214503Srpaulo				    (u8 *) dst->addr.sun_path, dst->addrlen -
1431214503Srpaulo				    offsetof(struct sockaddr_un, sun_path));
1432214503Srpaulo			msg.msg_name = &dst->addr;
1433214503Srpaulo			msg.msg_namelen = dst->addrlen;
1434214503Srpaulo			if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1435214503Srpaulo				int _errno = errno;
1436214503Srpaulo				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1437214503Srpaulo					   "%d - %s",
1438214503Srpaulo					   idx, errno, strerror(errno));
1439214503Srpaulo				dst->errors++;
1440214503Srpaulo				if (dst->errors > 10 || _errno == ENOENT) {
1441214503Srpaulo					hostapd_ctrl_iface_detach(
1442214503Srpaulo						hapd, &dst->addr,
1443214503Srpaulo						dst->addrlen);
1444214503Srpaulo				}
1445214503Srpaulo			} else
1446214503Srpaulo				dst->errors = 0;
1447214503Srpaulo		}
1448214503Srpaulo		idx++;
1449214503Srpaulo		dst = next;
1450214503Srpaulo	}
1451214503Srpaulo}
1452214503Srpaulo
1453214503Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */
1454