1 /* 2 * Common hostapd/wpa_supplicant ctrl iface code. 3 * Copyright (c) 2002-2013, Jouni Malinen <j@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