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

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

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