1 /* $OpenBSD: apme.c,v 1.15 2007/02/08 11:15:55 reyk 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 <net80211/ieee80211_radiotap.h> 38 39 #include <fcntl.h> 40 #include <stdlib.h> 41 #include <stdio.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include "hostapd.h" 46 #include "iapp.h" 47 48 void hostapd_apme_frame(struct hostapd_apme *, u_int8_t *, u_int); 49 void hostapd_apme_hopper(int, short, void *); 50 51 int 52 hostapd_apme_add(struct hostapd_config *cfg, const char *name) 53 { 54 struct hostapd_apme *apme; 55 56 if (hostapd_apme_lookup(cfg, name) != NULL) 57 return (EEXIST); 58 if ((apme = (struct hostapd_apme *) 59 calloc(1, sizeof(struct hostapd_apme))) == NULL) 60 return (ENOMEM); 61 if (strlcpy(apme->a_iface, name, sizeof(apme->a_iface)) >= 62 sizeof(apme->a_iface)) { 63 free(apme); 64 return (EINVAL); 65 } 66 67 apme->a_cfg = cfg; 68 apme->a_chanavail = NULL; 69 70 TAILQ_INSERT_TAIL(&cfg->c_apmes, apme, a_entries); 71 72 hostapd_log(HOSTAPD_LOG_DEBUG, 73 "%s: Host AP interface added", apme->a_iface); 74 75 return (0); 76 } 77 78 int 79 hostapd_apme_deauth(struct hostapd_apme *apme) 80 { 81 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 82 struct hostapd_iapp *iapp = &cfg->c_iapp; 83 u_int8_t buf[sizeof(struct ieee80211_frame) + sizeof(u_int16_t)]; 84 struct ieee80211_frame *wh; 85 86 bzero(&buf, sizeof(buf)); 87 wh = (struct ieee80211_frame *)&buf[0]; 88 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 89 IEEE80211_FC0_SUBTYPE_DEAUTH; 90 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 91 memset(&wh->i_addr1, 0xff, IEEE80211_ADDR_LEN); 92 bcopy(apme->a_bssid, wh->i_addr2, IEEE80211_ADDR_LEN); 93 bcopy(apme->a_bssid, wh->i_addr3, IEEE80211_ADDR_LEN); 94 *(u_int16_t *)(wh + 1) = htole16(IEEE80211_REASON_AUTH_EXPIRE); 95 96 if (write(apme->a_raw, buf, sizeof(buf)) == -1) { 97 hostapd_log(HOSTAPD_LOG_VERBOSE, 98 "%s/%s: failed to deauthenticate all stations: %s", 99 iapp->i_iface, apme->a_iface, 100 strerror(errno)); 101 return (EIO); 102 } 103 104 hostapd_log(HOSTAPD_LOG_VERBOSE, 105 "%s/%s: deauthenticated all stations", 106 apme->a_iface, iapp->i_iface); 107 108 return (0); 109 } 110 111 struct hostapd_apme * 112 hostapd_apme_lookup(struct hostapd_config *cfg, const char *name) 113 { 114 struct hostapd_apme *apme; 115 116 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { 117 if (strcmp(name, apme->a_iface) == 0) 118 return (apme); 119 } 120 121 return (NULL); 122 } 123 124 struct hostapd_apme * 125 hostapd_apme_addhopper(struct hostapd_config *cfg, const char *name) 126 { 127 struct hostapd_apme *apme; 128 129 if ((apme = hostapd_apme_lookup(cfg, name)) == NULL) 130 return (NULL); 131 if (apme->a_chanavail != NULL) 132 return (NULL); 133 apme->a_curchan = IEEE80211_CHAN_MAX; 134 apme->a_maxchan = roundup(IEEE80211_CHAN_MAX, NBBY); 135 if ((apme->a_chanavail = (u_int8_t *) 136 calloc(apme->a_maxchan, sizeof(u_int8_t))) == NULL) 137 return (NULL); 138 memset(apme->a_chanavail, 0xff, 139 apme->a_maxchan * sizeof(u_int8_t)); 140 (void)strlcpy(apme->a_chanreq.i_name, apme->a_iface, IFNAMSIZ); 141 142 return (apme); 143 } 144 145 void 146 hostapd_apme_sethopper(struct hostapd_apme *apme, int now) 147 { 148 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 149 struct timeval tv; 150 151 bzero(&tv, sizeof(tv)); 152 if (!now) 153 bcopy(&cfg->c_apme_hopdelay, &tv, sizeof(tv)); 154 155 if (!evtimer_initialized(&apme->a_chanev)) 156 evtimer_set(&apme->a_chanev, hostapd_apme_hopper, apme); 157 if (evtimer_add(&apme->a_chanev, &tv) == -1) 158 hostapd_fatal("failed to add hopper event"); 159 } 160 161 void 162 hostapd_apme_hopper(int fd, short sig, void *arg) 163 { 164 struct hostapd_apme *apme = (struct hostapd_apme *)arg; 165 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 166 int ret; 167 168 if (apme->a_curchan >= IEEE80211_CHAN_MAX) 169 apme->a_curchan = 0; 170 171 do { 172 if (apme->a_curchan >= IEEE80211_CHAN_MAX) 173 return; 174 apme->a_curchan %= IEEE80211_CHAN_MAX; 175 apme->a_curchan++; 176 } while (isclr(apme->a_chanavail, apme->a_curchan)); 177 178 apme->a_chanreq.i_channel = apme->a_curchan; 179 if ((ret = ioctl(cfg->c_apme_ctl, SIOCS80211CHANNEL, 180 &apme->a_chanreq)) != 0) { 181 hostapd_apme_sethopper(apme, 1); 182 return; 183 } 184 185 hostapd_log(HOSTAPD_LOG_DEBUG, 186 "[priv]: %s setting to channel %d", 187 apme->a_iface, apme->a_curchan); 188 189 hostapd_apme_sethopper(apme, 0); 190 } 191 192 void 193 hostapd_apme_term(struct hostapd_apme *apme) 194 { 195 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 196 197 /* Remove the channel hopper, if active */ 198 if (apme->a_chanavail != NULL) { 199 (void)event_del(&apme->a_chanev); 200 free(apme->a_chanavail); 201 apme->a_chanavail = NULL; 202 } 203 204 /* Kick a specified Host AP interface */ 205 (void)event_del(&apme->a_ev); 206 if (close(apme->a_raw)) 207 hostapd_fatal("failed to close: %s\n", 208 strerror(errno)); 209 210 TAILQ_REMOVE(&cfg->c_apmes, apme, a_entries); 211 212 /* Remove all dynamic roaming addresses */ 213 if (cfg->c_flags & HOSTAPD_CFG_F_PRIV) 214 hostapd_roaming_term(apme); 215 216 hostapd_log(HOSTAPD_LOG_DEBUG, 217 "%s: Host AP interface removed", apme->a_iface); 218 219 free(apme); 220 } 221 222 void 223 hostapd_apme_input(int fd, short sig, void *arg) 224 { 225 struct hostapd_apme *apme = (struct hostapd_apme *)arg; 226 u_int8_t buf[IAPP_MAXSIZE], *bp, *ep; 227 struct bpf_hdr *bph; 228 ssize_t len; 229 230 /* Ignore invalid signals */ 231 if (sig != EV_READ) 232 return; 233 234 bzero(&buf, sizeof(buf)); 235 236 if ((len = read(fd, buf, sizeof(buf))) < 237 (ssize_t)sizeof(struct ieee80211_frame)) 238 return; 239 240 /* 241 * Loop through each frame. 242 */ 243 244 bp = (u_int8_t *)&buf; 245 ep = bp + len; 246 247 while (bp < ep) { 248 register u_int caplen, hdrlen; 249 250 bph = (struct bpf_hdr *)bp; 251 caplen = bph->bh_caplen; 252 hdrlen = bph->bh_hdrlen; 253 254 /* Process frame */ 255 hostapd_apme_frame(apme, bp + hdrlen, caplen); 256 257 bp += BPF_WORDALIGN(caplen + hdrlen); 258 } 259 } 260 261 int 262 hostapd_apme_output(struct hostapd_apme *apme, 263 struct hostapd_ieee80211_frame *frame) 264 { 265 struct iovec iov[2]; 266 int iovcnt; 267 struct ieee80211_frame wh; 268 269 bzero(&wh, sizeof(wh)); 270 271 switch (frame->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 272 case IEEE80211_FC1_DIR_NODS: 273 bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN); 274 bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN); 275 bcopy(frame->i_bssid, wh.i_addr3, IEEE80211_ADDR_LEN); 276 break; 277 case IEEE80211_FC1_DIR_TODS: 278 bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN); 279 bcopy(frame->i_to, wh.i_addr3, IEEE80211_ADDR_LEN); 280 bcopy(frame->i_bssid, wh.i_addr1, IEEE80211_ADDR_LEN); 281 break; 282 case IEEE80211_FC1_DIR_FROMDS: 283 bcopy(frame->i_from, wh.i_addr3, IEEE80211_ADDR_LEN); 284 bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN); 285 bcopy(frame->i_bssid, wh.i_addr2, IEEE80211_ADDR_LEN); 286 break; 287 default: 288 case IEEE80211_FC1_DIR_DSTODS: 289 return (EINVAL); 290 } 291 292 wh.i_fc[0] = IEEE80211_FC0_VERSION_0 | frame->i_fc[0]; 293 wh.i_fc[1] = frame->i_fc[1]; 294 bcopy(frame->i_dur, wh.i_dur, sizeof(wh.i_dur)); 295 bcopy(frame->i_seq, wh.i_seq, sizeof(wh.i_seq)); 296 297 iovcnt = 1; 298 iov[0].iov_base = &wh; 299 iov[0].iov_len = sizeof(struct ieee80211_frame); 300 301 if (frame->i_data != NULL && frame->i_data_len > 0) { 302 iovcnt = 2; 303 iov[1].iov_base = frame->i_data; 304 iov[1].iov_len = frame->i_data_len; 305 } 306 307 if (writev(apme->a_raw, iov, iovcnt) == -1) 308 return (errno); 309 310 return (0); 311 } 312 313 int 314 hostapd_apme_offset(struct hostapd_apme *apme, 315 u_int8_t *buf, const u_int len) 316 { 317 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 318 struct ieee80211_radiotap_header *rh; 319 u_int rh_len; 320 321 if (cfg->c_apme_dlt == DLT_IEEE802_11) 322 return (0); 323 else if (cfg->c_apme_dlt != DLT_IEEE802_11_RADIO) 324 return (-1); 325 326 if (len < sizeof(struct ieee80211_radiotap_header)) 327 return (-1); 328 329 rh = (struct ieee80211_radiotap_header*)buf; 330 rh_len = letoh16(rh->it_len); 331 332 if (rh->it_version != 0) 333 return (-1); 334 if (len <= rh_len) 335 return (-1); 336 337 return ((int)rh_len); 338 } 339 340 void 341 hostapd_apme_frame(struct hostapd_apme *apme, u_int8_t *buf, u_int len) 342 { 343 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 344 struct hostapd_iapp *iapp = &cfg->c_iapp; 345 struct hostapd_apme *other_apme; 346 struct hostapd_node node; 347 struct ieee80211_frame *wh; 348 int offset; 349 350 if ((offset = hostapd_apme_offset(apme, buf, len)) < 0) 351 return; 352 wh = (struct ieee80211_frame *)(buf + offset); 353 354 /* Ignore short frames or fragments */ 355 if (len < sizeof(struct ieee80211_frame)) 356 return; 357 358 /* Handle received frames */ 359 if ((hostapd_handle_input(apme, buf, len) == 360 (HOSTAPD_FRAME_F_RET_SKIP >> HOSTAPD_FRAME_F_RET_S)) || 361 cfg->c_flags & HOSTAPD_CFG_F_IAPP_PASSIVE) 362 return; 363 364 /* 365 * Only accept local association response frames, ... 366 */ 367 if (!((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == 368 IEEE80211_FC1_DIR_NODS && 369 (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 370 IEEE80211_FC0_TYPE_MGT && 371 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 372 IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) 373 return; 374 375 /* 376 * ...sent by the Host AP (addr2) to our BSSID (addr3) 377 */ 378 if (bcmp(wh->i_addr2, apme->a_bssid, IEEE80211_ADDR_LEN) != 0 || 379 bcmp(wh->i_addr3, apme->a_bssid, IEEE80211_ADDR_LEN) != 0) 380 return; 381 382 cfg->c_stats.cn_rx_apme++; 383 384 /* 385 * Double-check if the station got associated to our Host AP 386 */ 387 bcopy(wh->i_addr1, node.ni_macaddr, IEEE80211_ADDR_LEN); 388 if (hostapd_priv_apme_getnode(apme, &node) != 0) { 389 hostapd_log(HOSTAPD_LOG_DEBUG, 390 "%s: invalid association from %s on the Host AP", 391 apme->a_iface, etheraddr_string(wh->i_addr1)); 392 return; 393 } 394 cfg->c_stats.cn_tx_apme++; 395 396 /* 397 * Delete node on other attached Host APs 398 */ 399 TAILQ_FOREACH(other_apme, &cfg->c_apmes, a_entries) { 400 if (apme == other_apme) 401 continue; 402 if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) 403 (void)hostapd_roaming_del(other_apme, &node); 404 if (hostapd_apme_delnode(other_apme, &node) == 0) 405 cfg->c_stats.cn_tx_apme++; 406 } 407 408 if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING) 409 (void)hostapd_roaming_add(apme, &node); 410 411 (void)hostapd_iapp_add_notify(apme, &node); 412 } 413 414 void 415 hostapd_apme_init(struct hostapd_apme *apme) 416 { 417 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 418 u_int i, dlt; 419 struct ifreq ifr; 420 421 apme->a_raw = hostapd_bpf_open(O_RDWR); 422 423 apme->a_rawlen = IAPP_MAXSIZE; 424 if (ioctl(apme->a_raw, BIOCSBLEN, &apme->a_rawlen) == -1) 425 hostapd_fatal("failed to set BPF buffer len \"%s\": %s\n", 426 apme->a_iface, strerror(errno)); 427 428 i = 1; 429 if (ioctl(apme->a_raw, BIOCIMMEDIATE, &i) == -1) 430 hostapd_fatal("failed to set BPF immediate mode on \"%s\": " 431 "%s\n", apme->a_iface, strerror(errno)); 432 433 bzero(&ifr, sizeof(struct ifreq)); 434 (void)strlcpy(ifr.ifr_name, apme->a_iface, sizeof(ifr.ifr_name)); 435 436 /* This may fail, ignore it */ 437 (void)ioctl(apme->a_raw, BIOCPROMISC, NULL); 438 439 /* Associate the wireless network interface to the BPF descriptor */ 440 if (ioctl(apme->a_raw, BIOCSETIF, &ifr) == -1) 441 hostapd_fatal("failed to set BPF interface \"%s\": %s\n", 442 apme->a_iface, strerror(errno)); 443 444 dlt = cfg->c_apme_dlt; 445 if (ioctl(apme->a_raw, BIOCSDLT, &dlt) == -1) 446 hostapd_fatal("failed to set BPF link type on \"%s\": %s\n", 447 apme->a_iface, strerror(errno)); 448 449 /* Lock the BPF descriptor, no further configuration */ 450 if (ioctl(apme->a_raw, BIOCLOCK, NULL) == -1) 451 hostapd_fatal("failed to lock BPF interface on \"%s\": %s\n", 452 apme->a_iface, strerror(errno)); 453 } 454 455 int 456 hostapd_apme_addnode(struct hostapd_apme *apme, struct hostapd_node *node) 457 { 458 return (hostapd_priv_apme_setnode(apme, node, 1)); 459 } 460 461 int 462 hostapd_apme_delnode(struct hostapd_apme *apme, struct hostapd_node *node) 463 { 464 return (hostapd_priv_apme_setnode(apme, node, 0)); 465 } 466