|
|
1.1.1.3 ! root 1: /* $Id: bsd-bpf.c,v 1.6 2004/05/17 11:57:01 fredette Exp $ */ 1.1 root 2: 3: /* host/bsd/bsd-bpf.c - BSD Berkeley Packet Filter Ethernet support: */ 4: 5: /* 6: * Copyright (c) 2001, 2003 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.3 ! root 37: _TME_RCSID("$Id: bsd-bpf.c,v 1.6 2004/05/17 11:57:01 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include "bsd-impl.h" 41: #include <tme/generic/ethernet.h> 1.1.1.3 ! root 42: #include <tme/misc.h> 1.1 root 43: #include <stdio.h> 44: #include <string.h> 45: #include <errno.h> 46: #include <fcntl.h> 47: #include <netdb.h> 48: #include <sys/param.h> 49: #include <sys/socket.h> 50: #include <sys/stat.h> 51: #include <net/if.h> 52: #include <netinet/in_systm.h> 53: #include <netinet/in.h> 54: #if defined(HAVE_SYS_SOCKIO_H) 55: #include <sys/sockio.h> 56: #elif defined(HAVE_SYS_SOCKETIO_H) 57: #include <sys/socketio.h> 58: #endif /* HAVE_SYS_SOCKETIO_H */ 59: #include <sys/ioctl.h> 60: #ifdef HAVE_IOCTLS_H 61: #include <ioctls.h> 62: #endif /* HAVE_IOCTLS_H */ 63: #ifdef HAVE_NET_IF_ETHER_H 64: #include <net/if_ether.h> 65: #endif /* HAVE_NET_IF_ETHER_H */ 66: #ifdef HAVE_NET_ETHERNET_H 67: #include <net/ethernet.h> 68: #endif /* HAVE_NET_ETHERNET_H */ 69: #include <netinet/ip.h> 70: #ifdef HAVE_NET_IF_DL_H 71: #include <net/if_dl.h> 72: #endif /* HAVE_NET_IF_DL_H */ 73: #include <arpa/inet.h> 74: #include <net/bpf.h> 75: 76: /* macros: */ 77: 78: /* the callout flags: */ 79: #define TME_BSD_BPF_CALLOUT_CHECK (0) 80: #define TME_BSD_BPF_CALLOUT_RUNNING TME_BIT(0) 81: #define TME_BSD_BPF_CALLOUTS_MASK (-2) 82: #define TME_BSD_BPF_CALLOUT_CTRL TME_BIT(1) 83: #define TME_BSD_BPF_CALLOUT_READ TME_BIT(2) 84: 85: /* structures: */ 86: 87: /* our internal data structure: */ 88: struct tme_bsd_bpf { 89: 90: /* backpointer to our element: */ 91: struct tme_element *tme_bsd_bpf_element; 92: 93: /* our mutex: */ 94: tme_mutex_t tme_bsd_bpf_mutex; 95: 1.1.1.3 ! root 96: /* our reader condition: */ 1.1 root 97: tme_cond_t tme_bsd_bpf_cond_reader; 98: 99: /* the callout flags: */ 100: unsigned int tme_bsd_bpf_callout_flags; 101: 102: /* our Ethernet connection: */ 103: struct tme_ethernet_connection *tme_bsd_bpf_eth_connection; 104: 105: /* the BPF file descriptor: */ 106: int tme_bsd_bpf_fd; 107: 108: /* the size of the packet buffer for the interface: */ 109: size_t tme_bsd_bpf_buffer_size; 110: 111: /* the packet buffer for the interface: */ 112: tme_uint8_t *tme_bsd_bpf_buffer; 113: 114: /* the next offset within the packet buffer, and the end of the data 115: in the packet buffer: */ 116: size_t tme_bsd_bpf_buffer_offset; 117: size_t tme_bsd_bpf_buffer_end; 1.1.1.3 ! root 118: ! 119: /* when nonzero, the packet delay time, in microseconds: */ ! 120: unsigned long tme_bsd_bpf_delay_time; ! 121: ! 122: /* all packets received on or before this time can be released: */ ! 123: struct timeval tme_bsd_bpf_delay_release; ! 124: ! 125: /* when nonzero, the packet delay sleep time, in microseconds: */ ! 126: unsigned long tme_bsd_bpf_delay_sleep; ! 127: ! 128: /* when nonzero, the packet delay is sleeping: */ ! 129: int tme_bsd_bpf_delay_sleeping; 1.1 root 130: }; 131: 132: /* the accept and reject packet insns: */ 133: static const struct bpf_insn _tme_bsd_bpf_insn_accept = BPF_STMT(BPF_RET + BPF_K, (u_int) -1); 134: static const struct bpf_insn _tme_bsd_bpf_insn_reject = BPF_STMT(BPF_RET + BPF_K, 0); 135: 136: /* this creates a BPF filter that accepts Ethernet packets with 137: destination addresses in the configured set. the broadcast address 138: must be in this set, it isn't accepted automatically: */ 139: static int 140: _tme_bsd_bpf_filter(struct tme_ethernet_config *config, 141: const tme_uint8_t *prefix, 142: unsigned int prefix_len, 143: struct bpf_insn *bpf_filter, 144: int bpf_filter_size, 145: int *_first_pc) 146: { 147: unsigned int addr_i; 148: tme_uint8_t byte; 149: tme_uint8_t byte_bitmap[(1 << (8 * sizeof(byte))) >> 3]; 150: int match_pc, miss_pc, this_pc; 151: 152: /* clear the byte bitmap: */ 153: memset(byte_bitmap, 0, sizeof(byte_bitmap)); 154: 155: /* the last instruction jumps to the reject insn when it fails: */ 156: miss_pc = bpf_filter_size - 1; 157: 158: /* loop over all of the addresses: */ 159: for (addr_i = 0; 160: addr_i < config->tme_ethernet_config_addr_count; 161: addr_i++) { 162: 163: /* skip this address if it doesn't match the prefix: */ 164: if (prefix_len > 0 165: && memcmp(config->tme_ethernet_config_addrs[addr_i], 166: prefix, 167: prefix_len)) { 168: continue; 169: } 170: 171: /* get the next byte, and skip this address if this byte has 172: already been done: */ 173: byte = config->tme_ethernet_config_addrs[addr_i][prefix_len]; 174: if (byte_bitmap[byte >> 3] & TME_BIT(byte & 7)) { 175: continue; 176: } 177: byte_bitmap[byte >> 3] |= TME_BIT(byte & 7); 178: 179: /* get the PC of the instruction to branch to if this byte 180: matches. if this is the last byte of the address, the branch 181: target is the accept insn, otherwise recurse and get the first 182: insn of the rest of the matcher: */ 183: match_pc = ((prefix_len == (TME_ETHERNET_ADDR_SIZE - 1)) 184: ? bpf_filter_size - 2 185: : _tme_bsd_bpf_filter(config, 186: config->tme_ethernet_config_addrs[addr_i], 187: prefix_len + 1, 188: bpf_filter, 189: bpf_filter_size, 190: _first_pc)); 191: 192: /* add this testing instruction: */ 193: this_pc = --(*_first_pc); 194: assert(this_pc >= 0); 195: bpf_filter[this_pc].code = BPF_JMP + BPF_JEQ + BPF_K; 196: bpf_filter[this_pc].jt = match_pc - (this_pc + 1); 197: bpf_filter[this_pc].jf = miss_pc - (this_pc + 1); 198: bpf_filter[this_pc].k = byte; 199: 200: /* update the miss pc: */ 201: miss_pc = this_pc; 202: } 203: 204: /* add this load instruction: */ 205: this_pc = --(*_first_pc); 206: assert(this_pc >= 0); 207: bpf_filter[this_pc].code = BPF_LD + BPF_B + BPF_ABS; 208: bpf_filter[this_pc].k = prefix_len; 209: 210: /* return our pc: */ 211: return (this_pc); 212: } 213: 214: /* this dumps a BPF filter. not all insns are supported, just 215: those used by our address matching filters: */ 216: void 217: _tme_bsd_bpf_dump_filter(const struct bpf_program *program) 218: { 1.1.1.2 root 219: unsigned int pc; 1.1 root 220: FILE *fp; 221: const struct bpf_insn *insn; 222: char ldsize; 223: const char *opc; 224: 225: fp = stderr; 226: for (pc = 0, insn = program->bf_insns; 1.1.1.2 root 227: pc < (unsigned int) program->bf_len; 1.1 root 228: pc++, insn++) { 229: 230: /* the PC: */ 231: fprintf(fp, "%d:\t", pc); 232: 233: /* dispatch on the instruction class: */ 234: switch (BPF_CLASS(insn->code)) { 235: 236: case BPF_LD: 237: 238: switch (BPF_SIZE(insn->code)) { 239: case BPF_B: ldsize = 'b'; break; 240: case BPF_H: ldsize = 'w'; break; 241: case BPF_W: ldsize = 'l'; break; 242: default: ldsize = '?'; break; 243: } 244: fprintf(fp, "ld.%c ", ldsize); 245: 246: switch (BPF_MODE(insn->code)) { 247: case BPF_ABS: fprintf(fp, "0x%x", insn->k); break; 248: default: fprintf(fp, "??"); 249: } 250: 251: break; 252: 253: case BPF_JMP: 254: 255: switch (BPF_OP(insn->code)) { 256: case BPF_JEQ: opc = "jeq"; break; 257: default: opc = "??"; break; 258: } 259: fprintf(fp, "%s ", opc); 260: 261: switch (BPF_SRC(insn->code)) { 262: case BPF_K: fprintf(fp, "#0x%x", insn->k); break; 263: case BPF_X: fprintf(fp, "x"); break; 264: default: fprintf(fp, "??"); break; 265: } 266: 267: fprintf(fp, ", %d, %d", pc + 1 + insn->jt, pc + 1 + insn->jf); 268: break; 269: 270: case BPF_RET: 271: switch (BPF_RVAL(insn->code)) { 272: case BPF_A: fprintf(fp, "ret a"); break; 273: case BPF_X: fprintf(fp, "ret x"); break; 274: case BPF_K: fprintf(fp, "ret #0x%x", insn->k); break; 275: default: fprintf(fp, "ret ??"); break; 276: } 277: break; 278: 279: default: 280: fprintf(fp, "??"); 281: break; 282: } 283: 284: putc('\n', fp); 285: } 286: } 287: 288: /* the bpf callout function. it must be called with the mutex locked: */ 289: static void 290: _tme_bsd_bpf_callout(struct tme_bsd_bpf *bpf, int new_callouts) 291: { 292: struct tme_ethernet_connection *conn_eth; 293: int callouts, later_callouts; 294: unsigned int ctrl; 295: int rc; 296: tme_ethernet_fid_t frame_id; 297: struct tme_ethernet_frame_chunk frame_chunk_buffer; 298: tme_uint8_t frame[TME_ETHERNET_FRAME_MAX]; 299: 300: /* add in any new callouts: */ 301: bpf->tme_bsd_bpf_callout_flags |= new_callouts; 302: 303: /* if this function is already running in another thread, simply 304: return now. the other thread will do our work: */ 305: if (bpf->tme_bsd_bpf_callout_flags & TME_BSD_BPF_CALLOUT_RUNNING) { 306: return; 307: } 308: 309: /* callouts are now running: */ 310: bpf->tme_bsd_bpf_callout_flags |= TME_BSD_BPF_CALLOUT_RUNNING; 311: 312: /* assume that we won't need any later callouts: */ 313: later_callouts = 0; 314: 315: /* loop while callouts are needed: */ 316: for (; (callouts = bpf->tme_bsd_bpf_callout_flags) & TME_BSD_BPF_CALLOUTS_MASK; ) { 317: 318: /* clear the needed callouts: */ 319: bpf->tme_bsd_bpf_callout_flags = callouts & ~TME_BSD_BPF_CALLOUTS_MASK; 320: callouts &= TME_BSD_BPF_CALLOUTS_MASK; 321: 322: /* get our Ethernet connection: */ 323: conn_eth = bpf->tme_bsd_bpf_eth_connection; 324: 325: /* if we need to call out new control information: */ 326: if (callouts & TME_BSD_BPF_CALLOUT_CTRL) { 327: 328: /* form the new ctrl: */ 329: ctrl = 0; 330: if (bpf->tme_bsd_bpf_buffer_offset 331: < bpf->tme_bsd_bpf_buffer_end) { 332: ctrl |= TME_ETHERNET_CTRL_OK_READ; 333: } 334: 335: /* unlock the mutex: */ 336: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); 337: 338: /* do the callout: */ 339: rc = (conn_eth != NULL 340: ? ((*conn_eth->tme_ethernet_connection_ctrl) 341: (conn_eth, 342: ctrl)) 343: : TME_OK); 344: 345: /* lock the mutex: */ 346: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 347: 348: /* if the callout was unsuccessful, remember that at some later 349: time this callout should be attempted again: */ 350: if (rc != TME_OK) { 351: later_callouts |= TME_BSD_BPF_CALLOUT_CTRL; 352: } 353: } 354: 355: /* if the Ethernet is readable: */ 356: if (callouts & TME_BSD_BPF_CALLOUT_READ) { 357: 358: /* unlock the mutex: */ 359: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); 360: 361: /* make a frame chunk to receive this frame: */ 362: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; 363: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes = frame; 364: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count 365: = sizeof(frame); 366: 367: /* do the callout: */ 368: rc = (conn_eth == NULL 369: ? TME_OK 370: : ((*conn_eth->tme_ethernet_connection_read) 371: (conn_eth, 372: &frame_id, 373: &frame_chunk_buffer, 374: TME_ETHERNET_READ_NEXT))); 375: 376: /* lock the mutex: */ 377: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 378: 379: /* if the read was successful: */ 380: if (rc > 0) { 381: 382: /* do the write: */ 383: tme_thread_write(bpf->tme_bsd_bpf_fd, frame, rc); 384: 385: /* mark that we need to loop to callout to read more frames: */ 386: bpf->tme_bsd_bpf_callout_flags |= TME_BSD_BPF_CALLOUT_READ; 387: } 388: 389: /* otherwise, the read failed. convention dictates that we 390: forget that the connection was readable, which we already 391: have done by clearing the CALLOUT_READ flag: */ 392: } 393: 394: } 395: 396: /* put in any later callouts, and clear that callouts are running: */ 397: bpf->tme_bsd_bpf_callout_flags = later_callouts; 398: } 399: 400: /* the BPF reader thread: */ 401: static void 402: _tme_bsd_bpf_th_reader(struct tme_bsd_bpf *bpf) 403: { 404: ssize_t buffer_end; 1.1.1.3 ! root 405: unsigned long sleep_usec; 1.1 root 406: 407: /* lock the mutex: */ 408: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 409: 410: /* loop forever: */ 411: for (;;) { 412: 1.1.1.3 ! root 413: /* if the delay sleeping flag is set: */ ! 414: if (bpf->tme_bsd_bpf_delay_sleeping) { ! 415: ! 416: /* clear the delay sleeping flag: */ ! 417: bpf->tme_bsd_bpf_delay_sleeping = FALSE; ! 418: ! 419: /* call out that we can be read again: */ ! 420: _tme_bsd_bpf_callout(bpf, TME_BSD_BPF_CALLOUT_CTRL); ! 421: } ! 422: ! 423: /* if a delay has been requested: */ ! 424: sleep_usec = bpf->tme_bsd_bpf_delay_sleep; ! 425: if (sleep_usec > 0) { ! 426: ! 427: /* clear the delay sleep time: */ ! 428: bpf->tme_bsd_bpf_delay_sleep = 0; ! 429: ! 430: /* set the delay sleeping flag: */ ! 431: bpf->tme_bsd_bpf_delay_sleeping = TRUE; ! 432: ! 433: /* unlock our mutex: */ ! 434: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); ! 435: ! 436: /* sleep for the delay sleep time: */ ! 437: tme_thread_sleep_yield(0, sleep_usec); ! 438: ! 439: /* lock our mutex: */ ! 440: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); ! 441: ! 442: continue; ! 443: } ! 444: ! 445: /* if the buffer is not empty, wait until either it is, ! 446: or we're asked to do a delay: */ 1.1 root 447: if (bpf->tme_bsd_bpf_buffer_offset 448: < bpf->tme_bsd_bpf_buffer_end) { 449: tme_cond_wait_yield(&bpf->tme_bsd_bpf_cond_reader, 450: &bpf->tme_bsd_bpf_mutex); 1.1.1.3 ! root 451: continue; 1.1 root 452: } 453: 454: /* unlock the mutex: */ 455: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); 456: 457: /* read the BPF socket: */ 458: tme_log(&bpf->tme_bsd_bpf_element->tme_element_log_handle, 1, TME_OK, 459: (&bpf->tme_bsd_bpf_element->tme_element_log_handle, 460: _("calling read"))); 461: buffer_end = 462: tme_thread_read_yield(bpf->tme_bsd_bpf_fd, 463: bpf->tme_bsd_bpf_buffer, 464: bpf->tme_bsd_bpf_buffer_size); 465: 466: /* lock the mutex: */ 467: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 468: 469: /* if the read failed: */ 470: if (buffer_end <= 0) { 471: tme_log(&bpf->tme_bsd_bpf_element->tme_element_log_handle, 1, errno, 472: (&bpf->tme_bsd_bpf_element->tme_element_log_handle, 473: _("failed to read packets"))); 474: continue; 475: } 476: 477: /* the read succeeded: */ 478: tme_log(&bpf->tme_bsd_bpf_element->tme_element_log_handle, 1, TME_OK, 479: (&bpf->tme_bsd_bpf_element->tme_element_log_handle, 480: _("read %ld bytes of packets"), (long) buffer_end)); 481: bpf->tme_bsd_bpf_buffer_offset = 0; 482: bpf->tme_bsd_bpf_buffer_end = buffer_end; 483: 484: /* call out that we can be read again: */ 485: _tme_bsd_bpf_callout(bpf, TME_BSD_BPF_CALLOUT_CTRL); 486: } 487: /* NOTREACHED */ 488: } 489: 490: /* this is called when the ethernet configuration changes: */ 491: static int 492: _tme_bsd_bpf_config(struct tme_ethernet_connection *conn_eth, 493: struct tme_ethernet_config *config) 494: { 495: struct tme_bsd_bpf *bpf; 496: struct bpf_insn *bpf_filter; 497: struct bpf_program program; 498: int bpf_filter_size, first_pc; 499: int rc; 500: 501: /* recover our data structures: */ 502: bpf = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; 503: 504: /* assume we will succeed: */ 505: rc = TME_OK; 506: 507: /* lock the mutex: */ 508: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 509: 510: /* allocate space for the worst-case filter: one insn for the packet 511: accept, one insn for the packet reject, and TME_ETHERNET_ADDR_SIZE 512: * 2 insns for each address - one insn to load an address byte and 513: one insn to test it and branch: */ 514: bpf_filter_size = (1 515: + 1 516: + ((1 + 1) 517: * TME_ETHERNET_ADDR_SIZE 518: * config->tme_ethernet_config_addr_count)); 519: bpf_filter = tme_new(struct bpf_insn, bpf_filter_size); 520: first_pc = bpf_filter_size; 521: 522: /* if this Ethernet is promiscuous, we will accept all packets: */ 523: if (config->tme_ethernet_config_flags & TME_ETHERNET_CONFIG_PROMISC) { 524: bpf_filter[--first_pc] = _tme_bsd_bpf_insn_accept; 525: } 526: 527: /* if this Ethernet does have a set of addresses, we will accept all 528: packets for one of those addresses: */ 529: else if (config->tme_ethernet_config_addr_count > 0) { 530: 531: /* the last insn in the filter is always the packet reject, 532: and the next-to-last insn in the filter is always the 533: packet accept. _tme_bsd_bpf_filter depends on this: */ 534: bpf_filter[--first_pc] = _tme_bsd_bpf_insn_reject; 535: bpf_filter[--first_pc] = _tme_bsd_bpf_insn_accept; 536: 537: /* make the address filter: */ 538: _tme_bsd_bpf_filter(config, 539: NULL, 540: 0, 541: bpf_filter, 542: bpf_filter_size, 543: &first_pc); 544: } 545: 546: /* otherwise this filter doesn't need to accept any packets: */ 547: else { 548: bpf_filter[--first_pc] = _tme_bsd_bpf_insn_reject; 549: } 550: 551: /* set the filter on the BPF device: */ 552: program.bf_len = bpf_filter_size - first_pc; 553: program.bf_insns = bpf_filter + first_pc; 554: if (ioctl(bpf->tme_bsd_bpf_fd, BIOCSETF, &program) < 0) { 555: tme_log(&bpf->tme_bsd_bpf_element->tme_element_log_handle, 1, errno, 556: (&bpf->tme_bsd_bpf_element->tme_element_log_handle, 557: _("failed to set the filter"))); 558: rc = errno; 559: } 560: 561: /* free the filter: */ 562: tme_free(bpf_filter); 563: 564: /* unlock the mutex: */ 565: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); 566: 567: /* done: */ 568: return (rc); 569: } 570: 571: /* this is called when control lines change: */ 572: static int 573: _tme_bsd_bpf_ctrl(struct tme_ethernet_connection *conn_eth, 574: unsigned int ctrl) 575: { 576: struct tme_bsd_bpf *bpf; 577: int new_callouts; 578: 579: /* recover our data structures: */ 580: bpf = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; 581: 582: /* assume that we won't need any new callouts: */ 583: new_callouts = 0; 584: 585: /* lock the mutex: */ 586: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 587: 588: /* if this connection is readable, call out a read: */ 589: if (ctrl & TME_ETHERNET_CTRL_OK_READ) { 590: new_callouts |= TME_BSD_BPF_CALLOUT_READ; 591: } 592: 593: /* make any new callouts: */ 594: _tme_bsd_bpf_callout(bpf, new_callouts); 595: 596: /* unlock the mutex: */ 597: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); 598: 599: return (TME_OK); 600: } 601: 602: /* this is called to read a frame: */ 603: static int 604: _tme_bsd_bpf_read(struct tme_ethernet_connection *conn_eth, 605: tme_ethernet_fid_t *_frame_id, 606: struct tme_ethernet_frame_chunk *frame_chunks, 607: unsigned int flags) 608: { 609: struct tme_bsd_bpf *bpf; 610: struct bpf_hdr the_bpf_header; 611: struct tme_ethernet_frame_chunk frame_chunk_buffer; 612: unsigned int count; 613: int rc; 614: 615: /* recover our data structure: */ 616: bpf = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; 617: 618: /* lock our mutex: */ 619: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 620: 621: /* assume that we won't be able to return a packet: */ 622: rc = -ENOENT; 623: 624: /* loop until we have a good captured packet or until we 625: exhaust the buffer: */ 626: for (;;) { 627: 628: /* if there's not enough for a BPF header, flush the buffer: */ 629: if ((bpf->tme_bsd_bpf_buffer_offset 630: + sizeof(the_bpf_header)) 631: > bpf->tme_bsd_bpf_buffer_end) { 632: tme_log(&bpf->tme_bsd_bpf_element->tme_element_log_handle, 1, TME_OK, 633: (&bpf->tme_bsd_bpf_element->tme_element_log_handle, 634: _("flushed garbage BPF header bytes"))); 635: bpf->tme_bsd_bpf_buffer_end = 0; 636: break; 637: } 638: 639: /* get the BPF header and check it: */ 640: memcpy(&the_bpf_header, 641: bpf->tme_bsd_bpf_buffer 642: + bpf->tme_bsd_bpf_buffer_offset, 643: sizeof(the_bpf_header)); 644: bpf->tme_bsd_bpf_buffer_offset += the_bpf_header.bh_hdrlen; 645: 646: /* if we're missing some part of the packet: */ 647: if (the_bpf_header.bh_caplen != the_bpf_header.bh_datalen 648: || ((bpf->tme_bsd_bpf_buffer_offset + the_bpf_header.bh_datalen) 649: > bpf->tme_bsd_bpf_buffer_end)) { 650: tme_log(&bpf->tme_bsd_bpf_element->tme_element_log_handle, 1, TME_OK, 651: (&bpf->tme_bsd_bpf_element->tme_element_log_handle, 652: _("flushed truncated BPF packet"))); 653: bpf->tme_bsd_bpf_buffer_offset += the_bpf_header.bh_datalen; 654: continue; 655: } 656: 657: /* if this packet isn't big enough to even have an Ethernet header: */ 658: if (the_bpf_header.bh_datalen < sizeof(struct tme_ethernet_header)) { 659: tme_log(&bpf->tme_bsd_bpf_element->tme_element_log_handle, 1, TME_OK, 660: (&bpf->tme_bsd_bpf_element->tme_element_log_handle, 661: _("flushed short BPF packet"))); 662: bpf->tme_bsd_bpf_buffer_offset += the_bpf_header.bh_datalen; 663: continue; 664: } 665: 1.1.1.3 ! root 666: /* if packets need to be delayed: */ ! 667: if (bpf->tme_bsd_bpf_delay_time > 0) { ! 668: ! 669: /* if the current release time is before this packet's time: */ ! 670: if ((bpf->tme_bsd_bpf_delay_release.tv_sec ! 671: < the_bpf_header.bh_tstamp.tv_sec) ! 672: || ((bpf->tme_bsd_bpf_delay_release.tv_sec ! 673: == the_bpf_header.bh_tstamp.tv_sec) ! 674: && (bpf->tme_bsd_bpf_delay_release.tv_usec ! 675: < the_bpf_header.bh_tstamp.tv_usec))) { ! 676: ! 677: /* update the current release time, by taking the current time ! 678: and subtracting the delay time: */ ! 679: gettimeofday(&bpf->tme_bsd_bpf_delay_release, NULL); ! 680: if (bpf->tme_bsd_bpf_delay_release.tv_usec < bpf->tme_bsd_bpf_delay_time) { ! 681: bpf->tme_bsd_bpf_delay_release.tv_usec += 1000000UL; ! 682: bpf->tme_bsd_bpf_delay_release.tv_sec--; ! 683: } ! 684: bpf->tme_bsd_bpf_delay_release.tv_usec -= bpf->tme_bsd_bpf_delay_time; ! 685: } ! 686: ! 687: /* if the current release time is still before this packet's ! 688: time: */ ! 689: if ((bpf->tme_bsd_bpf_delay_release.tv_sec ! 690: < the_bpf_header.bh_tstamp.tv_sec) ! 691: || ((bpf->tme_bsd_bpf_delay_release.tv_sec ! 692: == the_bpf_header.bh_tstamp.tv_sec) ! 693: && (bpf->tme_bsd_bpf_delay_release.tv_usec ! 694: < the_bpf_header.bh_tstamp.tv_usec))) { ! 695: ! 696: /* set the sleep time: */ ! 697: assert ((bpf->tme_bsd_bpf_delay_release.tv_sec ! 698: == the_bpf_header.bh_tstamp.tv_sec) ! 699: || ((bpf->tme_bsd_bpf_delay_release.tv_sec + 1) ! 700: == the_bpf_header.bh_tstamp.tv_sec)); ! 701: bpf->tme_bsd_bpf_delay_sleep ! 702: = (((bpf->tme_bsd_bpf_delay_release.tv_sec ! 703: == the_bpf_header.bh_tstamp.tv_sec) ! 704: ? 0 ! 705: : 1000000UL) ! 706: + the_bpf_header.bh_tstamp.tv_usec ! 707: - bpf->tme_bsd_bpf_delay_release.tv_usec); ! 708: ! 709: /* rewind the buffer pointer: */ ! 710: bpf->tme_bsd_bpf_buffer_offset -= the_bpf_header.bh_hdrlen; ! 711: ! 712: /* stop now: */ ! 713: break; ! 714: } ! 715: } ! 716: 1.1 root 717: /* form the single frame chunk: */ 718: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; 719: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes 720: = bpf->tme_bsd_bpf_buffer + bpf->tme_bsd_bpf_buffer_offset; 721: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count 722: = the_bpf_header.bh_datalen; 723: 724: /* copy out the frame: */ 725: count = tme_ethernet_chunks_copy(frame_chunks, &frame_chunk_buffer); 726: 1.1.1.3 ! root 727: /* if this is a peek: */ ! 728: if (flags & TME_ETHERNET_READ_PEEK) { ! 729: ! 730: /* rewind the buffer pointer: */ ! 731: bpf->tme_bsd_bpf_buffer_offset -= the_bpf_header.bh_hdrlen; ! 732: } ! 733: ! 734: /* otherwise, this isn't a peek: */ ! 735: else { 1.1 root 736: 737: /* update the buffer pointer: */ 738: bpf->tme_bsd_bpf_buffer_offset += the_bpf_header.bh_datalen; 739: } 740: 741: /* success: */ 742: rc = count; 743: break; 744: } 745: 1.1.1.3 ! root 746: /* if the buffer is empty, or if we failed to read a packet, ! 747: wake up the reader: */ ! 748: if ((bpf->tme_bsd_bpf_buffer_offset ! 749: >= bpf->tme_bsd_bpf_buffer_end) ! 750: || rc <= 0) { 1.1 root 751: tme_cond_notify(&bpf->tme_bsd_bpf_cond_reader, TRUE); 752: } 753: 754: /* unlock our mutex: */ 755: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); 756: 757: /* done: */ 758: return (rc); 759: } 760: 761: /* this makes a new Ethernet connection: */ 762: static int 763: _tme_bsd_bpf_connection_make(struct tme_connection *conn, unsigned int state) 764: { 765: struct tme_bsd_bpf *bpf; 766: struct tme_ethernet_connection *conn_eth; 767: struct tme_ethernet_connection *conn_eth_other; 768: 769: /* recover our data structures: */ 770: bpf = conn->tme_connection_element->tme_element_private; 771: conn_eth = (struct tme_ethernet_connection *) conn; 772: conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other; 773: 774: /* both sides must be Ethernet connections: */ 775: assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET); 776: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET); 777: 778: /* we're always set up to answer calls across the connection, so we 779: only have to do work when the connection has gone full, namely 780: taking the other side of the connection: */ 781: if (state == TME_CONNECTION_FULL) { 782: 783: /* lock our mutex: */ 784: tme_mutex_lock(&bpf->tme_bsd_bpf_mutex); 785: 786: /* save our connection: */ 787: bpf->tme_bsd_bpf_eth_connection = conn_eth_other; 788: 789: /* unlock our mutex: */ 790: tme_mutex_unlock(&bpf->tme_bsd_bpf_mutex); 791: } 792: 793: return (TME_OK); 794: } 795: 796: /* this breaks a connection: */ 797: static int 798: _tme_bsd_bpf_connection_break(struct tme_connection *conn, unsigned int state) 799: { 800: abort(); 801: } 802: 803: /* this makes a new connection side for a BPF: */ 804: static int 805: _tme_bsd_bpf_connections_new(struct tme_element *element, 806: const char * const *args, 807: struct tme_connection **_conns, 808: char **_output) 809: { 810: struct tme_bsd_bpf *bpf; 811: struct tme_ethernet_connection *conn_eth; 812: struct tme_connection *conn; 813: 814: /* recover our data structure: */ 815: bpf = (struct tme_bsd_bpf *) element->tme_element_private; 816: 817: /* if we already have an Ethernet connection, do nothing: */ 818: if (bpf->tme_bsd_bpf_eth_connection != NULL) { 819: return (TME_OK); 820: } 821: 822: /* allocate the new Ethernet connection: */ 823: conn_eth = tme_new0(struct tme_ethernet_connection, 1); 824: conn = &conn_eth->tme_ethernet_connection; 825: 826: /* fill in the generic connection: */ 827: conn->tme_connection_next = *_conns; 828: conn->tme_connection_type = TME_CONNECTION_ETHERNET; 829: conn->tme_connection_score = tme_ethernet_connection_score; 830: conn->tme_connection_make = _tme_bsd_bpf_connection_make; 831: conn->tme_connection_break = _tme_bsd_bpf_connection_break; 832: 833: /* fill in the Ethernet connection: */ 834: conn_eth->tme_ethernet_connection_config = _tme_bsd_bpf_config; 835: conn_eth->tme_ethernet_connection_ctrl = _tme_bsd_bpf_ctrl; 836: conn_eth->tme_ethernet_connection_read = _tme_bsd_bpf_read; 837: 838: /* return the connection side possibility: */ 839: *_conns = conn; 840: 841: /* done: */ 842: return (TME_OK); 843: } 844: 845: /* the new BPF function: */ 846: TME_ELEMENT_SUB_NEW_DECL(tme_host_bsd,bpf) { 847: struct tme_bsd_bpf *bpf; 848: int bpf_fd; 849: #define DEV_BPF_FORMAT "/dev/bpf%d" 850: char dev_bpf_filename[sizeof(DEV_BPF_FORMAT) + (sizeof(int) * 3) + 1]; 851: int minor; 852: int saved_errno; 853: u_int bpf_opt; 854: struct bpf_version version; 855: u_int packet_buffer_size; 856: const char *ifr_name_user; 857: struct ifreq *ifr; 1.1.1.3 ! root 858: unsigned long delay_time; 1.1 root 859: int arg_i; 860: int usage; 861: int rc; 862: 863: /* check our arguments: */ 864: usage = 0; 865: ifr_name_user = NULL; 1.1.1.3 ! root 866: delay_time = 0; 1.1 root 867: arg_i = 1; 868: for (;;) { 869: 870: /* the interface we're supposed to use: */ 871: if (TME_ARG_IS(args[arg_i + 0], "interface") 872: && args[arg_i + 1] != NULL) { 873: ifr_name_user = args[arg_i + 1]; 874: arg_i += 2; 875: } 876: 1.1.1.3 ! root 877: /* a delay time in microseconds: */ ! 878: else if (TME_ARG_IS(args[arg_i + 0], "delay") ! 879: && (delay_time = tme_misc_unumber_parse(args[arg_i + 1], 0)) > 0) { ! 880: arg_i += 2; ! 881: } ! 882: 1.1 root 883: /* if we ran out of arguments: */ 884: else if (args[arg_i + 0] == NULL) { 885: break; 886: } 887: 888: /* otherwise this is a bad argument: */ 889: else { 890: tme_output_append_error(_output, 891: "%s %s", 892: args[arg_i], 893: _("unexpected")); 894: usage = TRUE; 895: break; 896: } 897: } 898: 899: if (usage) { 900: tme_output_append_error(_output, 1.1.1.3 ! root 901: "%s %s [ interface %s ] [ delay %s ]", 1.1 root 902: _("usage:"), 903: args[0], 1.1.1.3 ! root 904: _("INTERFACE"), ! 905: _("MICROSECONDS")); 1.1 root 906: return (EINVAL); 907: } 908: 909: /* find the interface we will use: */ 910: rc = tme_bsd_if_find(ifr_name_user, &ifr, NULL, NULL); 911: if (rc != TME_OK) { 912: tme_output_append_error(_output, _("couldn't find an interface")); 913: return (ENOENT); 914: } 915: tme_log(&element->tme_element_log_handle, 1, TME_OK, 916: (&element->tme_element_log_handle, 917: "using interface %s", 918: ifr->ifr_name)); 919: 920: /* loop trying to open a /dev/bpf device: */ 921: for (minor = 0;; minor++) { 922: 923: /* form the name of the next device to try, then try opening 924: it. if we succeed, we're done: */ 925: sprintf(dev_bpf_filename, DEV_BPF_FORMAT, minor); 926: tme_log(&element->tme_element_log_handle, 1, TME_OK, 927: (&element->tme_element_log_handle, 928: "trying %s", 929: dev_bpf_filename)); 930: if ((bpf_fd = open(dev_bpf_filename, O_RDWR)) >= 0) { 931: tme_log(&element->tme_element_log_handle, 1, TME_OK, 932: (&element->tme_element_log_handle, 933: "opened %s", 934: dev_bpf_filename)); 935: break; 936: } 937: 938: /* we failed to open this device. if this device was simply 939: busy, loop: */ 940: saved_errno = errno; 941: tme_log(&element->tme_element_log_handle, 1, saved_errno, 942: (&element->tme_element_log_handle, 943: "%s", dev_bpf_filename)); 944: if (saved_errno == EBUSY 945: || saved_errno == EACCES) { 946: continue; 947: } 948: 949: /* otherwise, we have failed: */ 950: return (saved_errno); 951: } 952: 953: /* this macro helps in closing the BPF socket on error: */ 954: #define _TME_BPF_RAW_OPEN_ERROR(x) saved_errno = errno; x; errno = saved_errno 955: 956: /* check the BPF version: */ 957: if (ioctl(bpf_fd, BIOCVERSION, &version) < 0) { 958: tme_log(&element->tme_element_log_handle, 1, errno, 959: (&element->tme_element_log_handle, 960: _("failed to get the BPF version on %s"), 961: dev_bpf_filename)); 962: _TME_BPF_RAW_OPEN_ERROR(close(bpf_fd)); 963: return (errno); 964: } 965: if (version.bv_major != BPF_MAJOR_VERSION 966: || version.bv_minor < BPF_MINOR_VERSION) { 967: tme_log(&element->tme_element_log_handle, 1, errno, 968: (&element->tme_element_log_handle, 969: _("kernel BPF version is %d.%d, my BPF version is %d.%d"), 970: version.bv_major, version.bv_minor, 971: BPF_MAJOR_VERSION, BPF_MINOR_VERSION)); 972: close(bpf_fd); 973: return (ENXIO); 974: } 975: 976: /* put the BPF device into immediate mode: */ 977: bpf_opt = TRUE; 978: if (ioctl(bpf_fd, BIOCIMMEDIATE, &bpf_opt) < 0) { 979: tme_log(&element->tme_element_log_handle, 1, errno, 980: (&element->tme_element_log_handle, 981: _("failed to put %s into immediate mode"), 982: dev_bpf_filename)); 983: _TME_BPF_RAW_OPEN_ERROR(close(bpf_fd)); 984: return (errno); 985: } 986: 987: /* tell the BPF device we're providing complete Ethernet headers: */ 988: bpf_opt = TRUE; 989: if (ioctl(bpf_fd, BIOCSHDRCMPLT, &bpf_opt) < 0) { 990: tme_log(&element->tme_element_log_handle, 1, errno, 991: (&element->tme_element_log_handle, 992: _("failed to put %s into complete-headers mode"), 993: dev_bpf_filename)); 994: _TME_BPF_RAW_OPEN_ERROR(close(bpf_fd)); 995: return (errno); 996: } 997: 998: /* point the BPF device at the interface we're using: */ 999: if (ioctl(bpf_fd, BIOCSETIF, ifr) < 0) { 1000: tme_log(&element->tme_element_log_handle, 1, errno, 1001: (&element->tme_element_log_handle, 1002: _("failed to point BPF socket at %s"), 1003: ifr->ifr_name)); 1004: saved_errno = errno; 1005: close(bpf_fd); 1006: errno = saved_errno; 1007: return (errno); 1008: } 1009: 1010: /* get the BPF read buffer size: */ 1011: if (ioctl(bpf_fd, BIOCGBLEN, &packet_buffer_size) < 0) { 1012: tme_log(&element->tme_element_log_handle, 1, errno, 1013: (&element->tme_element_log_handle, 1014: _("failed to read the buffer size for %s"), 1015: dev_bpf_filename)); 1016: _TME_BPF_RAW_OPEN_ERROR(close(bpf_fd)); 1017: return (errno); 1018: } 1019: tme_log(&element->tme_element_log_handle, 1, errno, 1020: (&element->tme_element_log_handle, 1021: _("buffer size for %s is %u"), 1022: dev_bpf_filename, packet_buffer_size)); 1023: 1024: /* set the interface into promiscuous mode: */ 1025: if (ioctl(bpf_fd, BIOCPROMISC) < 0) { 1026: tme_log(&element->tme_element_log_handle, 1, errno, 1027: (&element->tme_element_log_handle, 1028: _("failed to set promiscuous mode on %s"), 1029: dev_bpf_filename)); 1030: _TME_BPF_RAW_OPEN_ERROR(close(bpf_fd)); 1031: return (errno); 1032: } 1033: 1034: /* start our data structure: */ 1035: bpf = tme_new0(struct tme_bsd_bpf, 1); 1036: bpf->tme_bsd_bpf_element = element; 1037: bpf->tme_bsd_bpf_fd = bpf_fd; 1038: bpf->tme_bsd_bpf_buffer_size = packet_buffer_size; 1039: bpf->tme_bsd_bpf_buffer = tme_new(tme_uint8_t, packet_buffer_size); 1.1.1.3 ! root 1040: bpf->tme_bsd_bpf_delay_time = delay_time; 1.1 root 1041: 1042: /* start the threads: */ 1043: tme_mutex_init(&bpf->tme_bsd_bpf_mutex); 1.1.1.3 ! root 1044: tme_cond_init(&bpf->tme_bsd_bpf_cond_reader); 1.1 root 1045: tme_thread_create((tme_thread_t) _tme_bsd_bpf_th_reader, bpf); 1046: 1047: /* fill the element: */ 1048: element->tme_element_private = bpf; 1049: element->tme_element_connections_new = _tme_bsd_bpf_connections_new; 1050: 1051: return (TME_OK); 1052: #undef _TME_BPF_RAW_OPEN_ERROR 1053: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.