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