ctrl_iface.c revision cce06667447b5aec83452adb0c15100ada531095
1/*
2 * hostapd / UNIX domain socket -based control interface
3 * Copyright (c) 2004-2013, 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
491
492static const char * pbc_status_str(enum pbc_status status)
493{
494	switch (status) {
495	case WPS_PBC_STATUS_DISABLE:
496		return "Disabled";
497	case WPS_PBC_STATUS_ACTIVE:
498		return "Active";
499	case WPS_PBC_STATUS_TIMEOUT:
500		return "Timed-out";
501	case WPS_PBC_STATUS_OVERLAP:
502		return "Overlap";
503	default:
504		return "Unknown";
505	}
506}
507
508
509static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
510					     char *buf, size_t buflen)
511{
512	int ret;
513	char *pos, *end;
514
515	pos = buf;
516	end = buf + buflen;
517
518	ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
519			  pbc_status_str(hapd->wps_stats.pbc_status));
520
521	if (ret < 0 || ret >= end - pos)
522		return pos - buf;
523	pos += ret;
524
525	ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
526			  (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
527			   "Success":
528			   (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
529			    "Failed" : "None")));
530
531	if (ret < 0 || ret >= end - pos)
532		return pos - buf;
533	pos += ret;
534
535	/* If status == Failure - Add possible Reasons */
536	if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
537	   hapd->wps_stats.failure_reason > 0) {
538		ret = os_snprintf(pos, end - pos,
539				  "Failure Reason: %s\n",
540				  wps_ei_str(hapd->wps_stats.failure_reason));
541
542		if (ret < 0 || ret >= end - pos)
543			return pos - buf;
544		pos += ret;
545	}
546
547	if (hapd->wps_stats.status) {
548		ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
549				  MAC2STR(hapd->wps_stats.peer_addr));
550
551		if (ret < 0 || ret >= end - pos)
552			return pos - buf;
553		pos += ret;
554	}
555
556	return pos - buf;
557}
558
559#endif /* CONFIG_WPS */
560
561
562#ifdef CONFIG_INTERWORKING
563
564static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
565					      const char *cmd)
566{
567	u8 qos_map_set[16 + 2 * 21], count = 0;
568	const char *pos = cmd;
569	int val, ret;
570
571	for (;;) {
572		if (count == sizeof(qos_map_set)) {
573			wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
574			return -1;
575		}
576
577		val = atoi(pos);
578		if (val < 0 || val > 255) {
579			wpa_printf(MSG_INFO, "Invalid QoS Map Set");
580			return -1;
581		}
582
583		qos_map_set[count++] = val;
584		pos = os_strchr(pos, ',');
585		if (!pos)
586			break;
587		pos++;
588	}
589
590	if (count < 16 || count & 1) {
591		wpa_printf(MSG_INFO, "Invalid QoS Map Set");
592		return -1;
593	}
594
595	ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
596	if (ret) {
597		wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
598		return -1;
599	}
600
601	os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
602	hapd->conf->qos_map_set_len = count;
603
604	return 0;
605}
606
607
608static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
609						const char *cmd)
610{
611	u8 addr[ETH_ALEN];
612	struct sta_info *sta;
613	struct wpabuf *buf;
614	u8 *qos_map_set = hapd->conf->qos_map_set;
615	u8 qos_map_set_len = hapd->conf->qos_map_set_len;
616	int ret;
617
618	if (!qos_map_set_len) {
619		wpa_printf(MSG_INFO, "QoS Map Set is not set");
620		return -1;
621	}
622
623	if (hwaddr_aton(cmd, addr))
624		return -1;
625
626	sta = ap_get_sta(hapd, addr);
627	if (sta == NULL) {
628		wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
629			   "for QoS Map Configuration message",
630			   MAC2STR(addr));
631		return -1;
632	}
633
634	if (!sta->qos_map_enabled) {
635		wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
636			   "support for QoS Map", MAC2STR(addr));
637		return -1;
638	}
639
640	buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
641	if (buf == NULL)
642		return -1;
643
644	wpabuf_put_u8(buf, WLAN_ACTION_QOS);
645	wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
646
647	/* QoS Map Set Element */
648	wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
649	wpabuf_put_u8(buf, qos_map_set_len);
650	wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
651
652	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
653				      wpabuf_head(buf), wpabuf_len(buf));
654	wpabuf_free(buf);
655
656	return ret;
657}
658
659#endif /* CONFIG_INTERWORKING */
660
661
662#ifdef CONFIG_WNM
663
664static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
665						const char *cmd)
666{
667	u8 addr[ETH_ALEN];
668	u8 buf[1000], *pos;
669	struct ieee80211_mgmt *mgmt;
670	int disassoc_timer;
671
672	if (hwaddr_aton(cmd, addr))
673		return -1;
674	if (cmd[17] != ' ')
675		return -1;
676	disassoc_timer = atoi(cmd + 17);
677
678	os_memset(buf, 0, sizeof(buf));
679	mgmt = (struct ieee80211_mgmt *) buf;
680	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
681					   WLAN_FC_STYPE_ACTION);
682	os_memcpy(mgmt->da, addr, ETH_ALEN);
683	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
684	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
685	mgmt->u.action.category = WLAN_ACTION_WNM;
686	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
687	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
688	mgmt->u.action.u.bss_tm_req.req_mode =
689		WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
690	mgmt->u.action.u.bss_tm_req.disassoc_timer =
691		host_to_le16(disassoc_timer);
692	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
693
694	pos = mgmt->u.action.u.bss_tm_req.variable;
695
696	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
697		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
698			   "Management Request frame");
699		return -1;
700	}
701
702	return 0;
703}
704
705
706static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
707					   const char *cmd)
708{
709	u8 addr[ETH_ALEN];
710	const char *url, *timerstr;
711	u8 buf[1000], *pos;
712	struct ieee80211_mgmt *mgmt;
713	size_t url_len;
714	int disassoc_timer;
715
716	if (hwaddr_aton(cmd, addr))
717		return -1;
718
719	timerstr = cmd + 17;
720	if (*timerstr != ' ')
721		return -1;
722	timerstr++;
723	disassoc_timer = atoi(timerstr);
724	if (disassoc_timer < 0 || disassoc_timer > 65535)
725		return -1;
726
727	url = os_strchr(timerstr, ' ');
728	if (url == NULL)
729		return -1;
730	url++;
731	url_len = os_strlen(url);
732	if (url_len > 255)
733		return -1;
734
735	os_memset(buf, 0, sizeof(buf));
736	mgmt = (struct ieee80211_mgmt *) buf;
737	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
738					   WLAN_FC_STYPE_ACTION);
739	os_memcpy(mgmt->da, addr, ETH_ALEN);
740	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
741	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
742	mgmt->u.action.category = WLAN_ACTION_WNM;
743	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
744	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
745	mgmt->u.action.u.bss_tm_req.req_mode =
746		WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
747		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
748	mgmt->u.action.u.bss_tm_req.disassoc_timer =
749		host_to_le16(disassoc_timer);
750	mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
751
752	pos = mgmt->u.action.u.bss_tm_req.variable;
753
754	/* Session Information URL */
755	*pos++ = url_len;
756	os_memcpy(pos, url, url_len);
757	pos += url_len;
758
759	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
760		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
761			   "Management Request frame");
762		return -1;
763	}
764
765	/* send disassociation frame after time-out */
766	if (disassoc_timer) {
767		struct sta_info *sta;
768		int timeout, beacon_int;
769
770		/*
771		 * Prevent STA from reconnecting using cached PMKSA to force
772		 * full authentication with the authentication server (which may
773		 * decide to reject the connection),
774		 */
775		wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
776
777		sta = ap_get_sta(hapd, addr);
778		if (sta == NULL) {
779			wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
780				   "for ESS disassociation imminent message",
781				   MAC2STR(addr));
782			return -1;
783		}
784
785		beacon_int = hapd->iconf->beacon_int;
786		if (beacon_int < 1)
787			beacon_int = 100; /* best guess */
788		/* Calculate timeout in ms based on beacon_int in TU */
789		timeout = disassoc_timer * beacon_int * 128 / 125;
790		wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
791			   " set to %d ms", MAC2STR(addr), timeout);
792
793		sta->timeout_next = STA_DISASSOC_FROM_CLI;
794		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
795		eloop_register_timeout(timeout / 1000,
796				       timeout % 1000 * 1000,
797				       ap_handle_timer, hapd, sta);
798	}
799
800	return 0;
801}
802
803#endif /* CONFIG_WNM */
804
805
806static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
807					 char *buf, size_t buflen)
808{
809	int ret;
810	char *pos, *end;
811
812	pos = buf;
813	end = buf + buflen;
814
815	ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
816			  "ssid=%s\n",
817			  MAC2STR(hapd->own_addr),
818			  wpa_ssid_txt(hapd->conf->ssid.ssid,
819				       hapd->conf->ssid.ssid_len));
820	if (ret < 0 || ret >= end - pos)
821		return pos - buf;
822	pos += ret;
823
824#ifdef CONFIG_WPS
825	ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
826			  hapd->conf->wps_state == 0 ? "disabled" :
827			  (hapd->conf->wps_state == 1 ? "not configured" :
828			   "configured"));
829	if (ret < 0 || ret >= end - pos)
830		return pos - buf;
831	pos += ret;
832
833	if (hapd->conf->wps_state && hapd->conf->wpa &&
834	    hapd->conf->ssid.wpa_passphrase) {
835		ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
836				  hapd->conf->ssid.wpa_passphrase);
837		if (ret < 0 || ret >= end - pos)
838			return pos - buf;
839		pos += ret;
840	}
841
842	if (hapd->conf->wps_state && hapd->conf->wpa &&
843	    hapd->conf->ssid.wpa_psk &&
844	    hapd->conf->ssid.wpa_psk->group) {
845		char hex[PMK_LEN * 2 + 1];
846		wpa_snprintf_hex(hex, sizeof(hex),
847				 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
848		ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
849		if (ret < 0 || ret >= end - pos)
850			return pos - buf;
851		pos += ret;
852	}
853#endif /* CONFIG_WPS */
854
855	if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
856		ret = os_snprintf(pos, end - pos, "key_mgmt=");
857		if (ret < 0 || ret >= end - pos)
858			return pos - buf;
859		pos += ret;
860
861		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
862			ret = os_snprintf(pos, end - pos, "WPA-PSK ");
863			if (ret < 0 || ret >= end - pos)
864				return pos - buf;
865			pos += ret;
866		}
867		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
868			ret = os_snprintf(pos, end - pos, "WPA-EAP ");
869			if (ret < 0 || ret >= end - pos)
870				return pos - buf;
871			pos += ret;
872		}
873#ifdef CONFIG_IEEE80211R
874		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
875			ret = os_snprintf(pos, end - pos, "FT-PSK ");
876			if (ret < 0 || ret >= end - pos)
877				return pos - buf;
878			pos += ret;
879		}
880		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
881			ret = os_snprintf(pos, end - pos, "FT-EAP ");
882			if (ret < 0 || ret >= end - pos)
883				return pos - buf;
884			pos += ret;
885		}
886#endif /* CONFIG_IEEE80211R */
887#ifdef CONFIG_IEEE80211W
888		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
889			ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
890			if (ret < 0 || ret >= end - pos)
891				return pos - buf;
892			pos += ret;
893		}
894		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
895			ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
896			if (ret < 0 || ret >= end - pos)
897				return pos - buf;
898			pos += ret;
899		}
900#endif /* CONFIG_IEEE80211W */
901
902		ret = os_snprintf(pos, end - pos, "\n");
903		if (ret < 0 || ret >= end - pos)
904			return pos - buf;
905		pos += ret;
906	}
907
908	if (hapd->conf->wpa) {
909		ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
910				  wpa_cipher_txt(hapd->conf->wpa_group));
911		if (ret < 0 || ret >= end - pos)
912			return pos - buf;
913		pos += ret;
914	}
915
916	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
917		ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
918		if (ret < 0 || ret >= end - pos)
919			return pos - buf;
920		pos += ret;
921
922		ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
923					" ");
924		if (ret < 0)
925			return pos - buf;
926		pos += ret;
927
928		ret = os_snprintf(pos, end - pos, "\n");
929		if (ret < 0 || ret >= end - pos)
930			return pos - buf;
931		pos += ret;
932	}
933
934	if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
935		ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
936		if (ret < 0 || ret >= end - pos)
937			return pos - buf;
938		pos += ret;
939
940		ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
941					" ");
942		if (ret < 0)
943			return pos - buf;
944		pos += ret;
945
946		ret = os_snprintf(pos, end - pos, "\n");
947		if (ret < 0 || ret >= end - pos)
948			return pos - buf;
949		pos += ret;
950	}
951
952	return pos - buf;
953}
954
955
956static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
957{
958	char *value;
959	int ret = 0;
960
961	value = os_strchr(cmd, ' ');
962	if (value == NULL)
963		return -1;
964	*value++ = '\0';
965
966	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
967	if (0) {
968#ifdef CONFIG_WPS_TESTING
969	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
970		long int val;
971		val = strtol(value, NULL, 0);
972		if (val < 0 || val > 0xff) {
973			ret = -1;
974			wpa_printf(MSG_DEBUG, "WPS: Invalid "
975				   "wps_version_number %ld", val);
976		} else {
977			wps_version_number = val;
978			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
979				   "version %u.%u",
980				   (wps_version_number & 0xf0) >> 4,
981				   wps_version_number & 0x0f);
982			hostapd_wps_update_ie(hapd);
983		}
984	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
985		wps_testing_dummy_cred = atoi(value);
986		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
987			   wps_testing_dummy_cred);
988#endif /* CONFIG_WPS_TESTING */
989#ifdef CONFIG_INTERWORKING
990	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
991		int val = atoi(value);
992		if (val <= 0)
993			ret = -1;
994		else
995			hapd->gas_frag_limit = val;
996#endif /* CONFIG_INTERWORKING */
997	} else {
998		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
999	}
1000
1001	return ret;
1002}
1003
1004
1005static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1006				  char *buf, size_t buflen)
1007{
1008	int res;
1009
1010	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1011
1012	if (os_strcmp(cmd, "version") == 0) {
1013		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
1014		if (res < 0 || (unsigned int) res >= buflen)
1015			return -1;
1016		return res;
1017	}
1018
1019	return -1;
1020}
1021
1022
1023static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1024{
1025	if (hostapd_enable_iface(iface) < 0) {
1026		wpa_printf(MSG_ERROR, "Enabling of interface failed");
1027		return -1;
1028	}
1029	return 0;
1030}
1031
1032
1033static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1034{
1035	if (hostapd_reload_iface(iface) < 0) {
1036		wpa_printf(MSG_ERROR, "Reloading of interface failed");
1037		return -1;
1038	}
1039	return 0;
1040}
1041
1042
1043static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1044{
1045	if (hostapd_disable_iface(iface) < 0) {
1046		wpa_printf(MSG_ERROR, "Disabling of interface failed");
1047		return -1;
1048	}
1049	return 0;
1050}
1051
1052
1053#ifdef CONFIG_TESTING_OPTIONS
1054static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
1055{
1056	union wpa_event_data data;
1057	char *pos, *param;
1058	enum wpa_event_type event;
1059
1060	wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
1061
1062	os_memset(&data, 0, sizeof(data));
1063
1064	param = os_strchr(cmd, ' ');
1065	if (param == NULL)
1066		return -1;
1067	*param++ = '\0';
1068
1069	if (os_strcmp(cmd, "DETECTED") == 0)
1070		event = EVENT_DFS_RADAR_DETECTED;
1071	else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
1072		event = EVENT_DFS_CAC_FINISHED;
1073	else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
1074		event = EVENT_DFS_CAC_ABORTED;
1075	else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
1076		event = EVENT_DFS_NOP_FINISHED;
1077	else {
1078		wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
1079			   cmd);
1080		return -1;
1081	}
1082
1083	pos = os_strstr(param, "freq=");
1084	if (pos)
1085		data.dfs_event.freq = atoi(pos + 5);
1086
1087	pos = os_strstr(param, "ht_enabled=1");
1088	if (pos)
1089		data.dfs_event.ht_enabled = 1;
1090
1091	pos = os_strstr(param, "chan_offset=");
1092	if (pos)
1093		data.dfs_event.chan_offset = atoi(pos + 12);
1094
1095	pos = os_strstr(param, "chan_width=");
1096	if (pos)
1097		data.dfs_event.chan_width = atoi(pos + 11);
1098
1099	pos = os_strstr(param, "cf1=");
1100	if (pos)
1101		data.dfs_event.cf1 = atoi(pos + 4);
1102
1103	pos = os_strstr(param, "cf2=");
1104	if (pos)
1105		data.dfs_event.cf2 = atoi(pos + 4);
1106
1107	wpa_supplicant_event(hapd, event, &data);
1108
1109	return 0;
1110}
1111#endif /* CONFIG_TESTING_OPTIONS */
1112
1113
1114static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
1115				       void *sock_ctx)
1116{
1117	struct hostapd_data *hapd = eloop_ctx;
1118	char buf[256];
1119	int res;
1120	struct sockaddr_un from;
1121	socklen_t fromlen = sizeof(from);
1122	char *reply;
1123	const int reply_size = 4096;
1124	int reply_len;
1125	int level = MSG_DEBUG;
1126
1127	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1128		       (struct sockaddr *) &from, &fromlen);
1129	if (res < 0) {
1130		perror("recvfrom(ctrl_iface)");
1131		return;
1132	}
1133	buf[res] = '\0';
1134	if (os_strcmp(buf, "PING") == 0)
1135		level = MSG_EXCESSIVE;
1136	wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
1137
1138	reply = os_malloc(reply_size);
1139	if (reply == NULL) {
1140		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
1141		       fromlen);
1142		return;
1143	}
1144
1145	os_memcpy(reply, "OK\n", 3);
1146	reply_len = 3;
1147
1148	if (os_strcmp(buf, "PING") == 0) {
1149		os_memcpy(reply, "PONG\n", 5);
1150		reply_len = 5;
1151	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
1152		if (wpa_debug_reopen_file() < 0)
1153			reply_len = -1;
1154	} else if (os_strcmp(buf, "STATUS") == 0) {
1155		reply_len = hostapd_ctrl_iface_status(hapd, reply,
1156						      reply_size);
1157	} else if (os_strcmp(buf, "MIB") == 0) {
1158		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
1159		if (reply_len >= 0) {
1160			res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
1161					  reply_size - reply_len);
1162			if (res < 0)
1163				reply_len = -1;
1164			else
1165				reply_len += res;
1166		}
1167		if (reply_len >= 0) {
1168			res = ieee802_1x_get_mib(hapd, reply + reply_len,
1169						 reply_size - reply_len);
1170			if (res < 0)
1171				reply_len = -1;
1172			else
1173				reply_len += res;
1174		}
1175#ifndef CONFIG_NO_RADIUS
1176		if (reply_len >= 0) {
1177			res = radius_client_get_mib(hapd->radius,
1178						    reply + reply_len,
1179						    reply_size - reply_len);
1180			if (res < 0)
1181				reply_len = -1;
1182			else
1183				reply_len += res;
1184		}
1185#endif /* CONFIG_NO_RADIUS */
1186	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
1187		reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
1188							 reply_size);
1189	} else if (os_strncmp(buf, "STA ", 4) == 0) {
1190		reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
1191						   reply_size);
1192	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
1193		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
1194							reply_size);
1195	} else if (os_strcmp(buf, "ATTACH") == 0) {
1196		if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
1197			reply_len = -1;
1198	} else if (os_strcmp(buf, "DETACH") == 0) {
1199		if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
1200			reply_len = -1;
1201	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
1202		if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
1203						    buf + 6))
1204			reply_len = -1;
1205	} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
1206		if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
1207			reply_len = -1;
1208	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
1209		if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
1210			reply_len = -1;
1211	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
1212		if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
1213			reply_len = -1;
1214#ifdef CONFIG_IEEE80211W
1215#ifdef NEED_AP_MLME
1216	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
1217		if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
1218			reply_len = -1;
1219#endif /* NEED_AP_MLME */
1220#endif /* CONFIG_IEEE80211W */
1221#ifdef CONFIG_WPS
1222	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
1223		if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
1224			reply_len = -1;
1225	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
1226		reply_len = hostapd_ctrl_iface_wps_check_pin(
1227			hapd, buf + 14, reply, reply_size);
1228	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
1229		if (hostapd_wps_button_pushed(hapd, NULL))
1230			reply_len = -1;
1231	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
1232		if (hostapd_wps_cancel(hapd))
1233			reply_len = -1;
1234	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
1235		reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
1236							  reply, reply_size);
1237	} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
1238		if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
1239			reply_len = -1;
1240	} else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
1241		reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
1242							      reply_size);
1243#ifdef CONFIG_WPS_NFC
1244	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
1245		if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
1246			reply_len = -1;
1247	} else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
1248		reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
1249			hapd, buf + 21, reply, reply_size);
1250	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
1251		reply_len = hostapd_ctrl_iface_wps_nfc_token(
1252			hapd, buf + 14, reply, reply_size);
1253	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
1254		reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
1255			hapd, buf + 21, reply, reply_size);
1256	} else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
1257		if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
1258			reply_len = -1;
1259#endif /* CONFIG_WPS_NFC */
1260#endif /* CONFIG_WPS */
1261#ifdef CONFIG_INTERWORKING
1262	} else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
1263		if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
1264			reply_len = -1;
1265	} else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
1266		if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
1267			reply_len = -1;
1268#endif /* CONFIG_INTERWORKING */
1269#ifdef CONFIG_WNM
1270	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
1271		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
1272			reply_len = -1;
1273	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
1274		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
1275			reply_len = -1;
1276#endif /* CONFIG_WNM */
1277	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
1278		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
1279							  reply_size);
1280	} else if (os_strncmp(buf, "SET ", 4) == 0) {
1281		if (hostapd_ctrl_iface_set(hapd, buf + 4))
1282			reply_len = -1;
1283	} else if (os_strncmp(buf, "GET ", 4) == 0) {
1284		reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
1285						   reply_size);
1286	} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
1287		if (hostapd_ctrl_iface_enable(hapd->iface))
1288			reply_len = -1;
1289	} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
1290		if (hostapd_ctrl_iface_reload(hapd->iface))
1291			reply_len = -1;
1292	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
1293		if (hostapd_ctrl_iface_disable(hapd->iface))
1294			reply_len = -1;
1295#ifdef CONFIG_TESTING_OPTIONS
1296	} else if (os_strncmp(buf, "RADAR ", 6) == 0) {
1297		if (hostapd_ctrl_iface_radar(hapd, buf + 6))
1298			reply_len = -1;
1299#endif /* CONFIG_TESTING_OPTIONS */
1300	} else {
1301		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1302		reply_len = 16;
1303	}
1304
1305	if (reply_len < 0) {
1306		os_memcpy(reply, "FAIL\n", 5);
1307		reply_len = 5;
1308	}
1309	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1310	os_free(reply);
1311}
1312
1313
1314static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
1315{
1316	char *buf;
1317	size_t len;
1318
1319	if (hapd->conf->ctrl_interface == NULL)
1320		return NULL;
1321
1322	len = os_strlen(hapd->conf->ctrl_interface) +
1323		os_strlen(hapd->conf->iface) + 2;
1324	buf = os_malloc(len);
1325	if (buf == NULL)
1326		return NULL;
1327
1328	os_snprintf(buf, len, "%s/%s",
1329		    hapd->conf->ctrl_interface, hapd->conf->iface);
1330	buf[len - 1] = '\0';
1331	return buf;
1332}
1333
1334
1335static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
1336				      const char *txt, size_t len)
1337{
1338	struct hostapd_data *hapd = ctx;
1339	if (hapd == NULL)
1340		return;
1341	hostapd_ctrl_iface_send(hapd, level, txt, len);
1342}
1343
1344
1345int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
1346{
1347	struct sockaddr_un addr;
1348	int s = -1;
1349	char *fname = NULL;
1350
1351	if (hapd->ctrl_sock > -1) {
1352		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
1353		return 0;
1354	}
1355
1356	if (hapd->conf->ctrl_interface == NULL)
1357		return 0;
1358
1359	if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1360		if (errno == EEXIST) {
1361			wpa_printf(MSG_DEBUG, "Using existing control "
1362				   "interface directory.");
1363		} else {
1364			perror("mkdir[ctrl_interface]");
1365			goto fail;
1366		}
1367	}
1368
1369	if (hapd->conf->ctrl_interface_gid_set &&
1370	    chown(hapd->conf->ctrl_interface, -1,
1371		  hapd->conf->ctrl_interface_gid) < 0) {
1372		perror("chown[ctrl_interface]");
1373		return -1;
1374	}
1375
1376	if (!hapd->conf->ctrl_interface_gid_set &&
1377	    hapd->iface->interfaces->ctrl_iface_group &&
1378	    chown(hapd->conf->ctrl_interface, -1,
1379		  hapd->iface->interfaces->ctrl_iface_group) < 0) {
1380		perror("chown[ctrl_interface]");
1381		return -1;
1382	}
1383
1384#ifdef ANDROID
1385	/*
1386	 * Android is using umask 0077 which would leave the control interface
1387	 * directory without group access. This breaks things since Wi-Fi
1388	 * framework assumes that this directory can be accessed by other
1389	 * applications in the wifi group. Fix this by adding group access even
1390	 * if umask value would prevent this.
1391	 */
1392	if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1393		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
1394			   strerror(errno));
1395		/* Try to continue anyway */
1396	}
1397#endif /* ANDROID */
1398
1399	if (os_strlen(hapd->conf->ctrl_interface) + 1 +
1400	    os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
1401		goto fail;
1402
1403	s = socket(PF_UNIX, SOCK_DGRAM, 0);
1404	if (s < 0) {
1405		perror("socket(PF_UNIX)");
1406		goto fail;
1407	}
1408
1409	os_memset(&addr, 0, sizeof(addr));
1410#ifdef __FreeBSD__
1411	addr.sun_len = sizeof(addr);
1412#endif /* __FreeBSD__ */
1413	addr.sun_family = AF_UNIX;
1414	fname = hostapd_ctrl_iface_path(hapd);
1415	if (fname == NULL)
1416		goto fail;
1417	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1418	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1419		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1420			   strerror(errno));
1421		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1422			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1423				   " allow connections - assuming it was left"
1424				   "over from forced program termination");
1425			if (unlink(fname) < 0) {
1426				perror("unlink[ctrl_iface]");
1427				wpa_printf(MSG_ERROR, "Could not unlink "
1428					   "existing ctrl_iface socket '%s'",
1429					   fname);
1430				goto fail;
1431			}
1432			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1433			    0) {
1434				perror("hostapd-ctrl-iface: bind(PF_UNIX)");
1435				goto fail;
1436			}
1437			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1438				   "ctrl_iface socket '%s'", fname);
1439		} else {
1440			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1441				   "be in use - cannot override it");
1442			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1443				   "not used anymore", fname);
1444			os_free(fname);
1445			fname = NULL;
1446			goto fail;
1447		}
1448	}
1449
1450	if (hapd->conf->ctrl_interface_gid_set &&
1451	    chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
1452		perror("chown[ctrl_interface/ifname]");
1453		goto fail;
1454	}
1455
1456	if (!hapd->conf->ctrl_interface_gid_set &&
1457	    hapd->iface->interfaces->ctrl_iface_group &&
1458	    chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
1459		perror("chown[ctrl_interface/ifname]");
1460		goto fail;
1461	}
1462
1463	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1464		perror("chmod[ctrl_interface/ifname]");
1465		goto fail;
1466	}
1467	os_free(fname);
1468
1469	hapd->ctrl_sock = s;
1470	eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
1471				 NULL);
1472	hapd->msg_ctx = hapd;
1473	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
1474
1475	return 0;
1476
1477fail:
1478	if (s >= 0)
1479		close(s);
1480	if (fname) {
1481		unlink(fname);
1482		os_free(fname);
1483	}
1484	return -1;
1485}
1486
1487
1488void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
1489{
1490	struct wpa_ctrl_dst *dst, *prev;
1491
1492	if (hapd->ctrl_sock > -1) {
1493		char *fname;
1494		eloop_unregister_read_sock(hapd->ctrl_sock);
1495		close(hapd->ctrl_sock);
1496		hapd->ctrl_sock = -1;
1497		fname = hostapd_ctrl_iface_path(hapd);
1498		if (fname)
1499			unlink(fname);
1500		os_free(fname);
1501
1502		if (hapd->conf->ctrl_interface &&
1503		    rmdir(hapd->conf->ctrl_interface) < 0) {
1504			if (errno == ENOTEMPTY) {
1505				wpa_printf(MSG_DEBUG, "Control interface "
1506					   "directory not empty - leaving it "
1507					   "behind");
1508			} else {
1509				wpa_printf(MSG_ERROR,
1510					   "rmdir[ctrl_interface=%s]: %s",
1511					   hapd->conf->ctrl_interface,
1512					   strerror(errno));
1513			}
1514		}
1515	}
1516
1517	dst = hapd->ctrl_dst;
1518	while (dst) {
1519		prev = dst;
1520		dst = dst->next;
1521		os_free(prev);
1522	}
1523}
1524
1525
1526static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
1527				  char *buf)
1528{
1529	if (hostapd_add_iface(interfaces, buf) < 0) {
1530		wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
1531		return -1;
1532	}
1533	return 0;
1534}
1535
1536
1537static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
1538				     char *buf)
1539{
1540	if (hostapd_remove_iface(interfaces, buf) < 0) {
1541		wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
1542		return -1;
1543	}
1544	return 0;
1545}
1546
1547
1548static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
1549					      void *sock_ctx)
1550{
1551	void *interfaces = eloop_ctx;
1552	char buf[256];
1553	int res;
1554	struct sockaddr_un from;
1555	socklen_t fromlen = sizeof(from);
1556	char reply[24];
1557	int reply_len;
1558
1559	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1560		       (struct sockaddr *) &from, &fromlen);
1561	if (res < 0) {
1562		perror("recvfrom(ctrl_iface)");
1563		return;
1564	}
1565	buf[res] = '\0';
1566	wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
1567
1568	os_memcpy(reply, "OK\n", 3);
1569	reply_len = 3;
1570
1571	if (os_strcmp(buf, "PING") == 0) {
1572		os_memcpy(reply, "PONG\n", 5);
1573		reply_len = 5;
1574	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
1575		if (wpa_debug_reopen_file() < 0)
1576			reply_len = -1;
1577	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
1578		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
1579			reply_len = -1;
1580	} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
1581		if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
1582			reply_len = -1;
1583	} else {
1584		wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
1585			   "ignored");
1586		reply_len = -1;
1587	}
1588
1589	if (reply_len < 0) {
1590		os_memcpy(reply, "FAIL\n", 5);
1591		reply_len = 5;
1592	}
1593
1594	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1595}
1596
1597
1598static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
1599{
1600	char *buf;
1601	size_t len;
1602
1603	if (interface->global_iface_path == NULL)
1604		return NULL;
1605
1606	len = os_strlen(interface->global_iface_path) +
1607		os_strlen(interface->global_iface_name) + 2;
1608	buf = os_malloc(len);
1609	if (buf == NULL)
1610		return NULL;
1611
1612	os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
1613		    interface->global_iface_name);
1614	buf[len - 1] = '\0';
1615	return buf;
1616}
1617
1618
1619int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
1620{
1621	struct sockaddr_un addr;
1622	int s = -1;
1623	char *fname = NULL;
1624
1625	if (interface->global_iface_path == NULL) {
1626		wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
1627		return 0;
1628	}
1629
1630	if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
1631		if (errno == EEXIST) {
1632			wpa_printf(MSG_DEBUG, "Using existing control "
1633				   "interface directory.");
1634		} else {
1635			perror("mkdir[ctrl_interface]");
1636			goto fail;
1637		}
1638	} else if (interface->ctrl_iface_group &&
1639		   chown(interface->global_iface_path, -1,
1640			 interface->ctrl_iface_group) < 0) {
1641		perror("chown[ctrl_interface]");
1642		goto fail;
1643	}
1644
1645	if (os_strlen(interface->global_iface_path) + 1 +
1646	    os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
1647		goto fail;
1648
1649	s = socket(PF_UNIX, SOCK_DGRAM, 0);
1650	if (s < 0) {
1651		perror("socket(PF_UNIX)");
1652		goto fail;
1653	}
1654
1655	os_memset(&addr, 0, sizeof(addr));
1656#ifdef __FreeBSD__
1657	addr.sun_len = sizeof(addr);
1658#endif /* __FreeBSD__ */
1659	addr.sun_family = AF_UNIX;
1660	fname = hostapd_global_ctrl_iface_path(interface);
1661	if (fname == NULL)
1662		goto fail;
1663	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1664	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1665		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1666			   strerror(errno));
1667		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1668			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1669				   " allow connections - assuming it was left"
1670				   "over from forced program termination");
1671			if (unlink(fname) < 0) {
1672				perror("unlink[ctrl_iface]");
1673				wpa_printf(MSG_ERROR, "Could not unlink "
1674					   "existing ctrl_iface socket '%s'",
1675					   fname);
1676				goto fail;
1677			}
1678			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1679			    0) {
1680				perror("bind(PF_UNIX)");
1681				goto fail;
1682			}
1683			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1684				   "ctrl_iface socket '%s'", fname);
1685		} else {
1686			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1687				   "be in use - cannot override it");
1688			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1689				   "not used anymore", fname);
1690			os_free(fname);
1691			fname = NULL;
1692			goto fail;
1693		}
1694	}
1695
1696	if (interface->ctrl_iface_group &&
1697	    chown(fname, -1, interface->ctrl_iface_group) < 0) {
1698		perror("chown[ctrl_interface]");
1699		goto fail;
1700	}
1701
1702	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1703		perror("chmod[ctrl_interface/ifname]");
1704		goto fail;
1705	}
1706	os_free(fname);
1707
1708	interface->global_ctrl_sock = s;
1709	eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
1710				 interface, NULL);
1711
1712	return 0;
1713
1714fail:
1715	if (s >= 0)
1716		close(s);
1717	if (fname) {
1718		unlink(fname);
1719		os_free(fname);
1720	}
1721	return -1;
1722}
1723
1724
1725void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
1726{
1727	char *fname = NULL;
1728
1729	if (interfaces->global_ctrl_sock > -1) {
1730		eloop_unregister_read_sock(interfaces->global_ctrl_sock);
1731		close(interfaces->global_ctrl_sock);
1732		interfaces->global_ctrl_sock = -1;
1733		fname = hostapd_global_ctrl_iface_path(interfaces);
1734		if (fname) {
1735			unlink(fname);
1736			os_free(fname);
1737		}
1738
1739		if (interfaces->global_iface_path &&
1740		    rmdir(interfaces->global_iface_path) < 0) {
1741			if (errno == ENOTEMPTY) {
1742				wpa_printf(MSG_DEBUG, "Control interface "
1743					   "directory not empty - leaving it "
1744					   "behind");
1745			} else {
1746				wpa_printf(MSG_ERROR,
1747					   "rmdir[ctrl_interface=%s]: %s",
1748					   interfaces->global_iface_path,
1749					   strerror(errno));
1750			}
1751		}
1752		os_free(interfaces->global_iface_path);
1753		interfaces->global_iface_path = NULL;
1754	}
1755}
1756
1757
1758static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1759				    const char *buf, size_t len)
1760{
1761	struct wpa_ctrl_dst *dst, *next;
1762	struct msghdr msg;
1763	int idx;
1764	struct iovec io[2];
1765	char levelstr[10];
1766
1767	dst = hapd->ctrl_dst;
1768	if (hapd->ctrl_sock < 0 || dst == NULL)
1769		return;
1770
1771	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1772	io[0].iov_base = levelstr;
1773	io[0].iov_len = os_strlen(levelstr);
1774	io[1].iov_base = (char *) buf;
1775	io[1].iov_len = len;
1776	os_memset(&msg, 0, sizeof(msg));
1777	msg.msg_iov = io;
1778	msg.msg_iovlen = 2;
1779
1780	idx = 0;
1781	while (dst) {
1782		next = dst->next;
1783		if (level >= dst->debug_level) {
1784			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1785				    (u8 *) dst->addr.sun_path, dst->addrlen -
1786				    offsetof(struct sockaddr_un, sun_path));
1787			msg.msg_name = &dst->addr;
1788			msg.msg_namelen = dst->addrlen;
1789			if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1790				int _errno = errno;
1791				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1792					   "%d - %s",
1793					   idx, errno, strerror(errno));
1794				dst->errors++;
1795				if (dst->errors > 10 || _errno == ENOENT) {
1796					hostapd_ctrl_iface_detach(
1797						hapd, &dst->addr,
1798						dst->addrlen);
1799				}
1800			} else
1801				dst->errors = 0;
1802		}
1803		idx++;
1804		dst = next;
1805	}
1806}
1807
1808#endif /* CONFIG_NATIVE_WINDOWS */
1809