1 /* $OpenBSD: iapp.c,v 1.20 2019/05/10 01:29:31 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/ioctl.h> 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <sys/time.h> 23 #include <sys/uio.h> 24 25 #include <net/if.h> 26 #include <net/if_media.h> 27 #include <net/if_arp.h> 28 #include <net/if_llc.h> 29 #include <net/bpf.h> 30 31 #include <netinet/in.h> 32 #include <netinet/if_ether.h> 33 #include <arpa/inet.h> 34 35 #include <fcntl.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 #include <limits.h> 40 41 #include "hostapd.h" 42 #include "iapp.h" 43 44 void 45 hostapd_iapp_init(struct hostapd_config *cfg) 46 { 47 struct hostapd_apme *apme; 48 struct hostapd_iapp *iapp = &cfg->c_iapp; 49 50 if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) 51 return; 52 53 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { 54 /* Get Host AP's BSSID */ 55 hostapd_priv_apme_bssid(apme); 56 hostapd_log(HOSTAPD_LOG, 57 "%s/%s: attached Host AP interface with BSSID %s", 58 apme->a_iface, iapp->i_iface, 59 etheraddr_string(apme->a_bssid)); 60 61 /* Deauthenticate all stations on startup */ 62 (void)hostapd_apme_deauth(apme); 63 } 64 } 65 66 void 67 hostapd_iapp_term(struct hostapd_config *cfg) 68 { 69 struct hostapd_apme *apme; 70 struct hostapd_iapp *iapp = &cfg->c_iapp; 71 72 if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) 73 return; 74 75 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { 76 hostapd_log(HOSTAPD_LOG_VERBOSE, 77 "%s/%s: detaching from Host AP", 78 apme->a_iface, iapp->i_iface); 79 } 80 } 81 82 int 83 hostapd_iapp_add_notify(struct hostapd_apme *apme, struct hostapd_node *node) 84 { 85 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 86 struct hostapd_iapp *iapp = &cfg->c_iapp; 87 struct sockaddr_in *addr; 88 struct { 89 struct ieee80211_iapp_frame hdr; 90 struct ieee80211_iapp_add_notify add; 91 } __packed frame; 92 93 if ((iapp->i_flags & HOSTAPD_IAPP_F_ADD_NOTIFY) == 0) 94 return (0); 95 96 /* 97 * Send an ADD.notify message to other access points to notify 98 * about a new association on our Host AP. 99 */ 100 bzero(&frame, sizeof(frame)); 101 102 frame.hdr.i_version = IEEE80211_IAPP_VERSION; 103 frame.hdr.i_command = IEEE80211_IAPP_FRAME_ADD_NOTIFY; 104 frame.hdr.i_identifier = htons(iapp->i_cnt++); 105 frame.hdr.i_length = sizeof(struct ieee80211_iapp_add_notify); 106 107 frame.add.a_length = IEEE80211_ADDR_LEN; 108 frame.add.a_seqnum = htons(node->ni_rxseq); 109 bcopy(node->ni_macaddr, frame.add.a_macaddr, IEEE80211_ADDR_LEN); 110 111 if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) 112 addr = &iapp->i_broadcast; 113 else 114 addr = &iapp->i_multicast; 115 116 if (sendto(iapp->i_udp, &frame, sizeof(frame), 117 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) { 118 hostapd_log(HOSTAPD_LOG, 119 "%s: failed to send ADD notification: %s", 120 iapp->i_iface, strerror(errno)); 121 return (errno); 122 } 123 124 hostapd_log(HOSTAPD_LOG, "%s/%s: sent ADD notification for %s", 125 apme->a_iface, iapp->i_iface, 126 etheraddr_string(frame.add.a_macaddr)); 127 128 /* Send a LLC XID frame, see llc.c for details */ 129 return (hostapd_priv_llc_xid(cfg, node)); 130 } 131 132 int 133 hostapd_iapp_radiotap(struct hostapd_apme *apme, u_int8_t *buf, 134 const u_int len) 135 { 136 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 137 struct hostapd_iapp *iapp = &cfg->c_iapp; 138 struct sockaddr_in *addr; 139 struct ieee80211_iapp_frame hdr; 140 struct msghdr msg; 141 struct iovec iov[2]; 142 143 /* 144 * Send an HOSTAPD.pcap/radiotap message to other access points 145 * with an appended network dump. This is an hostapd extension to 146 * IAPP. 147 */ 148 bzero(&hdr, sizeof(hdr)); 149 150 hdr.i_version = IEEE80211_IAPP_VERSION; 151 if (cfg->c_apme_dlt == DLT_IEEE802_11_RADIO) 152 hdr.i_command = IEEE80211_IAPP_FRAME_HOSTAPD_RADIOTAP; 153 else if (cfg->c_apme_dlt == DLT_IEEE802_11) 154 hdr.i_command = IEEE80211_IAPP_FRAME_HOSTAPD_PCAP; 155 else 156 return (EINVAL); 157 hdr.i_identifier = htons(iapp->i_cnt++); 158 hdr.i_length = len; 159 160 if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) 161 addr = &iapp->i_broadcast; 162 else 163 addr = &iapp->i_multicast; 164 165 iov[0].iov_base = &hdr; 166 iov[0].iov_len = sizeof(hdr); 167 iov[1].iov_base = buf; 168 iov[1].iov_len = len; 169 msg.msg_name = (caddr_t)addr; 170 msg.msg_namelen = sizeof(struct sockaddr_in); 171 msg.msg_iov = iov; 172 msg.msg_iovlen = 2; 173 msg.msg_control = 0; 174 msg.msg_controllen = 0; 175 msg.msg_flags = 0; 176 177 if (sendmsg(iapp->i_udp, &msg, 0) == -1) { 178 hostapd_log(HOSTAPD_LOG, 179 "%s: failed to send HOSTAPD %s: %s", 180 iapp->i_iface, cfg->c_apme_dlt == 181 DLT_IEEE802_11_RADIO ? "radiotap" : "pcap", 182 strerror(errno)); 183 return (errno); 184 } 185 186 return (0); 187 } 188 189 void 190 hostapd_iapp_input(int fd, short sig, void *arg) 191 { 192 struct hostapd_config *cfg = (struct hostapd_config *)arg; 193 struct hostapd_iapp *iapp = &cfg->c_iapp; 194 struct hostapd_apme *apme; 195 struct sockaddr_in addr; 196 socklen_t addr_len; 197 ssize_t len; 198 u_int8_t buf[IAPP_MAXSIZE]; 199 struct hostapd_node node; 200 struct ieee80211_iapp_recv { 201 struct ieee80211_iapp_frame hdr; 202 union { 203 struct ieee80211_iapp_add_notify add; 204 u_int8_t buf[1]; 205 } u; 206 } __packed *frame; 207 u_int dlt; 208 int ret = 0; 209 210 /* Ignore invalid signals */ 211 if (sig != EV_READ) 212 return; 213 214 /* 215 * Listen to possible messages from other IAPP 216 */ 217 bzero(buf, sizeof(buf)); 218 219 if ((len = recvfrom(fd, buf, sizeof(buf), 0, 220 (struct sockaddr*)&addr, &addr_len)) < 1) 221 return; 222 223 if (bcmp(&iapp->i_addr.sin_addr, &addr.sin_addr, 224 sizeof(addr.sin_addr)) == 0) 225 return; 226 227 frame = (struct ieee80211_iapp_recv*)buf; 228 229 /* Validate the IAPP version */ 230 if (len < (ssize_t)sizeof(struct ieee80211_iapp_frame) || 231 frame->hdr.i_version != IEEE80211_IAPP_VERSION || 232 addr_len < sizeof(struct sockaddr_in)) 233 return; 234 235 cfg->c_stats.cn_rx_iapp++; 236 237 /* 238 * Process the IAPP frame 239 */ 240 switch (frame->hdr.i_command) { 241 case IEEE80211_IAPP_FRAME_ADD_NOTIFY: 242 /* Short frame */ 243 if (len < (ssize_t)(sizeof(struct ieee80211_iapp_frame) + 244 sizeof(struct ieee80211_iapp_add_notify))) 245 return; 246 247 /* Don't support non-48bit MAC addresses, yet */ 248 if (frame->u.add.a_length != IEEE80211_ADDR_LEN) 249 return; 250 251 node.ni_rxseq = frame->u.add.a_seqnum; 252 bcopy(frame->u.add.a_macaddr, node.ni_macaddr, 253 IEEE80211_ADDR_LEN); 254 255 /* 256 * Try to remove a node from our Host AP and to free 257 * any allocated resources. Otherwise the received 258 * ADD.notify message will be ignored. 259 */ 260 if (iapp->i_flags & HOSTAPD_IAPP_F_ADD && 261 cfg->c_flags & HOSTAPD_CFG_F_APME) { 262 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { 263 if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) 264 (void)hostapd_roaming_del(apme, &node); 265 if (iapp->i_flags & HOSTAPD_IAPP_F_ADD_NOTIFY && 266 (ret = hostapd_apme_delnode(apme, 267 &node)) == 0) 268 cfg->c_stats.cn_tx_apme++; 269 } 270 } else 271 ret = 0; 272 273 hostapd_log(iapp->i_flags & HOSTAPD_IAPP_F_ADD ? 274 HOSTAPD_LOG : HOSTAPD_LOG_VERBOSE, 275 "%s: %s ADD notification for %s at %s", 276 iapp->i_iface, ret == 0 ? 277 "received" : "ignored", 278 etheraddr_string(node.ni_macaddr), 279 inet_ntoa(addr.sin_addr)); 280 break; 281 282 case IEEE80211_IAPP_FRAME_HOSTAPD_PCAP: 283 case IEEE80211_IAPP_FRAME_HOSTAPD_RADIOTAP: 284 if ((iapp->i_flags & HOSTAPD_IAPP_F_RADIOTAP) == 0) 285 return; 286 287 /* Short frame */ 288 if (len <= (ssize_t)sizeof(struct ieee80211_iapp_frame) || 289 frame->hdr.i_length < sizeof(struct ieee80211_frame)) 290 return; 291 292 dlt = frame->hdr.i_command == 293 IEEE80211_IAPP_FRAME_HOSTAPD_PCAP ? 294 DLT_IEEE802_11 : DLT_IEEE802_11_RADIO; 295 296 hostapd_print_ieee80211(dlt, 1, (u_int8_t *)frame->u.buf, 297 len - sizeof(struct ieee80211_iapp_frame)); 298 return; 299 300 case IEEE80211_IAPP_FRAME_MOVE_NOTIFY: 301 case IEEE80211_IAPP_FRAME_MOVE_RESPONSE: 302 case IEEE80211_IAPP_FRAME_SEND_SECURITY_BLOCK: 303 case IEEE80211_IAPP_FRAME_ACK_SECURITY_BLOCK: 304 case IEEE80211_IAPP_FRAME_CACHE_NOTIFY: 305 case IEEE80211_IAPP_FRAME_CACHE_RESPONSE: 306 307 /* 308 * XXX TODO 309 */ 310 311 hostapd_log(HOSTAPD_LOG_VERBOSE, 312 "%s: received unsupported IAPP message %d", 313 iapp->i_iface, frame->hdr.i_command); 314 return; 315 316 default: 317 return; 318 } 319 } 320