1 /* $OpenBSD: handle.c,v 1.13 2019/05/10 01:29:31 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006 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 24 #include <net/if.h> 25 #include <net/if_media.h> 26 #include <net/if_arp.h> 27 #include <net/if_llc.h> 28 #include <net/bpf.h> 29 30 #include <netinet/in.h> 31 #include <netinet/if_ether.h> 32 #include <arpa/inet.h> 33 34 #include <net80211/ieee80211.h> 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 46 int hostapd_handle_frame(struct hostapd_apme *, struct hostapd_frame *, 47 u_int8_t *, const u_int); 48 int hostapd_handle_action(struct hostapd_apme *, struct hostapd_frame *, 49 u_int8_t *, u_int8_t *, u_int8_t *, u_int8_t *, const u_int); 50 void hostapd_handle_addr(const u_int32_t, u_int32_t *, u_int8_t *, 51 u_int8_t *, struct hostapd_table *); 52 void hostapd_handle_ref(u_int, u_int, u_int8_t *, u_int8_t *, u_int8_t *, 53 u_int8_t *); 54 int hostapd_handle_radiotap(struct hostapd_radiotap *, u_int8_t *, 55 const u_int); 56 int hostapd_cmp(enum hostapd_op, int, int); 57 58 int 59 hostapd_handle_input(struct hostapd_apme *apme, u_int8_t *buf, u_int len) 60 { 61 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 62 struct hostapd_frame *frame; 63 int ret; 64 65 TAILQ_FOREACH(frame, &cfg->c_frames, f_entries) { 66 if ((ret = hostapd_handle_frame(apme, frame, buf, len)) != 0) 67 return (ret); 68 } 69 70 return (0); 71 } 72 73 void 74 hostapd_handle_addr(const u_int32_t mask, u_int32_t *flags, u_int8_t *addr, 75 u_int8_t *maddr, struct hostapd_table *table) 76 { 77 int ret = 0; 78 79 if ((*flags & mask) & HOSTAPD_FRAME_TABLE) { 80 if (hostapd_entry_lookup(table, addr) == NULL) 81 ret = 1; 82 } else if (bcmp(addr, maddr, IEEE80211_ADDR_LEN) != 0) 83 ret = 1; 84 85 if ((ret == 1 && (*flags & mask) & HOSTAPD_FRAME_N) || 86 (ret == 0 && ((*flags & mask) & HOSTAPD_FRAME_N) == 0)) 87 *flags &= ~mask; 88 } 89 90 void 91 hostapd_handle_ref(u_int flags, u_int shift, u_int8_t *wfrom, u_int8_t *wto, 92 u_int8_t *wbssid, u_int8_t *addr) 93 { 94 if (flags & (HOSTAPD_ACTION_F_REF_FROM << shift)) 95 bcopy(wfrom, addr, IEEE80211_ADDR_LEN); 96 else if (flags & (HOSTAPD_ACTION_F_REF_TO << shift)) 97 bcopy(wto, addr, IEEE80211_ADDR_LEN); 98 else if (flags & (HOSTAPD_ACTION_F_REF_BSSID << shift)) 99 bcopy(wbssid, addr, IEEE80211_ADDR_LEN); 100 else if (flags & (HOSTAPD_ACTION_F_REF_RANDOM << shift)) { 101 hostapd_randval(addr, IEEE80211_ADDR_LEN); 102 /* Avoid multicast/broadcast addresses */ 103 addr[0] &= ~0x1; 104 } 105 } 106 107 int 108 hostapd_handle_frame(struct hostapd_apme *apme, struct hostapd_frame *frame, 109 u_int8_t *buf, const u_int len) 110 { 111 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 112 struct ieee80211_frame *wh; 113 struct hostapd_ieee80211_frame *mh; 114 struct hostapd_radiotap rtap; 115 u_int8_t *wfrom, *wto, *wbssid; 116 struct timeval t_now; 117 u_int32_t flags; 118 int offset, min_rate = 0, val; 119 120 if ((offset = hostapd_apme_offset(apme, buf, len)) < 0) 121 return (0); 122 wh = (struct ieee80211_frame *)(buf + offset); 123 124 mh = &frame->f_frame; 125 flags = frame->f_flags; 126 127 /* Get timestamp */ 128 if (gettimeofday(&t_now, NULL) == -1) 129 hostapd_fatal("gettimeofday"); 130 131 /* Handle optional limit */ 132 if (frame->f_limit.tv_sec || frame->f_limit.tv_usec) { 133 if (timercmp(&t_now, &frame->f_then, <)) 134 return (0); 135 timeradd(&t_now, &frame->f_limit, &frame->f_then); 136 } 137 138 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 139 case IEEE80211_FC1_DIR_NODS: 140 wfrom = wh->i_addr2; 141 wto = wh->i_addr1; 142 wbssid = wh->i_addr3; 143 break; 144 case IEEE80211_FC1_DIR_TODS: 145 wfrom = wh->i_addr2; 146 wto = wh->i_addr3; 147 wbssid = wh->i_addr1; 148 break; 149 case IEEE80211_FC1_DIR_FROMDS: 150 wfrom = wh->i_addr3; 151 wto = wh->i_addr1; 152 wbssid = wh->i_addr2; 153 break; 154 default: 155 case IEEE80211_FC1_DIR_DSTODS: 156 return (0); 157 } 158 159 if (flags & HOSTAPD_FRAME_F_APME_M) { 160 if (frame->f_apme == NULL) 161 return (0); 162 /* Match hostap interface */ 163 if ((flags & HOSTAPD_FRAME_F_APME && 164 apme == frame->f_apme) || 165 (flags & HOSTAPD_FRAME_F_APME_N && 166 apme != frame->f_apme)) 167 flags &= ~HOSTAPD_FRAME_F_APME_M; 168 } 169 170 if (flags & HOSTAPD_FRAME_F_TYPE) { 171 /* type $type */ 172 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 173 (mh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)) 174 flags &= ~HOSTAPD_FRAME_F_TYPE; 175 } else if (flags & HOSTAPD_FRAME_F_TYPE_N) { 176 /* type !$type */ 177 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != 178 (mh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)) 179 flags &= ~HOSTAPD_FRAME_F_TYPE_N; 180 } 181 182 if (flags & HOSTAPD_FRAME_F_SUBTYPE) { 183 /* subtype $subtype */ 184 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 185 (mh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)) 186 flags &= ~HOSTAPD_FRAME_F_SUBTYPE; 187 } else if (flags & HOSTAPD_FRAME_F_SUBTYPE_N) { 188 /* subtype !$subtype */ 189 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) != 190 (mh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)) 191 flags &= ~HOSTAPD_FRAME_F_SUBTYPE_N; 192 } 193 194 if (flags & HOSTAPD_FRAME_F_DIR) { 195 /* dir $dir */ 196 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == 197 (mh->i_fc[1] & IEEE80211_FC1_DIR_MASK)) 198 flags &= ~HOSTAPD_FRAME_F_DIR; 199 } else if (flags & HOSTAPD_FRAME_F_DIR_N) { 200 /* dir !$dir */ 201 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != 202 (mh->i_fc[1] & IEEE80211_FC1_DIR_MASK)) 203 flags &= ~HOSTAPD_FRAME_F_DIR_N; 204 } 205 206 /* from/to/bssid [!]$addr/<table> */ 207 hostapd_handle_addr(HOSTAPD_FRAME_F_FROM_M, &flags, wfrom, 208 mh->i_from, frame->f_from); 209 hostapd_handle_addr(HOSTAPD_FRAME_F_TO_M, &flags, wto, 210 mh->i_to, frame->f_to); 211 hostapd_handle_addr(HOSTAPD_FRAME_F_BSSID_M, &flags, wbssid, 212 mh->i_bssid, frame->f_bssid); 213 214 /* parse the optional radiotap header if required */ 215 if (frame->f_radiotap) { 216 if (hostapd_handle_radiotap(&rtap, buf, len) != 0) 217 return (0); 218 else if ((rtap.r_present & frame->f_radiotap) != 219 frame->f_radiotap) { 220 cfg->c_stats.cn_rtap_miss++; 221 return (0); 222 } 223 if (flags & HOSTAPD_FRAME_F_RSSI && rtap.r_max_rssi) { 224 val = ((float)rtap.r_rssi / rtap.r_max_rssi) * 100; 225 if (hostapd_cmp(frame->f_rssi_op, 226 val, frame->f_rssi)) 227 flags &= ~HOSTAPD_FRAME_F_RSSI; 228 } 229 if (flags & HOSTAPD_FRAME_F_RATE) { 230 val = rtap.r_txrate; 231 if (hostapd_cmp(frame->f_txrate_op, 232 val, frame->f_txrate)) 233 flags &= ~HOSTAPD_FRAME_F_RATE; 234 } 235 if (flags & HOSTAPD_FRAME_F_CHANNEL) { 236 val = rtap.r_chan; 237 if (hostapd_cmp(frame->f_chan_op, 238 val, frame->f_chan)) 239 flags &= ~HOSTAPD_FRAME_F_CHANNEL; 240 } 241 } 242 243 /* Handle if frame matches */ 244 if ((flags & HOSTAPD_FRAME_F_M) != 0) 245 return (0); 246 247 /* Handle optional minimal rate */ 248 if (frame->f_rate && frame->f_rate_intval) { 249 frame->f_rate_delay = t_now.tv_sec - frame->f_last.tv_sec; 250 if (frame->f_rate_delay < frame->f_rate_intval) { 251 frame->f_rate_cnt++; 252 if (frame->f_rate_cnt < frame->f_rate) 253 min_rate = 1; 254 } else { 255 min_rate = 1; 256 frame->f_rate_cnt = 0; 257 } 258 } 259 260 /* Update timestamp for the last match of this event */ 261 if (frame->f_rate_cnt == 0 || min_rate == 0) 262 bcopy(&t_now, &frame->f_last, sizeof(struct timeval)); 263 264 /* Return if the minimal rate is not reached, yet */ 265 if (min_rate) 266 return (0); 267 268 if (hostapd_handle_action(apme, frame, wfrom, wto, wbssid, buf, 269 len) != 0) 270 return (0); 271 272 /* Reset minimal rate counter after successfully handled the frame */ 273 frame->f_rate_cnt = 0; 274 275 return ((frame->f_flags & HOSTAPD_FRAME_F_RET_M) >> 276 HOSTAPD_FRAME_F_RET_S); 277 } 278 279 int 280 hostapd_handle_action(struct hostapd_apme *apme, struct hostapd_frame *frame, 281 u_int8_t *wfrom, u_int8_t *wto, u_int8_t *wbssid, u_int8_t *buf, 282 const u_int len) 283 { 284 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 285 struct hostapd_iapp *iapp = &cfg->c_iapp; 286 struct hostapd_action_data *action = &frame->f_action_data; 287 struct hostapd_node node; 288 u_int8_t *lladdr = NULL; 289 int ret = 0, offset; 290 291 switch (frame->f_action) { 292 case HOSTAPD_ACTION_RADIOTAP: 293 /* Send IAPP frame with radiotap/pcap payload */ 294 if ((ret = hostapd_iapp_radiotap(apme, buf, len)) != 0) 295 return (ret); 296 297 if ((frame->f_action_flags & HOSTAPD_ACTION_VERBOSE) == 0) 298 return (0); 299 300 hostapd_log(HOSTAPD_LOG, 301 "%s: sent IAPP frame HOSTAPD_%s (%u bytes)", 302 iapp->i_iface, cfg->c_apme_dlt == 303 DLT_IEEE802_11_RADIO ? "RADIOTAP" : "PCAP", len); 304 break; 305 306 case HOSTAPD_ACTION_LOG: 307 /* Log frame to syslog/stderr */ 308 if (frame->f_rate && frame->f_rate_intval) { 309 hostapd_printf("%s: (rate: %ld/%ld sec) ", 310 apme->a_iface, frame->f_rate_cnt, 311 frame->f_rate_delay + 1); 312 } else 313 hostapd_printf("%s: ", apme->a_iface); 314 315 hostapd_print_ieee80211(cfg->c_apme_dlt, frame->f_action_flags & 316 HOSTAPD_ACTION_VERBOSE, buf, len); 317 318 /* Flush output buffer */ 319 hostapd_printf(NULL); 320 break; 321 322 case HOSTAPD_ACTION_DELNODE: 323 case HOSTAPD_ACTION_ADDNODE: 324 bzero(&node, sizeof(node)); 325 326 if (action->a_flags & HOSTAPD_ACTION_F_REF_FROM) 327 lladdr = wfrom; 328 else if (action->a_flags & HOSTAPD_ACTION_F_REF_TO) 329 lladdr = wto; 330 else if (action->a_flags & HOSTAPD_ACTION_F_REF_BSSID) 331 lladdr = wbssid; 332 else 333 lladdr = action->a_lladdr; 334 335 bcopy(lladdr, &node.ni_macaddr, IEEE80211_ADDR_LEN); 336 337 if (frame->f_action == HOSTAPD_ACTION_DELNODE) 338 ret = hostapd_apme_delnode(apme, &node); 339 else 340 ret = hostapd_apme_addnode(apme, &node); 341 342 if (ret != 0) { 343 hostapd_log(HOSTAPD_LOG_DEBUG, 344 "%s: node add/delete %s failed: %s", 345 apme->a_iface, etheraddr_string(lladdr), 346 strerror(ret)); 347 } 348 break; 349 350 case HOSTAPD_ACTION_NONE: 351 /* Nothing */ 352 break; 353 354 case HOSTAPD_ACTION_RESEND: 355 /* Resend received raw IEEE 802.11 frame */ 356 if ((offset = hostapd_apme_offset(apme, buf, len)) < 0) 357 return (EINVAL); 358 if (write(apme->a_raw, buf + offset, len - offset) == -1) 359 ret = errno; 360 break; 361 362 case HOSTAPD_ACTION_FRAME: 363 if (action->a_flags & HOSTAPD_ACTION_F_REF_M) { 364 hostapd_handle_ref(action->a_flags & 365 HOSTAPD_ACTION_F_REF_FROM_M, 366 HOSTAPD_ACTION_F_REF_FROM_S, wfrom, wto, wbssid, 367 action->a_frame.i_from); 368 hostapd_handle_ref(action->a_flags & 369 HOSTAPD_ACTION_F_REF_TO_M, 370 HOSTAPD_ACTION_F_REF_TO_S, wfrom, wto, wbssid, 371 action->a_frame.i_to); 372 hostapd_handle_ref(action->a_flags & 373 HOSTAPD_ACTION_F_REF_BSSID_M, 374 HOSTAPD_ACTION_F_REF_BSSID_S, wfrom, wto, wbssid, 375 action->a_frame.i_bssid); 376 } 377 378 /* Send a raw IEEE 802.11 frame */ 379 return (hostapd_apme_output(apme, &action->a_frame)); 380 381 default: 382 return (0); 383 } 384 385 return (ret); 386 } 387 388 int 389 hostapd_handle_radiotap(struct hostapd_radiotap *rtap, 390 u_int8_t *buf, const u_int len) 391 { 392 struct ieee80211_radiotap_header *rh = 393 (struct ieee80211_radiotap_header*)buf; 394 u_int8_t *t, *ptr = NULL; 395 u_int rh_len; 396 const u_int8_t *snapend = buf + len; 397 398 TCHECK(*rh); 399 400 rh_len = letoh16(rh->it_len); 401 if (rh->it_version != 0) 402 return (EINVAL); 403 if (len <= rh_len) 404 goto trunc; 405 406 bzero(rtap, sizeof(struct hostapd_radiotap)); 407 408 t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header); 409 if ((rtap->r_present = letoh32(rh->it_present)) == 0) 410 return (0); 411 412 #define RADIOTAP(_x, _len) \ 413 if (rtap->r_present & HOSTAPD_RADIOTAP_F(_x)) { \ 414 TCHECK2(*t, _len); \ 415 ptr = t; \ 416 t += _len; \ 417 } else \ 418 ptr = NULL; 419 420 /* radiotap doesn't use TLV header fields, ugh */ 421 RADIOTAP(TSFT, 8); 422 RADIOTAP(FLAGS, 1); 423 424 RADIOTAP(RATE, 1); 425 if (ptr != NULL) { 426 rtap->r_txrate = *(u_int8_t *)ptr; 427 } 428 429 RADIOTAP(CHANNEL, 4); 430 if (ptr != NULL) { 431 rtap->r_chan = letoh16(*(u_int16_t*)ptr); 432 rtap->r_chan_flags = letoh16(*(u_int16_t*)ptr + 1); 433 } 434 435 RADIOTAP(FHSS, 2); 436 RADIOTAP(DBM_ANTSIGNAL, 1); 437 RADIOTAP(DBM_ANTNOISE, 1); 438 RADIOTAP(LOCK_QUALITY, 2); 439 RADIOTAP(TX_ATTENUATION, 2); 440 RADIOTAP(DB_TX_ATTENUATION, 2); 441 RADIOTAP(DBM_TX_POWER, 1); 442 RADIOTAP(ANTENNA, 1); 443 RADIOTAP(DB_ANTSIGNAL, 1); 444 RADIOTAP(DB_ANTNOISE, 1); 445 RADIOTAP(FCS, 4); 446 447 RADIOTAP(RSSI, 2); 448 if (ptr != NULL) { 449 rtap->r_rssi = *(u_int8_t *)ptr; 450 rtap->r_max_rssi = *(u_int8_t *)ptr + 1; 451 } 452 453 return (0); 454 455 trunc: 456 return (EINVAL); 457 } 458 459 int 460 hostapd_cmp(enum hostapd_op op, int val1, int val2) 461 { 462 if ((op == HOSTAPD_OP_EQ && val1 == val2) || 463 (op == HOSTAPD_OP_NE && val1 != val2) || 464 (op == HOSTAPD_OP_LE && val1 <= val2) || 465 (op == HOSTAPD_OP_LT && val1 < val2) || 466 (op == HOSTAPD_OP_GE && val1 >= val2) || 467 (op == HOSTAPD_OP_GT && val1 > val2)) 468 return (1); 469 return (0); 470 } 471