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>