Home | History | Annotate | Download | only in common
      1 /*
      2  * Common hostapd/wpa_supplicant ctrl iface code.
      3  * Copyright (c) 2002-2013, Jouni Malinen <j (at) w1.fi>
      4  * Copyright (c) 2015, Qualcomm Atheros, Inc.
      5  *
      6  * This software may be distributed under the terms of the BSD license.
      7  * See README for more details.
      8  */
      9 
     10 #include "utils/includes.h"
     11 #include <netdb.h>
     12 #include <sys/un.h>
     13 
     14 #include "utils/common.h"
     15 #include "ctrl_iface_common.h"
     16 
     17 static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
     18 			    struct sockaddr_storage *b, socklen_t b_len)
     19 {
     20 	if (a->ss_family != b->ss_family)
     21 		return 1;
     22 
     23 	switch (a->ss_family) {
     24 #ifdef CONFIG_CTRL_IFACE_UDP
     25 	case AF_INET:
     26 	{
     27 		struct sockaddr_in *in_a, *in_b;
     28 
     29 		in_a = (struct sockaddr_in *) a;
     30 		in_b = (struct sockaddr_in *) b;
     31 
     32 		if (in_a->sin_port != in_b->sin_port)
     33 			return 1;
     34 		if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
     35 			return 1;
     36 		break;
     37 	}
     38 	case AF_INET6:
     39 	{
     40 		struct sockaddr_in6 *in6_a, *in6_b;
     41 
     42 		in6_a = (struct sockaddr_in6 *) a;
     43 		in6_b = (struct sockaddr_in6 *) b;
     44 
     45 		if (in6_a->sin6_port != in6_b->sin6_port)
     46 			return 1;
     47 		if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
     48 			      sizeof(in6_a->sin6_addr)) != 0)
     49 			return 1;
     50 		break;
     51 	}
     52 #endif /* CONFIG_CTRL_IFACE_UDP */
     53 #ifdef CONFIG_CTRL_IFACE_UNIX
     54 	case AF_UNIX:
     55 	{
     56 		struct sockaddr_un *u_a, *u_b;
     57 
     58 		u_a = (struct sockaddr_un *) a;
     59 		u_b = (struct sockaddr_un *) b;
     60 
     61 		if (a_len != b_len ||
     62 		    os_memcmp(u_a->sun_path, u_b->sun_path,
     63 			      a_len - offsetof(struct sockaddr_un, sun_path))
     64 		    != 0)
     65 			return 1;
     66 		break;
     67 	}
     68 #endif /* CONFIG_CTRL_IFACE_UNIX */
     69 	default:
     70 		return 1;
     71 	}
     72 
     73 	return 0;
     74 }
     75 
     76 
     77 void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
     78 		    socklen_t socklen)
     79 {
     80 	switch (sock->ss_family) {
     81 #ifdef CONFIG_CTRL_IFACE_UDP
     82 	case AF_INET:
     83 	case AF_INET6:
     84 	{
     85 		char host[NI_MAXHOST] = { 0 };
     86 		char service[NI_MAXSERV] = { 0 };
     87 
     88 		getnameinfo((struct sockaddr *) sock, socklen,
     89 			    host, sizeof(host),
     90 			    service, sizeof(service),
     91 			    NI_NUMERICHOST);
     92 
     93 		wpa_printf(level, "%s %s:%s", msg, host, service);
     94 		break;
     95 	}
     96 #endif /* CONFIG_CTRL_IFACE_UDP */
     97 #ifdef CONFIG_CTRL_IFACE_UNIX
     98 	case AF_UNIX:
     99 	{
    100 		char addr_txt[200];
    101 
    102 		printf_encode(addr_txt, sizeof(addr_txt),
    103 			      (u8 *) ((struct sockaddr_un *) sock)->sun_path,
    104 			      socklen - offsetof(struct sockaddr_un, sun_path));
    105 		wpa_printf(level, "%s %s", msg, addr_txt);
    106 		break;
    107 	}
    108 #endif /* CONFIG_CTRL_IFACE_UNIX */
    109 	default:
    110 		wpa_printf(level, "%s", msg);
    111 		break;
    112 	}
    113 }
    114 
    115 
    116 static int ctrl_set_events(struct wpa_ctrl_dst *dst, const char *input)
    117 {
    118 	const char *value;
    119 	int val;
    120 
    121 	if (!input)
    122 		return 0;
    123 
    124 	value = os_strchr(input, '=');
    125 	if (!value)
    126 		return -1;
    127 	value++;
    128 	val = atoi(value);
    129 	if (val < 0 || val > 1)
    130 		return -1;
    131 
    132 	if (str_starts(input, "probe_rx_events=")) {
    133 		if (val)
    134 			dst->events |= WPA_EVENT_RX_PROBE_REQUEST;
    135 		else
    136 			dst->events &= ~WPA_EVENT_RX_PROBE_REQUEST;
    137 	}
    138 
    139 	return 0;
    140 }
    141 
    142 
    143 int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
    144 		      socklen_t fromlen, const char *input)
    145 {
    146 	struct wpa_ctrl_dst *dst;
    147 
    148 	/* Update event registration if already attached */
    149 	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
    150 		if (!sockaddr_compare(from, fromlen,
    151 				      &dst->addr, dst->addrlen))
    152 			return ctrl_set_events(dst, input);
    153 	}
    154 
    155 	/* New attachment */
    156 	dst = os_zalloc(sizeof(*dst));
    157 	if (dst == NULL)
    158 		return -1;
    159 	os_memcpy(&dst->addr, from, fromlen);
    160 	dst->addrlen = fromlen;
    161 	dst->debug_level = MSG_INFO;
    162 	ctrl_set_events(dst, input);
    163 	dl_list_add(ctrl_dst, &dst->list);
    164 
    165 	sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
    166 	return 0;
    167 }
    168 
    169 
    170 int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
    171 		      socklen_t fromlen)
    172 {
    173 	struct wpa_ctrl_dst *dst;
    174 
    175 	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
    176 		if (!sockaddr_compare(from, fromlen,
    177 				      &dst->addr, dst->addrlen)) {
    178 			sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
    179 				       from, fromlen);
    180 			dl_list_del(&dst->list);
    181 			os_free(dst);
    182 			return 0;
    183 		}
    184 	}
    185 
    186 	return -1;
    187 }
    188 
    189 
    190 int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
    191 		     socklen_t fromlen, const char *level)
    192 {
    193 	struct wpa_ctrl_dst *dst;
    194 
    195 	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
    196 
    197 	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
    198 		if (!sockaddr_compare(from, fromlen,
    199 				      &dst->addr, dst->addrlen)) {
    200 			sockaddr_print(MSG_DEBUG,
    201 				       "CTRL_IFACE changed monitor level",
    202 				       from, fromlen);
    203 			dst->debug_level = atoi(level);
    204 			return 0;
    205 		}
    206 	}
    207 
    208 	return -1;
    209 }
    210