Annotation of embedaddon/quagga/isisd/isis_bpf.c, revision 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>