xref: /netbsd-src/external/bsd/wpa/dist/src/common/ctrl_iface_common.c (revision 0a73ee0a32b4208ab171f89f408b38fd4c664291)
136ebd06eSchristos /*
236ebd06eSchristos  * Common hostapd/wpa_supplicant ctrl iface code.
336ebd06eSchristos  * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
436ebd06eSchristos  * Copyright (c) 2015, Qualcomm Atheros, Inc.
536ebd06eSchristos  *
636ebd06eSchristos  * This software may be distributed under the terms of the BSD license.
736ebd06eSchristos  * See README for more details.
836ebd06eSchristos  */
936ebd06eSchristos 
1036ebd06eSchristos #include "utils/includes.h"
1136ebd06eSchristos #include <netdb.h>
1236ebd06eSchristos #include <sys/un.h>
1336ebd06eSchristos 
1436ebd06eSchristos #include "utils/common.h"
1536ebd06eSchristos #include "ctrl_iface_common.h"
1636ebd06eSchristos 
sockaddr_compare(struct sockaddr_storage * a,socklen_t a_len,struct sockaddr_storage * b,socklen_t b_len)1736ebd06eSchristos static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
1836ebd06eSchristos 			    struct sockaddr_storage *b, socklen_t b_len)
1936ebd06eSchristos {
2036ebd06eSchristos 	if (a->ss_family != b->ss_family)
2136ebd06eSchristos 		return 1;
2236ebd06eSchristos 
2336ebd06eSchristos 	switch (a->ss_family) {
2436ebd06eSchristos #ifdef CONFIG_CTRL_IFACE_UDP
2536ebd06eSchristos 	case AF_INET:
2636ebd06eSchristos 	{
2736ebd06eSchristos 		struct sockaddr_in *in_a, *in_b;
2836ebd06eSchristos 
2936ebd06eSchristos 		in_a = (struct sockaddr_in *) a;
3036ebd06eSchristos 		in_b = (struct sockaddr_in *) b;
3136ebd06eSchristos 
3236ebd06eSchristos 		if (in_a->sin_port != in_b->sin_port)
3336ebd06eSchristos 			return 1;
3436ebd06eSchristos 		if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
3536ebd06eSchristos 			return 1;
3636ebd06eSchristos 		break;
3736ebd06eSchristos 	}
3836ebd06eSchristos 	case AF_INET6:
3936ebd06eSchristos 	{
4036ebd06eSchristos 		struct sockaddr_in6 *in6_a, *in6_b;
4136ebd06eSchristos 
4236ebd06eSchristos 		in6_a = (struct sockaddr_in6 *) a;
4336ebd06eSchristos 		in6_b = (struct sockaddr_in6 *) b;
4436ebd06eSchristos 
4536ebd06eSchristos 		if (in6_a->sin6_port != in6_b->sin6_port)
4636ebd06eSchristos 			return 1;
4736ebd06eSchristos 		if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
4836ebd06eSchristos 			      sizeof(in6_a->sin6_addr)) != 0)
4936ebd06eSchristos 			return 1;
5036ebd06eSchristos 		break;
5136ebd06eSchristos 	}
5236ebd06eSchristos #endif /* CONFIG_CTRL_IFACE_UDP */
5336ebd06eSchristos #ifdef CONFIG_CTRL_IFACE_UNIX
5436ebd06eSchristos 	case AF_UNIX:
5536ebd06eSchristos 	{
5636ebd06eSchristos 		struct sockaddr_un *u_a, *u_b;
5736ebd06eSchristos 
5836ebd06eSchristos 		u_a = (struct sockaddr_un *) a;
5936ebd06eSchristos 		u_b = (struct sockaddr_un *) b;
6036ebd06eSchristos 
6136ebd06eSchristos 		if (a_len != b_len ||
6236ebd06eSchristos 		    os_memcmp(u_a->sun_path, u_b->sun_path,
6336ebd06eSchristos 			      a_len - offsetof(struct sockaddr_un, sun_path))
6436ebd06eSchristos 		    != 0)
6536ebd06eSchristos 			return 1;
6636ebd06eSchristos 		break;
6736ebd06eSchristos 	}
6836ebd06eSchristos #endif /* CONFIG_CTRL_IFACE_UNIX */
6936ebd06eSchristos 	default:
7036ebd06eSchristos 		return 1;
7136ebd06eSchristos 	}
7236ebd06eSchristos 
7336ebd06eSchristos 	return 0;
7436ebd06eSchristos }
7536ebd06eSchristos 
7636ebd06eSchristos 
sockaddr_print(int level,const char * msg,struct sockaddr_storage * sock,socklen_t socklen)7736ebd06eSchristos void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
7836ebd06eSchristos 		    socklen_t socklen)
7936ebd06eSchristos {
8036ebd06eSchristos 	switch (sock->ss_family) {
8136ebd06eSchristos #ifdef CONFIG_CTRL_IFACE_UDP
8236ebd06eSchristos 	case AF_INET:
8336ebd06eSchristos 	case AF_INET6:
8436ebd06eSchristos 	{
8536ebd06eSchristos 		char host[NI_MAXHOST] = { 0 };
8636ebd06eSchristos 		char service[NI_MAXSERV] = { 0 };
8736ebd06eSchristos 
8836ebd06eSchristos 		getnameinfo((struct sockaddr *) sock, socklen,
8936ebd06eSchristos 			    host, sizeof(host),
9036ebd06eSchristos 			    service, sizeof(service),
9136ebd06eSchristos 			    NI_NUMERICHOST);
9236ebd06eSchristos 
9336ebd06eSchristos 		wpa_printf(level, "%s %s:%s", msg, host, service);
9436ebd06eSchristos 		break;
9536ebd06eSchristos 	}
9636ebd06eSchristos #endif /* CONFIG_CTRL_IFACE_UDP */
9736ebd06eSchristos #ifdef CONFIG_CTRL_IFACE_UNIX
9836ebd06eSchristos 	case AF_UNIX:
9936ebd06eSchristos 	{
10036ebd06eSchristos 		char addr_txt[200];
10136ebd06eSchristos 
10236ebd06eSchristos 		printf_encode(addr_txt, sizeof(addr_txt),
10336ebd06eSchristos 			      (u8 *) ((struct sockaddr_un *) sock)->sun_path,
10436ebd06eSchristos 			      socklen - offsetof(struct sockaddr_un, sun_path));
10536ebd06eSchristos 		wpa_printf(level, "%s %s", msg, addr_txt);
10636ebd06eSchristos 		break;
10736ebd06eSchristos 	}
10836ebd06eSchristos #endif /* CONFIG_CTRL_IFACE_UNIX */
10936ebd06eSchristos 	default:
11036ebd06eSchristos 		wpa_printf(level, "%s", msg);
11136ebd06eSchristos 		break;
11236ebd06eSchristos 	}
11336ebd06eSchristos }
11436ebd06eSchristos 
11536ebd06eSchristos 
ctrl_set_events(struct wpa_ctrl_dst * dst,const char * input)116*0a73ee0aSchristos static int ctrl_set_events(struct wpa_ctrl_dst *dst, const char *input)
117*0a73ee0aSchristos {
118*0a73ee0aSchristos 	const char *value;
119*0a73ee0aSchristos 	int val;
120*0a73ee0aSchristos 
121*0a73ee0aSchristos 	if (!input)
122*0a73ee0aSchristos 		return 0;
123*0a73ee0aSchristos 
124*0a73ee0aSchristos 	value = os_strchr(input, '=');
125*0a73ee0aSchristos 	if (!value)
126*0a73ee0aSchristos 		return -1;
127*0a73ee0aSchristos 	value++;
128*0a73ee0aSchristos 	val = atoi(value);
129*0a73ee0aSchristos 	if (val < 0 || val > 1)
130*0a73ee0aSchristos 		return -1;
131*0a73ee0aSchristos 
132*0a73ee0aSchristos 	if (str_starts(input, "probe_rx_events=")) {
133*0a73ee0aSchristos 		if (val)
134*0a73ee0aSchristos 			dst->events |= WPA_EVENT_RX_PROBE_REQUEST;
135*0a73ee0aSchristos 		else
136*0a73ee0aSchristos 			dst->events &= ~WPA_EVENT_RX_PROBE_REQUEST;
137*0a73ee0aSchristos 	}
138*0a73ee0aSchristos 
139*0a73ee0aSchristos 	return 0;
140*0a73ee0aSchristos }
141*0a73ee0aSchristos 
142*0a73ee0aSchristos 
ctrl_iface_attach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen,const char * input)14336ebd06eSchristos int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
144*0a73ee0aSchristos 		      socklen_t fromlen, const char *input)
14536ebd06eSchristos {
14636ebd06eSchristos 	struct wpa_ctrl_dst *dst;
14736ebd06eSchristos 
148*0a73ee0aSchristos 	/* Update event registration if already attached */
149*0a73ee0aSchristos 	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
150*0a73ee0aSchristos 		if (!sockaddr_compare(from, fromlen,
151*0a73ee0aSchristos 				      &dst->addr, dst->addrlen))
152*0a73ee0aSchristos 			return ctrl_set_events(dst, input);
153*0a73ee0aSchristos 	}
154*0a73ee0aSchristos 
155*0a73ee0aSchristos 	/* New attachment */
15636ebd06eSchristos 	dst = os_zalloc(sizeof(*dst));
15736ebd06eSchristos 	if (dst == NULL)
15836ebd06eSchristos 		return -1;
15936ebd06eSchristos 	os_memcpy(&dst->addr, from, fromlen);
16036ebd06eSchristos 	dst->addrlen = fromlen;
16136ebd06eSchristos 	dst->debug_level = MSG_INFO;
162*0a73ee0aSchristos 	ctrl_set_events(dst, input);
16336ebd06eSchristos 	dl_list_add(ctrl_dst, &dst->list);
16436ebd06eSchristos 
16536ebd06eSchristos 	sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
16636ebd06eSchristos 	return 0;
16736ebd06eSchristos }
16836ebd06eSchristos 
16936ebd06eSchristos 
ctrl_iface_detach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen)17036ebd06eSchristos int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
17136ebd06eSchristos 		      socklen_t fromlen)
17236ebd06eSchristos {
17336ebd06eSchristos 	struct wpa_ctrl_dst *dst;
17436ebd06eSchristos 
17536ebd06eSchristos 	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
17636ebd06eSchristos 		if (!sockaddr_compare(from, fromlen,
17736ebd06eSchristos 				      &dst->addr, dst->addrlen)) {
17836ebd06eSchristos 			sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
17936ebd06eSchristos 				       from, fromlen);
18036ebd06eSchristos 			dl_list_del(&dst->list);
18136ebd06eSchristos 			os_free(dst);
18236ebd06eSchristos 			return 0;
18336ebd06eSchristos 		}
18436ebd06eSchristos 	}
18536ebd06eSchristos 
18636ebd06eSchristos 	return -1;
18736ebd06eSchristos }
18836ebd06eSchristos 
18936ebd06eSchristos 
ctrl_iface_level(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen,const char * level)19036ebd06eSchristos int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
19136ebd06eSchristos 		     socklen_t fromlen, const char *level)
19236ebd06eSchristos {
19336ebd06eSchristos 	struct wpa_ctrl_dst *dst;
19436ebd06eSchristos 
19536ebd06eSchristos 	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
19636ebd06eSchristos 
19736ebd06eSchristos 	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
19836ebd06eSchristos 		if (!sockaddr_compare(from, fromlen,
19936ebd06eSchristos 				      &dst->addr, dst->addrlen)) {
20036ebd06eSchristos 			sockaddr_print(MSG_DEBUG,
20136ebd06eSchristos 				       "CTRL_IFACE changed monitor level",
20236ebd06eSchristos 				       from, fromlen);
20336ebd06eSchristos 			dst->debug_level = atoi(level);
20436ebd06eSchristos 			return 0;
20536ebd06eSchristos 		}
20636ebd06eSchristos 	}
20736ebd06eSchristos 
20836ebd06eSchristos 	return -1;
20936ebd06eSchristos }
210