File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_bpf.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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 "network.h"
   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;
  305:   ssize_t written;
  306:   size_t buflen;
  307: 
  308:   buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
  309:   if (buflen > sizeof (sock_buff))
  310:     {
  311:       zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than "
  312: 		 "output pdu size %zu on circuit %s",
  313: 		 sizeof (sock_buff), buflen, circuit->interface->name);
  314:       return ISIS_WARNING;
  315:     }
  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 */
  342:   written = write (circuit->fd, sock_buff, buflen);
  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:     }
  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>