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