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