1780fb4a2SCy Schubert /*
2780fb4a2SCy Schubert * Common hostapd/wpa_supplicant ctrl iface code.
3780fb4a2SCy Schubert * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4780fb4a2SCy Schubert * Copyright (c) 2015, Qualcomm Atheros, Inc.
5780fb4a2SCy Schubert *
6780fb4a2SCy Schubert * This software may be distributed under the terms of the BSD license.
7780fb4a2SCy Schubert * See README for more details.
8780fb4a2SCy Schubert */
9780fb4a2SCy Schubert
10780fb4a2SCy Schubert #include "utils/includes.h"
11780fb4a2SCy Schubert #include <netdb.h>
12780fb4a2SCy Schubert #include <sys/un.h>
13780fb4a2SCy Schubert
14780fb4a2SCy Schubert #include "utils/common.h"
15780fb4a2SCy Schubert #include "ctrl_iface_common.h"
16780fb4a2SCy Schubert
sockaddr_compare(struct sockaddr_storage * a,socklen_t a_len,struct sockaddr_storage * b,socklen_t b_len)17780fb4a2SCy Schubert static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
18780fb4a2SCy Schubert struct sockaddr_storage *b, socklen_t b_len)
19780fb4a2SCy Schubert {
20780fb4a2SCy Schubert if (a->ss_family != b->ss_family)
21780fb4a2SCy Schubert return 1;
22780fb4a2SCy Schubert
23780fb4a2SCy Schubert switch (a->ss_family) {
24780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
25780fb4a2SCy Schubert case AF_INET:
26780fb4a2SCy Schubert {
27780fb4a2SCy Schubert struct sockaddr_in *in_a, *in_b;
28780fb4a2SCy Schubert
29780fb4a2SCy Schubert in_a = (struct sockaddr_in *) a;
30780fb4a2SCy Schubert in_b = (struct sockaddr_in *) b;
31780fb4a2SCy Schubert
32780fb4a2SCy Schubert if (in_a->sin_port != in_b->sin_port)
33780fb4a2SCy Schubert return 1;
34780fb4a2SCy Schubert if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
35780fb4a2SCy Schubert return 1;
36780fb4a2SCy Schubert break;
37780fb4a2SCy Schubert }
38780fb4a2SCy Schubert case AF_INET6:
39780fb4a2SCy Schubert {
40780fb4a2SCy Schubert struct sockaddr_in6 *in6_a, *in6_b;
41780fb4a2SCy Schubert
42780fb4a2SCy Schubert in6_a = (struct sockaddr_in6 *) a;
43780fb4a2SCy Schubert in6_b = (struct sockaddr_in6 *) b;
44780fb4a2SCy Schubert
45780fb4a2SCy Schubert if (in6_a->sin6_port != in6_b->sin6_port)
46780fb4a2SCy Schubert return 1;
47780fb4a2SCy Schubert if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
48780fb4a2SCy Schubert sizeof(in6_a->sin6_addr)) != 0)
49780fb4a2SCy Schubert return 1;
50780fb4a2SCy Schubert break;
51780fb4a2SCy Schubert }
52780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
53780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UNIX
54780fb4a2SCy Schubert case AF_UNIX:
55780fb4a2SCy Schubert {
56780fb4a2SCy Schubert struct sockaddr_un *u_a, *u_b;
57780fb4a2SCy Schubert
58780fb4a2SCy Schubert u_a = (struct sockaddr_un *) a;
59780fb4a2SCy Schubert u_b = (struct sockaddr_un *) b;
60780fb4a2SCy Schubert
61780fb4a2SCy Schubert if (a_len != b_len ||
62780fb4a2SCy Schubert os_memcmp(u_a->sun_path, u_b->sun_path,
63780fb4a2SCy Schubert a_len - offsetof(struct sockaddr_un, sun_path))
64780fb4a2SCy Schubert != 0)
65780fb4a2SCy Schubert return 1;
66780fb4a2SCy Schubert break;
67780fb4a2SCy Schubert }
68780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UNIX */
69780fb4a2SCy Schubert default:
70780fb4a2SCy Schubert return 1;
71780fb4a2SCy Schubert }
72780fb4a2SCy Schubert
73780fb4a2SCy Schubert return 0;
74780fb4a2SCy Schubert }
75780fb4a2SCy Schubert
76780fb4a2SCy Schubert
sockaddr_print(int level,const char * msg,struct sockaddr_storage * sock,socklen_t socklen)77780fb4a2SCy Schubert void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
78780fb4a2SCy Schubert socklen_t socklen)
79780fb4a2SCy Schubert {
80780fb4a2SCy Schubert switch (sock->ss_family) {
81780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
82780fb4a2SCy Schubert case AF_INET:
83780fb4a2SCy Schubert case AF_INET6:
84780fb4a2SCy Schubert {
85780fb4a2SCy Schubert char host[NI_MAXHOST] = { 0 };
86780fb4a2SCy Schubert char service[NI_MAXSERV] = { 0 };
87780fb4a2SCy Schubert
88780fb4a2SCy Schubert getnameinfo((struct sockaddr *) sock, socklen,
89780fb4a2SCy Schubert host, sizeof(host),
90780fb4a2SCy Schubert service, sizeof(service),
91780fb4a2SCy Schubert NI_NUMERICHOST);
92780fb4a2SCy Schubert
93780fb4a2SCy Schubert wpa_printf(level, "%s %s:%s", msg, host, service);
94780fb4a2SCy Schubert break;
95780fb4a2SCy Schubert }
96780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
97780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UNIX
98780fb4a2SCy Schubert case AF_UNIX:
99780fb4a2SCy Schubert {
100780fb4a2SCy Schubert char addr_txt[200];
101780fb4a2SCy Schubert
102780fb4a2SCy Schubert printf_encode(addr_txt, sizeof(addr_txt),
103780fb4a2SCy Schubert (u8 *) ((struct sockaddr_un *) sock)->sun_path,
104780fb4a2SCy Schubert socklen - offsetof(struct sockaddr_un, sun_path));
105780fb4a2SCy Schubert wpa_printf(level, "%s %s", msg, addr_txt);
106780fb4a2SCy Schubert break;
107780fb4a2SCy Schubert }
108780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UNIX */
109780fb4a2SCy Schubert default:
110780fb4a2SCy Schubert wpa_printf(level, "%s", msg);
111780fb4a2SCy Schubert break;
112780fb4a2SCy Schubert }
113780fb4a2SCy Schubert }
114780fb4a2SCy Schubert
115780fb4a2SCy Schubert
ctrl_set_events(struct wpa_ctrl_dst * dst,const char * input)116*85732ac8SCy Schubert static int ctrl_set_events(struct wpa_ctrl_dst *dst, const char *input)
117*85732ac8SCy Schubert {
118*85732ac8SCy Schubert const char *value;
119*85732ac8SCy Schubert int val;
120*85732ac8SCy Schubert
121*85732ac8SCy Schubert if (!input)
122*85732ac8SCy Schubert return 0;
123*85732ac8SCy Schubert
124*85732ac8SCy Schubert value = os_strchr(input, '=');
125*85732ac8SCy Schubert if (!value)
126*85732ac8SCy Schubert return -1;
127*85732ac8SCy Schubert value++;
128*85732ac8SCy Schubert val = atoi(value);
129*85732ac8SCy Schubert if (val < 0 || val > 1)
130*85732ac8SCy Schubert return -1;
131*85732ac8SCy Schubert
132*85732ac8SCy Schubert if (str_starts(input, "probe_rx_events=")) {
133*85732ac8SCy Schubert if (val)
134*85732ac8SCy Schubert dst->events |= WPA_EVENT_RX_PROBE_REQUEST;
135*85732ac8SCy Schubert else
136*85732ac8SCy Schubert dst->events &= ~WPA_EVENT_RX_PROBE_REQUEST;
137*85732ac8SCy Schubert }
138*85732ac8SCy Schubert
139*85732ac8SCy Schubert return 0;
140*85732ac8SCy Schubert }
141*85732ac8SCy Schubert
142*85732ac8SCy Schubert
ctrl_iface_attach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen,const char * input)143780fb4a2SCy Schubert int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
144*85732ac8SCy Schubert socklen_t fromlen, const char *input)
145780fb4a2SCy Schubert {
146780fb4a2SCy Schubert struct wpa_ctrl_dst *dst;
147780fb4a2SCy Schubert
148*85732ac8SCy Schubert /* Update event registration if already attached */
149*85732ac8SCy Schubert dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
150*85732ac8SCy Schubert if (!sockaddr_compare(from, fromlen,
151*85732ac8SCy Schubert &dst->addr, dst->addrlen))
152*85732ac8SCy Schubert return ctrl_set_events(dst, input);
153*85732ac8SCy Schubert }
154*85732ac8SCy Schubert
155*85732ac8SCy Schubert /* New attachment */
156780fb4a2SCy Schubert dst = os_zalloc(sizeof(*dst));
157780fb4a2SCy Schubert if (dst == NULL)
158780fb4a2SCy Schubert return -1;
159780fb4a2SCy Schubert os_memcpy(&dst->addr, from, fromlen);
160780fb4a2SCy Schubert dst->addrlen = fromlen;
161780fb4a2SCy Schubert dst->debug_level = MSG_INFO;
162*85732ac8SCy Schubert ctrl_set_events(dst, input);
163780fb4a2SCy Schubert dl_list_add(ctrl_dst, &dst->list);
164780fb4a2SCy Schubert
165780fb4a2SCy Schubert sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
166780fb4a2SCy Schubert return 0;
167780fb4a2SCy Schubert }
168780fb4a2SCy Schubert
169780fb4a2SCy Schubert
ctrl_iface_detach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen)170780fb4a2SCy Schubert int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
171780fb4a2SCy Schubert socklen_t fromlen)
172780fb4a2SCy Schubert {
173780fb4a2SCy Schubert struct wpa_ctrl_dst *dst;
174780fb4a2SCy Schubert
175780fb4a2SCy Schubert dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
176780fb4a2SCy Schubert if (!sockaddr_compare(from, fromlen,
177780fb4a2SCy Schubert &dst->addr, dst->addrlen)) {
178780fb4a2SCy Schubert sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
179780fb4a2SCy Schubert from, fromlen);
180780fb4a2SCy Schubert dl_list_del(&dst->list);
181780fb4a2SCy Schubert os_free(dst);
182780fb4a2SCy Schubert return 0;
183780fb4a2SCy Schubert }
184780fb4a2SCy Schubert }
185780fb4a2SCy Schubert
186780fb4a2SCy Schubert return -1;
187780fb4a2SCy Schubert }
188780fb4a2SCy Schubert
189780fb4a2SCy Schubert
ctrl_iface_level(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen,const char * level)190780fb4a2SCy Schubert int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
191780fb4a2SCy Schubert socklen_t fromlen, const char *level)
192780fb4a2SCy Schubert {
193780fb4a2SCy Schubert struct wpa_ctrl_dst *dst;
194780fb4a2SCy Schubert
195780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
196780fb4a2SCy Schubert
197780fb4a2SCy Schubert dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
198780fb4a2SCy Schubert if (!sockaddr_compare(from, fromlen,
199780fb4a2SCy Schubert &dst->addr, dst->addrlen)) {
200780fb4a2SCy Schubert sockaddr_print(MSG_DEBUG,
201780fb4a2SCy Schubert "CTRL_IFACE changed monitor level",
202780fb4a2SCy Schubert from, fromlen);
203780fb4a2SCy Schubert dst->debug_level = atoi(level);
204780fb4a2SCy Schubert return 0;
205780fb4a2SCy Schubert }
206780fb4a2SCy Schubert }
207780fb4a2SCy Schubert
208780fb4a2SCy Schubert return -1;
209780fb4a2SCy Schubert }
210