Annotation of embedaddon/quagga/isisd/isis_bpf.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * IS-IS Rout(e)ing protocol - isis_bpf.c
                      3:  *
                      4:  * Copyright (C) 2001,2002    Sampo Saaristo
                      5:  *                            Tampere University of Technology      
                      6:  *                            Institute of Communications Engineering
                      7:  *
                      8:  * This program is free software; you can redistribute it and/or modify it 
                      9:  * under the terms of the GNU General Public Licenseas published by the Free 
                     10:  * Software Foundation; either version 2 of the License, or (at your option) 
                     11:  * any later version.
                     12:  *
                     13:  * This program is distributed in the hope that it will be useful,but WITHOUT 
                     14:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
                     15:  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
                     16:  * more details.
                     17: 
                     18:  * You should have received a copy of the GNU General Public License along 
                     19:  * with this program; if not, write to the Free Software Foundation, Inc., 
                     20:  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
                     21:  */
                     22: 
                     23: #include <zebra.h>
                     24: #if ISIS_METHOD == ISIS_METHOD_BPF
                     25: #include <net/if.h>
                     26: #include <netinet/if_ether.h>
                     27: #include <sys/time.h>
                     28: #include <sys/ioctl.h>
                     29: #include <net/bpf.h>
                     30: 
                     31: #include "log.h"
                     32: #include "stream.h"
                     33: #include "if.h"
                     34: 
                     35: #include "isisd/dict.h"
                     36: #include "isisd/include-netbsd/iso.h"
                     37: #include "isisd/isis_constants.h"
                     38: #include "isisd/isis_common.h"
                     39: #include "isisd/isis_circuit.h"
                     40: #include "isisd/isis_flags.h"
                     41: #include "isisd/isisd.h"
                     42: #include "isisd/isis_constants.h"
                     43: #include "isisd/isis_circuit.h"
                     44: #include "isisd/isis_network.h"
                     45: 
                     46: #include "privs.h"
                     47: 
                     48: extern struct zebra_privs_t isisd_privs;
                     49: 
                     50: struct bpf_insn llcfilter[] = {
                     51:   BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN),  /* check first byte */
                     52:   BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5),
                     53:   BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1),
                     54:   BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3), /* check second byte */
                     55:   BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2),
                     56:   BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1),    /* check third byte */
                     57:   BPF_STMT (BPF_RET + BPF_K, (u_int) - 1),
                     58:   BPF_STMT (BPF_RET + BPF_K, 0)
                     59: };
                     60: u_int readblen = 0;
                     61: u_char *readbuff = NULL;
                     62: 
                     63: /*
                     64:  * Table 9 - Architectural constants for use with ISO 8802 subnetworks
                     65:  * ISO 10589 - 8.4.8
                     66:  */
                     67: 
                     68: u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
                     69: u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
                     70: u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
                     71: u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
                     72: 
                     73: static char sock_buff[8192];
                     74: 
                     75: static int
                     76: open_bpf_dev (struct isis_circuit *circuit)
                     77: {
                     78:   int i = 0, fd;
                     79:   char bpfdev[128];
                     80:   struct ifreq ifr;
                     81:   u_int blen, immediate, seesent;
                     82:   struct timeval timeout;
                     83:   struct bpf_program bpf_prog;
                     84: 
                     85:   do
                     86:     {
                     87:       (void) snprintf (bpfdev, sizeof (bpfdev), "/dev/bpf%d", i++);
                     88:       fd = open (bpfdev, O_RDWR);
                     89:     }
                     90:   while (fd < 0 && errno == EBUSY);
                     91: 
                     92:   if (fd < 0)
                     93:     {
                     94:       zlog_warn ("open_bpf_dev(): failed to create bpf socket: %s",
                     95:                 safe_strerror (errno));
                     96:       return ISIS_WARNING;
                     97:     }
                     98: 
                     99:   zlog_debug ("Opened BPF device %s", bpfdev);
                    100: 
                    101:   memcpy (ifr.ifr_name, circuit->interface->name, sizeof (ifr.ifr_name));
                    102:   if (ioctl (fd, BIOCSETIF, (caddr_t) & ifr) < 0)
                    103:     {
                    104:       zlog_warn ("open_bpf_dev(): failed to bind to interface: %s",
                    105:                 safe_strerror (errno));
                    106:       return ISIS_WARNING;
                    107:     }
                    108: 
                    109:   if (ioctl (fd, BIOCGBLEN, (caddr_t) & blen) < 0)
                    110:     {
                    111:       zlog_warn ("failed to get BPF buffer len");
                    112:       blen = circuit->interface->mtu;
                    113:     }
                    114: 
                    115:   readblen = blen;
                    116: 
                    117:   if (readbuff == NULL)
                    118:     readbuff = malloc (blen);
                    119: 
                    120:   zlog_debug ("BPF buffer len = %u", blen);
                    121: 
                    122:   /*  BPF(4): reads return immediately upon packet reception.
                    123:    *  Otherwise, a read will block until either the kernel
                    124:    *  buffer becomes full or a timeout occurs. 
                    125:    */
                    126:   immediate = 1;
                    127:   if (ioctl (fd, BIOCIMMEDIATE, (caddr_t) & immediate) < 0)
                    128:     {
                    129:       zlog_warn ("failed to set BPF dev to immediate mode");
                    130:     }
                    131: 
                    132: #ifdef BIOCSSEESENT
                    133:   /*
                    134:    * We want to see only incoming packets
                    135:    */
                    136:   seesent = 0;
                    137:   if (ioctl (fd, BIOCSSEESENT, (caddr_t) & seesent) < 0)
                    138:     {
                    139:       zlog_warn ("failed to set BPF dev to incoming only mode");
                    140:     }
                    141: #endif
                    142: 
                    143:   /*
                    144:    * ...but all of them
                    145:    */
                    146:   if (ioctl (fd, BIOCPROMISC) < 0)
                    147:     {
                    148:       zlog_warn ("failed to set BPF dev to promiscuous mode");
                    149:     }
                    150: 
                    151:   /*
                    152:    * If the buffer length is smaller than our mtu, lets try to increase it
                    153:    */
                    154:   if (blen < circuit->interface->mtu)
                    155:     {
                    156:       if (ioctl (fd, BIOCSBLEN, &circuit->interface->mtu) < 0)
                    157:        {
                    158:          zlog_warn ("failed to set BPF buffer len (%u to %u)", blen,
                    159:                     circuit->interface->mtu);
                    160:        }
                    161:     }
                    162: 
                    163:   /*
                    164:    * Set a timeout parameter - hope this helps select()
                    165:    */
                    166:   timeout.tv_sec = 600;
                    167:   timeout.tv_usec = 0;
                    168:   if (ioctl (fd, BIOCSRTIMEOUT, (caddr_t) & timeout) < 0)
                    169:     {
                    170:       zlog_warn ("failed to set BPF device timeout");
                    171:     }
                    172: 
                    173:   /*
                    174:    * And set the filter
                    175:    */
                    176:   memset (&bpf_prog, 0, sizeof (struct bpf_program));
                    177:   bpf_prog.bf_len = 8;
                    178:   bpf_prog.bf_insns = &(llcfilter[0]);
                    179:   if (ioctl (fd, BIOCSETF, (caddr_t) & bpf_prog) < 0)
                    180:     {
                    181:       zlog_warn ("open_bpf_dev(): failed to install filter: %s",
                    182:                 safe_strerror (errno));
                    183:       return ISIS_WARNING;
                    184:     }
                    185: 
                    186:   assert (fd > 0);
                    187: 
                    188:   circuit->fd = fd;
                    189: 
                    190:   return ISIS_OK;
                    191: }
                    192: 
                    193: /*
                    194:  * Create the socket and set the tx/rx funcs
                    195:  */
                    196: int
                    197: isis_sock_init (struct isis_circuit *circuit)
                    198: {
                    199:   int retval = ISIS_OK;
                    200: 
                    201:   if (isisd_privs.change (ZPRIVS_RAISE))
                    202:     zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
                    203: 
                    204:   retval = open_bpf_dev (circuit);
                    205: 
                    206:   if (retval != ISIS_OK)
                    207:     {
                    208:       zlog_warn ("%s: could not initialize the socket", __func__);
                    209:       goto end;
                    210:     }
                    211: 
                    212:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
                    213:     {
                    214:       circuit->tx = isis_send_pdu_bcast;
                    215:       circuit->rx = isis_recv_pdu_bcast;
                    216:     }
                    217:   else if (circuit->circ_type == CIRCUIT_T_P2P)
                    218:     {
                    219:       circuit->tx = isis_send_pdu_p2p;
                    220:       circuit->rx = isis_recv_pdu_p2p;
                    221:     }
                    222:   else
                    223:     {
                    224:       zlog_warn ("isis_sock_init(): unknown circuit type");
                    225:       retval = ISIS_WARNING;
                    226:       goto end;
                    227:     }
                    228: 
                    229: end:
                    230:   if (isisd_privs.change (ZPRIVS_LOWER))
                    231:     zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
                    232: 
                    233:   return retval;
                    234: }
                    235: 
                    236: int
                    237: isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
                    238: {
                    239:   int bytesread = 0, bytestoread, offset, one = 1;
                    240:   struct bpf_hdr *bpf_hdr;
                    241: 
                    242:   assert (circuit->fd > 0);
                    243: 
                    244:   if (ioctl (circuit->fd, FIONREAD, (caddr_t) & bytestoread) < 0)
                    245:     {
                    246:       zlog_warn ("ioctl() FIONREAD failed: %s", safe_strerror (errno));
                    247:     }
                    248: 
                    249:   if (bytestoread)
                    250:     {
                    251:       bytesread = read (circuit->fd, readbuff, readblen);
                    252:     }
                    253:   if (bytesread < 0)
                    254:     {
                    255:       zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s",
                    256:                 safe_strerror (errno));
                    257:       return ISIS_WARNING;
                    258:     }
                    259: 
                    260:   if (bytesread == 0)
                    261:     return ISIS_WARNING;
                    262: 
                    263:   bpf_hdr = (struct bpf_hdr *) readbuff;
                    264: 
                    265:   assert (bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
                    266: 
                    267:   offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
                    268: 
                    269:   /* then we lose the BPF, LLC and ethernet headers */
                    270:   stream_write (circuit->rcv_stream, readbuff + offset, 
                    271:                 bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
                    272:   stream_set_getp (circuit->rcv_stream, 0);
                    273: 
                    274:   memcpy (ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN,
                    275:          ETHER_ADDR_LEN);
                    276: 
                    277:   if (ioctl (circuit->fd, BIOCFLUSH, &one) < 0)
                    278:     zlog_warn ("Flushing failed: %s", safe_strerror (errno));
                    279: 
                    280:   return ISIS_OK;
                    281: }
                    282: 
                    283: int
                    284: isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
                    285: {
                    286:   int bytesread;
                    287: 
                    288:   bytesread = stream_read (circuit->rcv_stream, circuit->fd, 
                    289:                            circuit->interface->mtu);
                    290: 
                    291:   if (bytesread < 0)
                    292:     {
                    293:       zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
                    294:       return ISIS_WARNING;
                    295:     }
                    296: 
                    297:   return ISIS_OK;
                    298: }
                    299: 
                    300: int
                    301: isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
                    302: {
                    303:   struct ether_header *eth;
                    304:   int written;
                    305: 
                    306:   stream_set_getp (circuit->snd_stream, 0);
                    307: 
                    308:   /*
                    309:    * First the eth header
                    310:    */
                    311:   eth = (struct ether_header *) sock_buff;
                    312:   if (level == 1)
                    313:     memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN);
                    314:   else
                    315:     memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
                    316:   memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
                    317:   eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
                    318: 
                    319:   /*
                    320:    * Then the LLC
                    321:    */
                    322:   sock_buff[ETHER_HDR_LEN] = ISO_SAP;
                    323:   sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
                    324:   sock_buff[ETHER_HDR_LEN + 2] = 0x03;
                    325: 
                    326:   /* then we copy the data */
                    327:   memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
                    328:          stream_get_endp (circuit->snd_stream));
                    329: 
                    330:   /* now we can send this */
                    331:   written = write (circuit->fd, sock_buff,
                    332:                   stream_get_endp (circuit->snd_stream) 
                    333:                    + LLC_LEN + ETHER_HDR_LEN);
                    334: 
                    335:   return ISIS_OK;
                    336: }
                    337: 
                    338: int
                    339: isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
                    340: {
                    341:   return ISIS_OK;
                    342: }
                    343: 
                    344: #endif /* ISIS_METHOD == ISIS_METHOD_BPF */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>