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>