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