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