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