Annotation of tme/host/bsd/bsd-bpf.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.