summaryrefslogtreecommitdiffstats
path: root/lib/libpcap
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1995-01-20 04:13:07 +0000
committerjkh <jkh@FreeBSD.org>1995-01-20 04:13:07 +0000
commit92a97f198be3fb322c5ee6f5bc5443a05b713b57 (patch)
treee20b1b84001d0bfa407f612304872ad7460e3f9f /lib/libpcap
downloadFreeBSD-src-92a97f198be3fb322c5ee6f5bc5443a05b713b57.zip
FreeBSD-src-92a97f198be3fb322c5ee6f5bc5443a05b713b57.tar.gz
Add the Packet Capture Library from Michael Reifenberger.
Submitted by: mr
Diffstat (limited to 'lib/libpcap')
-rw-r--r--lib/libpcap/bpf_filter.c550
-rw-r--r--lib/libpcap/bpf_image.c284
-rw-r--r--lib/libpcap/etherent.c148
-rw-r--r--lib/libpcap/ethertype.h74
-rw-r--r--lib/libpcap/gencode.c1755
-rw-r--r--lib/libpcap/gencode.h173
-rw-r--r--lib/libpcap/grammar.y264
-rw-r--r--lib/libpcap/inet.c196
-rw-r--r--lib/libpcap/nametoaddr.c357
-rw-r--r--lib/libpcap/optimize.c1923
-rw-r--r--lib/libpcap/pcap-bpf.c233
-rw-r--r--lib/libpcap/pcap-dlpi.c506
-rw-r--r--lib/libpcap/pcap-enet.c227
-rw-r--r--lib/libpcap/pcap-int.h98
-rw-r--r--lib/libpcap/pcap-namedb.h76
-rw-r--r--lib/libpcap/pcap-nit.c240
-rw-r--r--lib/libpcap/pcap-nit.h19
-rw-r--r--lib/libpcap/pcap-pf.c310
-rw-r--r--lib/libpcap/pcap-pf.h19
-rw-r--r--lib/libpcap/pcap-snit.c293
-rw-r--r--lib/libpcap/pcap-snoop.c195
-rw-r--r--lib/libpcap/pcap.3323
-rw-r--r--lib/libpcap/pcap.c180
-rw-r--r--lib/libpcap/pcap.h137
-rw-r--r--lib/libpcap/savefile.c285
-rw-r--r--lib/libpcap/scanner.l193
26 files changed, 9058 insertions, 0 deletions
diff --git a/lib/libpcap/bpf_filter.c b/lib/libpcap/bpf_filter.c
new file mode 100644
index 0000000..5baa552
--- /dev/null
+++ b/lib/libpcap/bpf_filter.c
@@ -0,0 +1,550 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.c 7.5 (Berkeley) 7/15/91
+ *
+ * static char rcsid[] =
+ * "$Header: bpf_filter.c,v 1.22 94/06/05 20:12:39 leres Exp $";
+ */
+#if !(defined(lint) || defined(KERNEL))
+static char rcsid[] =
+ "@(#) $Header: bpf_filter.c,v 1.22 94/06/05 20:12:39 leres Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#if defined(__alpha)
+typedef int int32;
+typedef u_int u_int32;
+#else
+typedef long int32;
+typedef u_long u_int32;
+#endif
+
+#ifdef sun
+#include <netinet/in.h>
+#endif
+
+#if defined(sparc) || defined(mips) || defined(ibm032) || defined(__alpha)
+#define BPF_ALIGN
+#endif
+
+#ifndef BPF_ALIGN
+#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p))
+#else
+#define EXTRACT_SHORT(p)\
+ ((u_short)\
+ ((u_short)*((u_char *)p+0)<<8|\
+ (u_short)*((u_char *)p+1)<<0))
+#define EXTRACT_LONG(p)\
+ ((u_int32)*((u_char *)p+0)<<24|\
+ (u_int32)*((u_char *)p+1)<<16|\
+ (u_int32)*((u_char *)p+2)<<8|\
+ (u_int32)*((u_char *)p+3)<<0)
+#endif
+
+#ifdef KERNEL
+#include <sys/mbuf.h>
+#define MINDEX(m, k) \
+{ \
+ register int len = m->m_len; \
+ \
+ while (k >= len) { \
+ k -= len; \
+ m = m->m_next; \
+ if (m == 0) \
+ return 0; \
+ len = m->m_len; \
+ } \
+}
+
+static int
+m_xword(m, k, err)
+ register struct mbuf *m;
+ register int k, *err;
+{
+ register int len;
+ register u_char *cp, *np;
+ register struct mbuf *m0;
+
+ len = m->m_len;
+ while (k >= len) {
+ k -= len;
+ m = m->m_next;
+ if (m == 0)
+ goto bad;
+ len = m->m_len;
+ }
+ cp = mtod(m, u_char *) + k;
+ if (len - k >= 4) {
+ *err = 0;
+ return EXTRACT_LONG(cp);
+ }
+ m0 = m->m_next;
+ if (m0 == 0 || m0->m_len + len - k < 4)
+ goto bad;
+ *err = 0;
+ np = mtod(m0, u_char *);
+ switch (len - k) {
+
+ case 1:
+ return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
+
+ case 2:
+ return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) |
+ np[1];
+
+ default:
+ return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) |
+ np[0];
+ }
+ bad:
+ *err = 1;
+ return 0;
+}
+
+static int
+m_xhalf(m, k, err)
+ register struct mbuf *m;
+ register int k, *err;
+{
+ register int len;
+ register u_char *cp;
+ register struct mbuf *m0;
+
+ len = m->m_len;
+ while (k >= len) {
+ k -= len;
+ m = m->m_next;
+ if (m == 0)
+ goto bad;
+ len = m->m_len;
+ }
+ cp = mtod(m, u_char *) + k;
+ if (len - k >= 2) {
+ *err = 0;
+ return EXTRACT_SHORT(cp);
+ }
+ m0 = m->m_next;
+ if (m0 == 0)
+ goto bad;
+ *err = 0;
+ return (cp[k] << 8) | mtod(m0, u_char *)[0];
+ bad:
+ *err = 1;
+ return 0;
+}
+#endif
+
+/*
+ * Execute the filter program starting at pc on the packet p
+ * wirelen is the length of the original packet
+ * buflen is the amount of data present
+ */
+u_int
+bpf_filter(pc, p, wirelen, buflen)
+ register struct bpf_insn *pc;
+ register u_char *p;
+ u_int wirelen;
+ register u_int buflen;
+{
+ register u_int32 A, X;
+ register int k;
+ int32 mem[BPF_MEMWORDS];
+
+ if (pc == 0)
+ /*
+ * No filter means accept all.
+ */
+ return (u_int)-1;
+#ifdef lint
+ A = 0;
+ X = 0;
+#endif
+ --pc;
+ while (1) {
+ ++pc;
+ switch (pc->code) {
+
+ default:
+#ifdef KERNEL
+ return 0;
+#else
+ abort();
+#endif
+ case BPF_RET|BPF_K:
+ return (u_int)pc->k;
+
+ case BPF_RET|BPF_A:
+ return (u_int)A;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ k = pc->k;
+ if (k + sizeof(int32) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xword((struct mbuf *)p, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = EXTRACT_LONG(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ k = pc->k;
+ if (k + sizeof(short) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xhalf((struct mbuf *)p, k, &merr);
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ k = pc->k;
+ if (k >= buflen) {
+#ifdef KERNEL
+ register struct mbuf *m;
+
+ if (buflen != 0)
+ return 0;
+ m = (struct mbuf *)p;
+ MINDEX(m, k);
+ A = mtod(m, u_char *)[k];
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = p[k];
+ continue;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ A = wirelen;
+ continue;
+
+ case BPF_LDX|BPF_W|BPF_LEN:
+ X = wirelen;
+ continue;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ k = X + pc->k;
+ if (k + sizeof(int32) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xword((struct mbuf *)p, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = EXTRACT_LONG(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ k = X + pc->k;
+ if (k + sizeof(short) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xhalf((struct mbuf *)p, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ k = X + pc->k;
+ if (k >= buflen) {
+#ifdef KERNEL
+ register struct mbuf *m;
+
+ if (buflen != 0)
+ return 0;
+ m = (struct mbuf *)p;
+ MINDEX(m, k);
+ A = mtod(m, char *)[k];
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = p[k];
+ continue;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ k = pc->k;
+ if (k >= buflen) {
+#ifdef KERNEL
+ register struct mbuf *m;
+
+ if (buflen != 0)
+ return 0;
+ m = (struct mbuf *)p;
+ MINDEX(m, k);
+ X = (mtod(m, char *)[k] & 0xf) << 2;
+ continue;
+#else
+ return 0;
+#endif
+ }
+ X = (p[pc->k] & 0xf) << 2;
+ continue;
+
+ case BPF_LD|BPF_IMM:
+ A = pc->k;
+ continue;
+
+ case BPF_LDX|BPF_IMM:
+ X = pc->k;
+ continue;
+
+ case BPF_LD|BPF_MEM:
+ A = mem[pc->k];
+ continue;
+
+ case BPF_LDX|BPF_MEM:
+ X = mem[pc->k];
+ continue;
+
+ case BPF_ST:
+ mem[pc->k] = A;
+ continue;
+
+ case BPF_STX:
+ mem[pc->k] = X;
+ continue;
+
+ case BPF_JMP|BPF_JA:
+ pc += pc->k;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ pc += (A > pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ pc += (A >= pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ pc += (A == pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ pc += (A & pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ pc += (A > X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ pc += (A >= X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ pc += (A == X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ pc += (A & X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ A += X;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ A -= X;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ A *= X;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ if (X == 0)
+ return 0;
+ A /= X;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ A &= X;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ A |= X;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ A <<= X;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ A >>= X;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ A += pc->k;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ A -= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ A *= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ A /= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ A &= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ A |= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ A <<= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ A >>= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_NEG:
+ A = -A;
+ continue;
+
+ case BPF_MISC|BPF_TAX:
+ X = A;
+ continue;
+
+ case BPF_MISC|BPF_TXA:
+ A = X;
+ continue;
+ }
+ }
+}
+
+#ifdef KERNEL
+/*
+ * Return true if the 'fcode' is a valid filter program.
+ * The constraints are that each jump be forward and to a valid
+ * code. The code must terminate with either an accept or reject.
+ * 'valid' is an array for use by the routine (it must be at least
+ * 'len' bytes long).
+ *
+ * The kernel needs to be able to verify an application's filter code.
+ * Otherwise, a bogus program could easily crash the system.
+ */
+int
+bpf_validate(f, len)
+ struct bpf_insn *f;
+ int len;
+{
+ register int i;
+ register struct bpf_insn *p;
+
+ for (i = 0; i < len; ++i) {
+ /*
+ * Check that that jumps are forward, and within
+ * the code block.
+ */
+ p = &f[i];
+ if (BPF_CLASS(p->code) == BPF_JMP) {
+ register int from = i + 1;
+
+ if (BPF_OP(p->code) == BPF_JA) {
+ if (from + p->k >= len)
+ return 0;
+ }
+ else if (from + p->jt >= len || from + p->jf >= len)
+ return 0;
+ }
+ /*
+ * Check that memory operations use valid addresses.
+ */
+ if ((BPF_CLASS(p->code) == BPF_ST ||
+ (BPF_CLASS(p->code) == BPF_LD &&
+ (p->code & 0xe0) == BPF_MEM)) &&
+ (p->k >= BPF_MEMWORDS || p->k < 0))
+ return 0;
+ /*
+ * Check for constant division by 0.
+ */
+ if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
+ return 0;
+ }
+ return BPF_CLASS(f[len - 1].code) == BPF_RET;
+}
+#endif
diff --git a/lib/libpcap/bpf_image.c b/lib/libpcap/bpf_image.c
new file mode 100644
index 0000000..e86fa85
--- /dev/null
+++ b/lib/libpcap/bpf_image.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: bpf_image.c,v 1.12 94/01/31 03:22:34 leres Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <net/bpf.h>
+
+#include <pcap.h>
+#include <stdio.h>
+#include <string.h>
+
+char *
+bpf_image(p, n)
+ struct bpf_insn *p;
+ int n;
+{
+ int v;
+ char *fmt, *op;
+ static char image[256];
+ char operand[64];
+
+ v = p->k;
+ switch (p->code) {
+
+ default:
+ op = "unimp";
+ fmt = "0x%x";
+ v = p->code;
+ break;
+
+ case BPF_RET|BPF_K:
+ op = "ret";
+ fmt = "#%d";
+ break;
+
+ case BPF_RET|BPF_A:
+ op = "ret";
+ fmt = "";
+ break;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ op = "ld";
+ fmt = "[%d]";
+ break;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ op = "ldh";
+ fmt = "[%d]";
+ break;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ op = "ldb";
+ fmt = "[%d]";
+ break;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ op = "ld";
+ fmt = "#pktlen";
+ break;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ op = "ld";
+ fmt = "[x + %d]";
+ break;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ op = "ldh";
+ fmt = "[x + %d]";
+ break;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ op = "ldb";
+ fmt = "[x + %d]";
+ break;
+
+ case BPF_LD|BPF_IMM:
+ op = "ld";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_LDX|BPF_IMM:
+ op = "ldx";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ op = "ldxb";
+ fmt = "4*([%d]&0xf)";
+ break;
+
+ case BPF_LD|BPF_MEM:
+ op = "ld";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_LDX|BPF_MEM:
+ op = "ldx";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_ST:
+ op = "st";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_STX:
+ op = "stx";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_JMP|BPF_JA:
+ op = "ja";
+ fmt = "%d";
+ v = n + p->k;
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ op = "jgt";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ op = "jge";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ op = "jeq";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ op = "jset";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ op = "jgt";
+ fmt = "x";
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ op = "jge";
+ fmt = "x";
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ op = "jeq";
+ fmt = "x";
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ op = "jset";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ op = "add";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ op = "sub";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ op = "mul";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ op = "div";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ op = "and";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ op = "or";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ op = "lsh";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ op = "rsh";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ op = "add";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ op = "sub";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ op = "mul";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ op = "div";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ op = "and";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ op = "or";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ op = "lsh";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ op = "rsh";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_NEG:
+ op = "neg";
+ fmt = "";
+ break;
+
+ case BPF_MISC|BPF_TAX:
+ op = "tax";
+ fmt = "";
+ break;
+
+ case BPF_MISC|BPF_TXA:
+ op = "txa";
+ fmt = "";
+ break;
+ }
+ (void)sprintf(operand, fmt, v);
+ (void)sprintf(image,
+ (BPF_CLASS(p->code) == BPF_JMP &&
+ BPF_OP(p->code) != BPF_JA) ?
+ "(%03d) %-8s %-16s jt %d\tjf %d"
+ : "(%03d) %-8s %s",
+ n, op, operand, n + 1 + p->jt, n + 1 + p->jf);
+ return image;
+}
diff --git a/lib/libpcap/etherent.c b/lib/libpcap/etherent.c
new file mode 100644
index 0000000..7045f3d
--- /dev/null
+++ b/lib/libpcap/etherent.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: etherent.c,v 1.8 94/06/20 19:07:50 leres Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <pcap.h>
+#include <pcap-namedb.h>
+#include <stdio.h>
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+static inline int xdtoi(int);
+static inline int skip_space(FILE *);
+static inline int skip_line(FILE *);
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+ register int c;
+{
+ if (isdigit(c))
+ return c - '0';
+ else if (islower(c))
+ return c - 'a' + 10;
+ else
+ return c - 'A' + 10;
+}
+
+static inline int
+skip_space(f)
+ FILE *f;
+{
+ int c;
+
+ do {
+ c = getc(f);
+ } while (isspace(c) && c != '\n');
+
+ return c;
+}
+
+static inline int
+skip_line(f)
+ FILE *f;
+{
+ int c;
+
+ do
+ c = getc(f);
+ while (c != '\n' && c != EOF);
+
+ return c;
+}
+
+struct pcap_etherent *
+pcap_next_etherent(FILE *fp)
+{
+ register int c, d, i;
+ char *bp;
+ static struct pcap_etherent e;
+ static int nline = 1;
+ top:
+ while (nline) {
+ /* Find addr */
+ c = skip_space(fp);
+ if (c == '\n')
+ continue;
+ /* If this is a comment, or first thing on line
+ cannot be ethernet address, skip the line. */
+ else if (!isxdigit(c))
+ c = skip_line(fp);
+ else {
+ /* must be the start of an address */
+ for (i = 0; i < 6; i += 1) {
+ d = xdtoi(c);
+ c = getc(fp);
+ if (c != ':') {
+ d <<= 4;
+ d |= xdtoi(c);
+ c = getc(fp);
+ }
+ e.addr[i] = d;
+ if (c != ':')
+ break;
+ c = getc(fp);
+ }
+ nline = 0;
+ }
+ if (c == EOF)
+ return 0;
+ }
+
+ /* If we started a new line, 'c' holds the char past the ether addr,
+ which we assume is white space. If we are continuing a line,
+ 'c' is garbage. In either case, we can throw it away. */
+
+ c = skip_space(fp);
+ if (c == '\n') {
+ nline = 1;
+ goto top;
+ }
+ else if (c == '#') {
+ (void)skip_line(fp);
+ nline = 1;
+ goto top;
+ }
+ else if (c == EOF)
+ return 0;
+
+ /* Must be a name. */
+ bp = e.name;
+ /* Use 'd' to prevent buffer overflow. */
+ d = sizeof(e.name) - 1;
+ do {
+ *bp++ = c;
+ c = getc(fp);
+ } while (!isspace(c) && c != EOF && --d > 0);
+ *bp = '\0';
+ if (c == '\n')
+ nline = 1;
+
+ return &e;
+}
diff --git a/lib/libpcap/ethertype.h b/lib/libpcap/ethertype.h
new file mode 100644
index 0000000..37f6920
--- /dev/null
+++ b/lib/libpcap/ethertype.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: ethertype.h,v 1.2 94/06/14 20:03:27 leres Exp $ (LBL)
+ */
+
+/* Map between Ethernet protocol types and names */
+
+/* Add other Ethernet packet types here */
+#ifndef ETHERTYPE_SPRITE
+#define ETHERTYPE_SPRITE 0x0500
+#endif
+#ifndef ETHERTYPE_MOPDL
+#define ETHERTYPE_MOPDL 0x6001
+#endif
+#ifndef ETHERTYPE_MOPRC
+#define ETHERTYPE_MOPRC 0x6002
+#endif
+#ifndef ETHERTYPE_DN
+#define ETHERTYPE_DN 0x6003
+#endif
+#ifndef ETHERTYPE_LAT
+#define ETHERTYPE_LAT 0x6004
+#endif
+#ifndef ETHERTYPE_LANBRIDGE
+#define ETHERTYPE_LANBRIDGE 0x8038
+#endif
+#ifndef ETHERTYPE_DECDNS
+#define ETHERTYPE_DECDNS 0x803c
+#endif
+#ifndef ETHERTYPE_DECDTS
+#define ETHERTYPE_DECDTS 0x803e
+#endif
+#ifndef ETHERTYPE_VEXP
+#define ETHERTYPE_VEXP 0x805b
+#endif
+#ifndef ETHERTYPE_VPROD
+#define ETHERTYPE_VPROD 0x805c
+#endif
+#ifndef ETHERTYPE_LOOPBACK
+#define ETHERTYPE_LOOPBACK 0x9000
+#endif
+
+#ifndef ETHERTYPE_ATALK
+#define ETHERTYPE_ATALK 0x809b /* XXX */
+#endif
+#ifndef ETHERTYPE_AARP
+#define ETHERTYPE_AARP 0x80f3
+#endif
+#ifndef ETHERTYPE_NS
+#define ETHERTYPE_NS 0x0600
+#endif
+
+#ifndef ETHERTYPE_REVARP
+#define ETHERTYPE_REVARP 0x8035
+#endif
+
diff --git a/lib/libpcap/gencode.c b/lib/libpcap/gencode.c
new file mode 100644
index 0000000..0c7c049
--- /dev/null
+++ b/lib/libpcap/gencode.c
@@ -0,0 +1,1755 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: gencode.c,v 1.55 94/06/20 19:07:53 leres Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <memory.h>
+#include <pcap.h>
+#include <pcap-namedb.h>
+#include <setjmp.h>
+#if __STDC__
+#include <stdarg.h>
+#include <stdlib.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "gencode.h"
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+#ifndef ETHERTYPE_REVARP
+#define ETHERTYPE_REVARP 0x8035
+#endif
+#ifndef ETHERTYPE_MOPDL
+#define ETHERTYPE_MOPDL 0x6001
+#endif
+#ifndef ETHERTYPE_MOPRC
+#define ETHERTYPE_MOPRC 0x6002
+#endif
+#ifndef ETHERTYPE_DN
+#define ETHERTYPE_DN 0x6003
+#endif
+#ifndef ETHERTYPE_LAT
+#define ETHERTYPE_LAT 0x6004
+#endif
+
+#define JMP(c) ((c)|BPF_JMP|BPF_K)
+
+static jmp_buf top_ctx;
+static pcap_t *bpf_pcap;
+
+/* VARARGS */
+volatile void
+#if __STDC__ || defined(SOLARIS)
+bpf_error(char *fmt, ...)
+#else
+bpf_error(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ if (bpf_pcap != NULL)
+ (void)vsprintf(pcap_geterr(bpf_pcap), fmt, ap);
+ va_end(ap);
+ longjmp(top_ctx, 1);
+ /* NOTREACHED */
+}
+
+static void init_linktype(int);
+
+static int alloc_reg(void);
+static void free_reg(int);
+
+static struct block *root;
+
+/*
+ * We divy out chunks of memory rather than call malloc each time so
+ * we don't have to worry about leaking memory. It's probably
+ * not a big deal if all this memory was wasted but it this ever
+ * goes into a library that would probably not be a good idea.
+ */
+#define NCHUNKS 16
+#define CHUNK0SIZE 1024
+struct chunk {
+ u_int n_left;
+ void *m;
+};
+
+static struct chunk chunks[NCHUNKS];
+static int cur_chunk;
+
+static void *newchunk(u_int);
+static void freechunks(void);
+static inline struct block *new_block(int);
+static inline struct slist *new_stmt(int);
+static struct block *gen_retblk(int);
+static inline void syntax(void);
+
+static void backpatch(struct block *, struct block *);
+static void merge(struct block *, struct block *);
+static struct block *gen_cmp(u_int, u_int, long);
+static struct block *gen_mcmp(u_int, u_int, long, u_long);
+static struct block *gen_bcmp(u_int, u_int, u_char *);
+static struct block *gen_uncond(int);
+static inline struct block *gen_true(void);
+static inline struct block *gen_false(void);
+static struct block *gen_linktype(int);
+static struct block *gen_hostop(u_long, u_long, int, int, u_int, u_int);
+static struct block *gen_ehostop(u_char *, int);
+#ifdef FDDI
+static struct block *gen_fhostop(u_char *, int);
+#endif
+static struct block *gen_dnhostop(u_long, int, u_int);
+static struct block *gen_host(u_long, u_long, int, int);
+static struct block *gen_gateway(u_char *, u_long **, int, int);
+static struct block *gen_ipfrag(void);
+static struct block *gen_portatom(int, long);
+struct block *gen_portop(int, int, int);
+static struct block *gen_port(int, int, int);
+static int lookup_proto(char *, int);
+static struct block *gen_proto(int, int, int);
+static u_long net_mask(u_long *);
+static u_long net_mask(u_long *);
+static struct slist *xfer_to_x(struct arth *);
+static struct slist *xfer_to_a(struct arth *);
+static struct block *gen_len(int, int);
+
+static void *
+newchunk(n)
+ u_int n;
+{
+ struct chunk *cp;
+ int k, size;
+
+ /* XXX Round up to nearest long. */
+ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
+
+ cp = &chunks[cur_chunk];
+ if (n > cp->n_left) {
+ ++cp, k = ++cur_chunk;
+ if (k >= NCHUNKS)
+ bpf_error("out of memory");
+ size = CHUNK0SIZE << k;
+ cp->m = (void *)malloc(size);
+ memset((char *)cp->m, 0, size);
+ cp->n_left = size;
+ if (n > size)
+ bpf_error("out of memory");
+ }
+ cp->n_left -= n;
+ return (void *)((char *)cp->m + cp->n_left);
+}
+
+static void
+freechunks()
+{
+ int i;
+
+ for (i = 0; i < NCHUNKS; ++i)
+ if (chunks[i].m)
+ free(chunks[i].m);
+}
+
+/*
+ * A strdup whose allocations are freed after code generation is over.
+ */
+char *
+sdup(s)
+ char *s;
+{
+ int n = strlen(s) + 1;
+ char *cp = newchunk(n);
+ strcpy(cp, s);
+ return (cp);
+}
+
+static inline struct block *
+new_block(code)
+ int code;
+{
+ struct block *p;
+
+ p = (struct block *)newchunk(sizeof(*p));
+ p->s.code = code;
+ p->head = p;
+
+ return p;
+}
+
+static inline struct slist *
+new_stmt(code)
+ int code;
+{
+ struct slist *p;
+
+ p = (struct slist *)newchunk(sizeof(*p));
+ p->s.code = code;
+
+ return p;
+}
+
+static struct block *
+gen_retblk(v)
+ int v;
+{
+ struct block *b = new_block(BPF_RET|BPF_K);
+
+ b->s.k = v;
+ return b;
+}
+
+static inline void
+syntax()
+{
+ bpf_error("syntax error in filter expression");
+}
+
+static u_long netmask;
+static int snaplen;
+
+int
+pcap_compile(pcap_t *p, struct bpf_program *program,
+ char *buf, int optimize, u_long mask)
+{
+ extern int n_errors;
+ int len;
+
+ bpf_pcap = p;
+ if (setjmp(top_ctx))
+ return (-1);
+
+ netmask = mask;
+ snaplen = pcap_snapshot(p);
+
+ lex_init(buf ? buf : "");
+ init_linktype(pcap_datalink(p));
+ pcap_parse();
+
+ if (n_errors)
+ syntax();
+
+ if (root == NULL)
+ root = gen_retblk(snaplen);
+
+ if (optimize) {
+ bpf_optimize(&root);
+ if (root == NULL ||
+ (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0))
+ bpf_error("expression rejects all packets");
+ }
+ program->bf_insns = icode_to_fcode(root, &len);
+ program->bf_len = len;
+
+ freechunks();
+ return (0);
+}
+
+/*
+ * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates
+ * which of the jt and jf fields has been resolved and which is a pointer
+ * back to another unresolved block (or nil). At least one of the fields
+ * in each block is already resolved.
+ */
+static void
+backpatch(list, target)
+ struct block *list, *target;
+{
+ struct block *next;
+
+ while (list) {
+ if (!list->sense) {
+ next = JT(list);
+ JT(list) = target;
+ } else {
+ next = JF(list);
+ JF(list) = target;
+ }
+ list = next;
+ }
+}
+
+/*
+ * Merge the lists in b0 and b1, using the 'sense' field to indicate
+ * which of jt and jf is the link.
+ */
+static void
+merge(b0, b1)
+ struct block *b0, *b1;
+{
+ register struct block **p = &b0;
+
+ /* Find end of list. */
+ while (*p)
+ p = !((*p)->sense) ? &JT(*p) : &JF(*p);
+
+ /* Concatenate the lists. */
+ *p = b1;
+}
+
+void
+finish_parse(p)
+ struct block *p;
+{
+ backpatch(p, gen_retblk(snaplen));
+ p->sense = !p->sense;
+ backpatch(p, gen_retblk(0));
+ root = p->head;
+}
+
+void
+gen_and(b0, b1)
+ struct block *b0, *b1;
+{
+ backpatch(b0, b1->head);
+ b0->sense = !b0->sense;
+ b1->sense = !b1->sense;
+ merge(b1, b0);
+ b1->sense = !b1->sense;
+ b1->head = b0->head;
+}
+
+void
+gen_or(b0, b1)
+ struct block *b0, *b1;
+{
+ b0->sense = !b0->sense;
+ backpatch(b0, b1->head);
+ b0->sense = !b0->sense;
+ merge(b1, b0);
+ b1->head = b0->head;
+}
+
+void
+gen_not(b)
+ struct block *b;
+{
+ b->sense = !b->sense;
+}
+
+static struct block *
+gen_cmp(offset, size, v)
+ u_int offset, size;
+ long v;
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(BPF_LD|BPF_ABS|size);
+ s->s.k = offset;
+
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+ b->s.k = v;
+
+ return b;
+}
+
+static struct block *
+gen_mcmp(offset, size, v, mask)
+ u_int offset, size;
+ long v;
+ u_long mask;
+{
+ struct block *b = gen_cmp(offset, size, v);
+ struct slist *s;
+
+ if (mask != 0xffffffff) {
+ s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+ s->s.k = mask;
+ b->stmts->next = s;
+ }
+ return b;
+}
+
+static struct block *
+gen_bcmp(offset, size, v)
+ u_int offset, size;
+ u_char *v;
+{
+ struct block *b, *tmp;
+
+ b = NULL;
+ while (size >= 4) {
+ u_char *p = &v[size - 4];
+ long w = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ tmp = gen_cmp(offset + size - 4, BPF_W, w);
+ if (b != NULL)
+ gen_and(b, tmp);
+ b = tmp;
+ size -= 4;
+ }
+ while (size >= 2) {
+ u_char *p = &v[size - 2];
+ long w = (p[0] << 8) | p[1];
+ tmp = gen_cmp(offset + size - 2, BPF_H, w);
+ if (b != NULL)
+ gen_and(b, tmp);
+ b = tmp;
+ size -= 2;
+ }
+ if (size > 0) {
+ tmp = gen_cmp(offset, BPF_B, (long)v[0]);
+ if (b != NULL)
+ gen_and(b, tmp);
+ b = tmp;
+ }
+ return b;
+}
+
+/*
+ * Various code constructs need to know the layout of the data link
+ * layer. These variables give the necessary offsets. off_linktype
+ * is set to -1 for no encapsulation, in which case, IP is assumed.
+ */
+static u_int off_linktype;
+static u_int off_nl;
+static int linktype;
+#ifdef FDDI
+extern int fddipad;
+#endif
+
+static void
+init_linktype(type)
+ int type;
+{
+ linktype = type;
+
+ switch (type) {
+
+ case DLT_EN10MB:
+ off_linktype = 12;
+ off_nl = 14;
+ return;
+
+ case DLT_SLIP:
+ /*
+ * SLIP doesn't have a link level type. The 16 byte
+ * header is hacked into our SLIP driver.
+ */
+ off_linktype = -1;
+ off_nl = 16;
+ return;
+
+ case DLT_NULL:
+ off_linktype = -1;
+ off_nl = 0;
+ return;
+
+ case DLT_PPP:
+ off_linktype = 2;
+ off_nl = 4;
+ return;
+
+#ifdef FDDI
+ case DLT_FDDI:
+ /*
+ * FDDI doesn't really have a link-level type field.
+ * We assume that SSAP = SNAP is being used and pick
+ * out the encapsulated Ethernet type.
+ */
+ off_linktype = 19 + fddipad;
+ off_nl = 21 + fddipad;
+ return;
+#endif
+
+ case DLT_IEEE802:
+ off_linktype = 20;
+ off_nl = 22;
+ return;
+ }
+ bpf_error("unknown data link type 0x%x", linktype);
+ /* NOTREACHED */
+}
+
+static struct block *
+gen_uncond(rsense)
+ int rsense;
+{
+ struct block *b;
+ struct slist *s;
+
+ s = new_stmt(BPF_LD|BPF_IMM);
+ s->s.k = !rsense;
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+
+ return b;
+}
+
+static inline struct block *
+gen_true()
+{
+ return gen_uncond(1);
+}
+
+static inline struct block *
+gen_false()
+{
+ return gen_uncond(0);
+}
+
+static struct block *
+gen_linktype(proto)
+ int proto;
+{
+ switch (linktype) {
+ case DLT_SLIP:
+ if (proto == ETHERTYPE_IP)
+ return gen_true();
+ else
+ return gen_false();
+
+ case DLT_PPP:
+ if (proto == ETHERTYPE_IP)
+ proto = 0x0021; /* XXX - need ppp.h defs */
+ break;
+ }
+ return gen_cmp(off_linktype, BPF_H, (long)proto);
+}
+
+static struct block *
+gen_hostop(addr, mask, dir, proto, src_off, dst_off)
+ u_long addr;
+ u_long mask;
+ int dir, proto;
+ u_int src_off, dst_off;
+{
+ struct block *b0, *b1;
+ u_int offset;
+
+ switch (dir) {
+
+ case Q_SRC:
+ offset = src_off;
+ break;
+
+ case Q_DST:
+ offset = dst_off;
+ break;
+
+ case Q_AND:
+ b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ abort();
+ }
+ b0 = gen_linktype(proto);
+ b1 = gen_mcmp(offset, BPF_W, (long)addr, mask);
+ gen_and(b0, b1);
+ return b1;
+}
+
+static struct block *
+gen_ehostop(eaddr, dir)
+ u_char *eaddr;
+ int dir;
+{
+ struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(6, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(0, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_ehostop(eaddr, Q_SRC);
+ b1 = gen_ehostop(eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_ehostop(eaddr, Q_SRC);
+ b1 = gen_ehostop(eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+#ifdef FDDI
+/*
+ * Like gen_ehostop, but for DLT_FDDI
+ */
+static struct block *
+gen_fhostop(eaddr, dir)
+ u_char *eaddr;
+ int dir;
+{
+ struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(6 + 1 + fddipad, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(0 + 1 + fddipad, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_fhostop(eaddr, Q_SRC);
+ b1 = gen_fhostop(eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_fhostop(eaddr, Q_SRC);
+ b1 = gen_fhostop(eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+ }
+ abort();
+ /* NOTREACHED */
+}
+#endif
+
+/*
+ * This is quite tricky because there may be pad bytes in front of the
+ * DECNET header, and then there are two possible data packet formats that
+ * carry both src and dst addresses, plus 5 packet types in a format that
+ * carries only the src node, plus 2 types that use a different format and
+ * also carry just the src node.
+ *
+ * Yuck.
+ *
+ * Instead of doing those all right, we just look for data packets with
+ * 0 or 1 bytes of padding. If you want to look at other packets, that
+ * will require a lot more hacking.
+ *
+ * To add support for filtering on DECNET "areas" (network numbers)
+ * one would want to add a "mask" argument to this routine. That would
+ * make the filter even more inefficient, although one could be clever
+ * and not generate masking instructions if the mask is 0xFFFF.
+ */
+static struct block *
+gen_dnhostop(addr, dir, base_off)
+ u_long addr;
+ int dir;
+ u_int base_off;
+{
+ struct block *b0, *b1, *b2, *tmp;
+ u_int offset_lh; /* offset if long header is received */
+ u_int offset_sh; /* offset if short header is received */
+
+ switch (dir) {
+
+ case Q_DST:
+ offset_sh = 1; /* follows flags */
+ offset_lh = 7; /* flgs,darea,dsubarea,HIORD */
+ break;
+
+ case Q_SRC:
+ offset_sh = 3; /* follows flags, dstnode */
+ offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */
+ break;
+
+ case Q_AND:
+ /* Inefficient because we do our Calvinball dance twice */
+ b0 = gen_dnhostop(addr, Q_SRC, base_off);
+ b1 = gen_dnhostop(addr, Q_DST, base_off);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ /* Inefficient because we do our Calvinball dance twice */
+ b0 = gen_dnhostop(addr, Q_SRC, base_off);
+ b1 = gen_dnhostop(addr, Q_DST, base_off);
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ abort();
+ }
+ b0 = gen_linktype(ETHERTYPE_DN);
+ /* Check for pad = 1, long header case */
+ tmp = gen_mcmp(base_off + 2, BPF_H,
+ (long)ntohs(0x0681), (long)ntohs(0x07FF));
+ b1 = gen_cmp(base_off + 2 + 1 + offset_lh, BPF_H, (long)ntohs(addr));
+ gen_and(tmp, b1);
+ /* Check for pad = 0, long header case */
+ tmp = gen_mcmp(base_off + 2, BPF_B, (long)0x06, (long)0x7);
+ b2 = gen_cmp(base_off + 2 + offset_lh, BPF_H, (long)ntohs(addr));
+ gen_and(tmp, b2);
+ gen_or(b2, b1);
+ /* Check for pad = 1, short header case */
+ tmp = gen_mcmp(base_off + 2, BPF_H,
+ (long)ntohs(0x0281), (long)ntohs(0x07FF));
+ b2 = gen_cmp(base_off + 2 + 1 + offset_sh, BPF_H, (long)ntohs(addr));
+ gen_and(tmp, b2);
+ gen_or(b2, b1);
+ /* Check for pad = 0, short header case */
+ tmp = gen_mcmp(base_off + 2, BPF_B, (long)0x02, (long)0x7);
+ b2 = gen_cmp(base_off + 2 + offset_sh, BPF_H, (long)ntohs(addr));
+ gen_and(tmp, b2);
+ gen_or(b2, b1);
+
+ /* Combine with test for linktype */
+ gen_and(b0, b1);
+ return b1;
+}
+
+static struct block *
+gen_host(addr, mask, proto, dir)
+ u_long addr;
+ u_long mask;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1;
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ b0 = gen_host(addr, mask, Q_IP, dir);
+ b1 = gen_host(addr, mask, Q_ARP, dir);
+ gen_or(b0, b1);
+ b0 = gen_host(addr, mask, Q_RARP, dir);
+ gen_or(b1, b0);
+ return b0;
+
+ case Q_IP:
+ return gen_hostop(addr, mask, dir, ETHERTYPE_IP,
+ off_nl + 12, off_nl + 16);
+
+ case Q_RARP:
+ return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP,
+ off_nl + 14, off_nl + 24);
+
+ case Q_ARP:
+ return gen_hostop(addr, mask, dir, ETHERTYPE_ARP,
+ off_nl + 14, off_nl + 24);
+
+ case Q_TCP:
+ bpf_error("'tcp' modifier applied to host");
+
+ case Q_UDP:
+ bpf_error("'udp' modifier applied to host");
+
+ case Q_ICMP:
+ bpf_error("'icmp' modifier applied to host");
+
+ case Q_DECNET:
+ return gen_dnhostop(addr, dir, off_nl);
+
+ case Q_LAT:
+ bpf_error("LAT host filtering not implemented");
+
+ case Q_MOPDL:
+ bpf_error("MOPDL host filtering not implemented");
+
+ case Q_MOPRC:
+ bpf_error("MOPRC host filtering not implemented");
+
+ default:
+ abort();
+ }
+ /* NOTREACHED */
+}
+
+static struct block *
+gen_gateway(eaddr, alist, proto, dir)
+ u_char *eaddr;
+ u_long **alist;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ if (dir != 0)
+ bpf_error("direction applied to 'gateway'");
+
+ switch (proto) {
+ case Q_DEFAULT:
+ case Q_IP:
+ case Q_ARP:
+ case Q_RARP:
+ if (linktype == DLT_EN10MB)
+ b0 = gen_ehostop(eaddr, Q_OR);
+#ifdef FDDI
+ else if (linktype == DLT_FDDI)
+ b0 = gen_fhostop(eaddr, Q_OR);
+#endif
+ else
+ bpf_error("'gateway' supported only on ethernet or FDDI");
+
+ b1 = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
+ while (*alist) {
+ tmp = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
+ gen_or(b1, tmp);
+ b1 = tmp;
+ }
+ gen_not(b1);
+ gen_and(b0, b1);
+ return b1;
+ }
+ bpf_error("illegal modifier of 'gateway'");
+ /* NOTREACHED */
+}
+
+struct block *
+gen_proto_abbrev(proto)
+ int proto;
+{
+ struct block *b0, *b1;
+
+ switch (proto) {
+
+ case Q_TCP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_TCP);
+ gen_and(b0, b1);
+ break;
+
+ case Q_UDP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_UDP);
+ gen_and(b0, b1);
+ break;
+
+ case Q_ICMP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_ICMP);
+ gen_and(b0, b1);
+ break;
+
+ case Q_IP:
+ b1 = gen_linktype(ETHERTYPE_IP);
+ break;
+
+ case Q_ARP:
+ b1 = gen_linktype(ETHERTYPE_ARP);
+ break;
+
+ case Q_RARP:
+ b1 = gen_linktype(ETHERTYPE_REVARP);
+ break;
+
+ case Q_LINK:
+ bpf_error("link layer applied in wrong context");
+
+ case Q_DECNET:
+ b1 = gen_linktype(ETHERTYPE_DN);
+ break;
+
+ case Q_LAT:
+ b1 = gen_linktype(ETHERTYPE_LAT);
+ break;
+
+ case Q_MOPDL:
+ b1 = gen_linktype(ETHERTYPE_MOPDL);
+ break;
+
+ case Q_MOPRC:
+ b1 = gen_linktype(ETHERTYPE_MOPRC);
+ break;
+
+ default:
+ abort();
+ }
+ return b1;
+}
+
+static struct block *
+gen_ipfrag()
+{
+ struct slist *s;
+ struct block *b;
+
+ /* not ip frag */
+ s = new_stmt(BPF_LD|BPF_H|BPF_ABS);
+ s->s.k = off_nl + 6;
+ b = new_block(JMP(BPF_JSET));
+ b->s.k = 0x1fff;
+ b->stmts = s;
+ gen_not(b);
+
+ return b;
+}
+
+static struct block *
+gen_portatom(off, v)
+ int off;
+ long v;
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+ s->s.k = off_nl;
+
+ s->next = new_stmt(BPF_LD|BPF_IND|BPF_H);
+ s->next->s.k = off_nl + off;
+
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+ b->s.k = v;
+
+ return b;
+}
+
+struct block *
+gen_portop(port, proto, dir)
+ int port, proto, dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip proto 'proto' */
+ tmp = gen_cmp(off_nl + 9, BPF_B, (long)proto);
+ b0 = gen_ipfrag();
+ gen_and(tmp, b0);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portatom(0, (long)port);
+ break;
+
+ case Q_DST:
+ b1 = gen_portatom(2, (long)port);
+ break;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ tmp = gen_portatom(0, (long)port);
+ b1 = gen_portatom(2, (long)port);
+ gen_or(tmp, b1);
+ break;
+
+ case Q_AND:
+ tmp = gen_portatom(0, (long)port);
+ b1 = gen_portatom(2, (long)port);
+ gen_and(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_port(port, ip_proto, dir)
+ int port;
+ int ip_proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ether proto ip */
+ b0 = gen_linktype(ETHERTYPE_IP);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ b1 = gen_portop(port, ip_proto, dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portop(port, IPPROTO_TCP, dir);
+ b1 = gen_portop(port, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+
+static int
+lookup_proto(name, proto)
+ char *name;
+ int proto;
+{
+ int v;
+
+ switch (proto) {
+ case Q_DEFAULT:
+ case Q_IP:
+ v = pcap_nametoproto(name);
+ if (v == PROTO_UNDEF)
+ bpf_error("unknown ip proto '%s'", name);
+ break;
+
+ case Q_LINK:
+ /* XXX should look up h/w protocol type based on linktype */
+ v = pcap_nametoeproto(name);
+ if (v == PROTO_UNDEF)
+ bpf_error("unknown ether proto '%s'", name);
+ break;
+
+ default:
+ v = PROTO_UNDEF;
+ break;
+ }
+ return v;
+}
+
+static struct block *
+gen_proto(v, proto, dir)
+ int v;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1;
+
+ if (dir != Q_DEFAULT)
+ bpf_error("direction applied to 'proto'");
+
+ switch (proto) {
+ case Q_DEFAULT:
+ case Q_IP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)v);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_ARP:
+ bpf_error("arp does not encapsulate another protocol");
+ /* NOTREACHED */
+
+ case Q_RARP:
+ bpf_error("rarp does not encapsulate another protocol");
+ /* NOTREACHED */
+
+ case Q_DECNET:
+ bpf_error("decnet encapsulation is not specifiable");
+ /* NOTREACHED */
+
+ case Q_LAT:
+ bpf_error("lat does not encapsulate another protocol");
+ /* NOTREACHED */
+
+ case Q_MOPRC:
+ bpf_error("moprc does not encapsulate another protocol");
+ /* NOTREACHED */
+
+ case Q_MOPDL:
+ bpf_error("mopdl does not encapsulate another protocol");
+ /* NOTREACHED */
+
+ case Q_LINK:
+ return gen_linktype(v);
+
+ case Q_UDP:
+ bpf_error("'udp proto' is bogus");
+ /* NOTREACHED */
+
+ case Q_TCP:
+ bpf_error("'tcp proto' is bogus");
+ /* NOTREACHED */
+
+ case Q_ICMP:
+ bpf_error("'icmp proto' is bogus");
+ /* NOTREACHED */
+
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Left justify 'addr' and return its resulting network mask.
+ */
+static u_long
+net_mask(addr)
+ u_long *addr;
+{
+ register u_long m = 0xffffffff;
+
+ if (*addr)
+ while ((*addr & 0xff000000) == 0)
+ *addr <<= 8, m <<= 8;
+
+ return m;
+}
+
+struct block *
+gen_scode(name, q)
+ char *name;
+ struct qual q;
+{
+ int proto = q.proto;
+ int dir = q.dir;
+ u_char *eaddr;
+ u_long mask, addr, **alist;
+ struct block *b, *tmp;
+ int port, real_proto;
+
+ switch (q.addr) {
+
+ case Q_NET:
+ addr = pcap_nametonetaddr(name);
+ if (addr == 0)
+ bpf_error("unknown network '%s'", name);
+ mask = net_mask(&addr);
+ return gen_host(addr, mask, proto, dir);
+
+ case Q_DEFAULT:
+ case Q_HOST:
+ if (proto == Q_LINK) {
+ switch (linktype) {
+ case DLT_EN10MB:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error("unknown ether host '%s'", name);
+ return gen_ehostop(eaddr, dir);
+
+#ifdef FDDI
+ case DLT_FDDI:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error("unknown FDDI host '%s'", name);
+ return gen_fhostop(eaddr, dir);
+#endif
+ default:
+ bpf_error("only ethernet/FDDI supports link-level host name");
+ break;
+ }
+ } else if (proto == Q_DECNET) {
+ unsigned short dn_addr = __pcap_nametodnaddr(name);
+ /*
+ * I don't think DECNET hosts can be multihomed, so
+ * there is no need to build up a list of addresses
+ */
+ return (gen_host(dn_addr, 0, proto, dir));
+ } else {
+ alist = pcap_nametoaddr(name);
+ if (alist == NULL || *alist == NULL)
+ bpf_error("unknown host '%s'", name);
+ b = gen_host(**alist++, 0xffffffffL, proto, dir);
+ while (*alist) {
+ tmp = gen_host(**alist++, 0xffffffffL,
+ proto, dir);
+ gen_or(b, tmp);
+ b = tmp;
+ }
+ return b;
+ }
+
+ case Q_PORT:
+ if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP)
+ bpf_error("illegal qualifier of 'port'");
+ if (pcap_nametoport(name, &port, &real_proto) == 0)
+ bpf_error("unknown port '%s'", name);
+ if (proto == Q_UDP) {
+ if (real_proto == IPPROTO_TCP)
+ bpf_error("port '%s' is tcp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_UDP;
+ }
+ if (proto == Q_TCP) {
+ if (real_proto == IPPROTO_UDP)
+ bpf_error("port '%s' is udp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_TCP;
+ }
+ return gen_port(port, real_proto, dir);
+
+ case Q_GATEWAY:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error("unknown ether host: %s", name);
+
+ alist = pcap_nametoaddr(name);
+ if (alist == NULL || *alist == NULL)
+ bpf_error("unknown host '%s'", name);
+ return gen_gateway(eaddr, alist, proto, dir);
+
+ case Q_PROTO:
+ real_proto = lookup_proto(name, proto);
+ if (real_proto >= 0)
+ return gen_proto(real_proto, proto, dir);
+ else
+ bpf_error("unknown protocol: %s", name);
+
+ case Q_UNDEF:
+ syntax();
+ /* NOTREACHED */
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+struct block *
+gen_ncode(v, q)
+ u_long v;
+ struct qual q;
+{
+ u_long mask;
+ int proto = q.proto;
+ int dir = q.dir;
+
+ switch (q.addr) {
+
+ case Q_DEFAULT:
+ case Q_HOST:
+ case Q_NET:
+ if (proto == Q_DECNET)
+ return gen_host(v, 0, proto, dir);
+ else if (proto == Q_LINK) {
+ bpf_error("illegal link layer address");
+ } else {
+ mask = net_mask(&v);
+ return gen_host(v, mask, proto, dir);
+ }
+
+ case Q_PORT:
+ if (proto == Q_UDP)
+ proto = IPPROTO_UDP;
+ else if (proto == Q_TCP)
+ proto = IPPROTO_TCP;
+ else if (proto == Q_DEFAULT)
+ proto = PROTO_UNDEF;
+ else
+ bpf_error("illegal qualifier of 'port'");
+
+ return gen_port((int)v, proto, dir);
+
+ case Q_GATEWAY:
+ bpf_error("'gateway' requires a name");
+ /* NOTREACHED */
+
+ case Q_PROTO:
+ return gen_proto((int)v, proto, dir);
+
+ case Q_UNDEF:
+ syntax();
+ /* NOTREACHED */
+
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+ /* NOTREACHED */
+}
+
+struct block *
+gen_ecode(eaddr, q)
+ u_char *eaddr;
+ struct qual q;
+{
+ if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
+ if (linktype == DLT_EN10MB)
+ return gen_ehostop(eaddr, (int)q.dir);
+#ifdef FDDI
+ if (linktype == DLT_FDDI)
+ return gen_fhostop(eaddr, (int)q.dir);
+#endif
+ }
+ bpf_error("ethernet address used in non-ether expression");
+ /* NOTREACHED */
+}
+
+void
+sappend(s0, s1)
+ struct slist *s0, *s1;
+{
+ /*
+ * This is definitely not the best way to do this, but the
+ * lists will rarely get long.
+ */
+ while (s0->next)
+ s0 = s0->next;
+ s0->next = s1;
+}
+
+static struct slist *
+xfer_to_x(a)
+ struct arth *a;
+{
+ struct slist *s;
+
+ s = new_stmt(BPF_LDX|BPF_MEM);
+ s->s.k = a->regno;
+ return s;
+}
+
+static struct slist *
+xfer_to_a(a)
+ struct arth *a;
+{
+ struct slist *s;
+
+ s = new_stmt(BPF_LD|BPF_MEM);
+ s->s.k = a->regno;
+ return s;
+}
+
+struct arth *
+gen_load(proto, index, size)
+ int proto;
+ struct arth *index;
+ int size;
+{
+ struct slist *s, *tmp;
+ struct block *b;
+ int regno = alloc_reg();
+
+ free_reg(index->regno);
+ switch (size) {
+
+ default:
+ bpf_error("data size must be 1, 2, or 4");
+
+ case 1:
+ size = BPF_B;
+ break;
+
+ case 2:
+ size = BPF_H;
+ break;
+
+ case 4:
+ size = BPF_W;
+ break;
+ }
+ switch (proto) {
+ default:
+ bpf_error("unsupported index operation");
+
+ case Q_LINK:
+ s = xfer_to_x(index);
+ tmp = new_stmt(BPF_LD|BPF_IND|size);
+ sappend(s, tmp);
+ sappend(index->s, s);
+ break;
+
+ case Q_IP:
+ case Q_ARP:
+ case Q_RARP:
+ case Q_DECNET:
+ case Q_LAT:
+ case Q_MOPRC:
+ case Q_MOPDL:
+ /* XXX Note that we assume a fixed link link header here. */
+ s = xfer_to_x(index);
+ tmp = new_stmt(BPF_LD|BPF_IND|size);
+ tmp->s.k = off_nl;
+ sappend(s, tmp);
+ sappend(index->s, s);
+
+ b = gen_proto_abbrev(proto);
+ if (index->b)
+ gen_and(index->b, b);
+ index->b = b;
+ break;
+
+ case Q_TCP:
+ case Q_UDP:
+ case Q_ICMP:
+ s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+ s->s.k = off_nl;
+ sappend(s, xfer_to_a(index));
+ sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(BPF_MISC|BPF_TAX));
+ sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size));
+ tmp->s.k = off_nl;
+ sappend(index->s, s);
+
+ gen_and(gen_proto_abbrev(proto), b = gen_ipfrag());
+ if (index->b)
+ gen_and(index->b, b);
+ index->b = b;
+ break;
+ }
+ index->regno = regno;
+ s = new_stmt(BPF_ST);
+ s->s.k = regno;
+ sappend(index->s, s);
+
+ return index;
+}
+
+struct block *
+gen_relation(code, a0, a1, reversed)
+ int code;
+ struct arth *a0, *a1;
+ int reversed;
+{
+ struct slist *s0, *s1, *s2;
+ struct block *b, *tmp;
+
+ s0 = xfer_to_x(a1);
+ s1 = xfer_to_a(a0);
+ s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X);
+ b = new_block(JMP(code));
+ if (reversed)
+ gen_not(b);
+
+ sappend(s1, s2);
+ sappend(s0, s1);
+ sappend(a1->s, s0);
+ sappend(a0->s, a1->s);
+
+ b->stmts = a0->s;
+
+ free_reg(a0->regno);
+ free_reg(a1->regno);
+
+ /* 'and' together protocol checks */
+ if (a0->b) {
+ if (a1->b) {
+ gen_and(a0->b, tmp = a1->b);
+ }
+ else
+ tmp = a0->b;
+ } else
+ tmp = a1->b;
+
+ if (tmp)
+ gen_and(tmp, b);
+
+ return b;
+}
+
+struct arth *
+gen_loadlen()
+{
+ int regno = alloc_reg();
+ struct arth *a = (struct arth *)newchunk(sizeof(*a));
+ struct slist *s;
+
+ s = new_stmt(BPF_LD|BPF_LEN);
+ s->next = new_stmt(BPF_ST);
+ s->next->s.k = regno;
+ a->s = s;
+ a->regno = regno;
+
+ return a;
+}
+
+struct arth *
+gen_loadi(val)
+ int val;
+{
+ struct arth *a;
+ struct slist *s;
+ int reg;
+
+ a = (struct arth *)newchunk(sizeof(*a));
+
+ reg = alloc_reg();
+
+ s = new_stmt(BPF_LD|BPF_IMM);
+ s->s.k = val;
+ s->next = new_stmt(BPF_ST);
+ s->next->s.k = reg;
+ a->s = s;
+ a->regno = reg;
+
+ return a;
+}
+
+struct arth *
+gen_neg(a)
+ struct arth *a;
+{
+ struct slist *s;
+
+ s = xfer_to_a(a);
+ sappend(a->s, s);
+ s = new_stmt(BPF_ALU|BPF_NEG);
+ s->s.k = 0;
+ sappend(a->s, s);
+ s = new_stmt(BPF_ST);
+ s->s.k = a->regno;
+ sappend(a->s, s);
+
+ return a;
+}
+
+struct arth *
+gen_arth(code, a0, a1)
+ int code;
+ struct arth *a0, *a1;
+{
+ struct slist *s0, *s1, *s2;
+
+ s0 = xfer_to_x(a1);
+ s1 = xfer_to_a(a0);
+ s2 = new_stmt(BPF_ALU|BPF_X|code);
+
+ sappend(s1, s2);
+ sappend(s0, s1);
+ sappend(a1->s, s0);
+ sappend(a0->s, a1->s);
+
+ free_reg(a1->regno);
+
+ s0 = new_stmt(BPF_ST);
+ a0->regno = s0->s.k = alloc_reg();
+ sappend(a0->s, s0);
+
+ return a0;
+}
+
+/*
+ * Here we handle simple allocation of the scratch registers.
+ * If too many registers are alloc'd, the allocator punts.
+ */
+static int regused[BPF_MEMWORDS];
+static int curreg;
+
+/*
+ * Return the next free register.
+ */
+static int
+alloc_reg()
+{
+ int n = BPF_MEMWORDS;
+
+ while (--n >= 0) {
+ if (regused[curreg])
+ curreg = (curreg + 1) % BPF_MEMWORDS;
+ else {
+ regused[curreg] = 1;
+ return curreg;
+ }
+ }
+ bpf_error("too many registers needed to evaluate expression");
+ /* NOTREACHED */
+}
+
+/*
+ * Return a register to the table so it can
+ * be used later.
+ */
+static void
+free_reg(n)
+ int n;
+{
+ regused[n] = 0;
+}
+
+static struct block *
+gen_len(jmp, n)
+ int jmp, n;
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(BPF_LD|BPF_LEN);
+ s->next = new_stmt(BPF_ALU|BPF_SUB|BPF_K);
+ s->next->s.k = n;
+ b = new_block(JMP(jmp));
+ b->stmts = s;
+
+ return b;
+}
+
+struct block *
+gen_greater(n)
+ int n;
+{
+ return gen_len(BPF_JGE, n);
+}
+
+struct block *
+gen_less(n)
+ int n;
+{
+ struct block *b;
+
+ b = gen_len(BPF_JGT, n);
+ gen_not(b);
+
+ return b;
+}
+
+struct block *
+gen_byteop(op, idx, val)
+ int op, idx, val;
+{
+ struct block *b;
+ struct slist *s;
+
+ switch (op) {
+ default:
+ abort();
+
+ case '=':
+ return gen_cmp((u_int)idx, BPF_B, (long)val);
+
+ case '<':
+ b = gen_cmp((u_int)idx, BPF_B, (long)val);
+ b->s.code = JMP(BPF_JGE);
+ gen_not(b);
+ return b;
+
+ case '>':
+ b = gen_cmp((u_int)idx, BPF_B, (long)val);
+ b->s.code = JMP(BPF_JGT);
+ return b;
+
+ case '|':
+ s = new_stmt(BPF_ALU|BPF_OR|BPF_K);
+ break;
+
+ case '&':
+ s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+ break;
+ }
+ s->s.k = val;
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+ gen_not(b);
+
+ return b;
+}
+
+struct block *
+gen_broadcast(proto)
+ int proto;
+{
+ u_long hostmask;
+ struct block *b0, *b1, *b2;
+ static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ case Q_LINK:
+ if (linktype == DLT_EN10MB)
+ return gen_ehostop(ebroadcast, Q_DST);
+#ifdef FDDI
+ if (linktype == DLT_FDDI)
+ return gen_fhostop(ebroadcast, Q_DST);
+#endif
+ bpf_error("not a broadcast link");
+ break;
+
+ case Q_IP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ hostmask = ~netmask;
+ b1 = gen_mcmp(off_nl + 16, BPF_W, (long)0, hostmask);
+ b2 = gen_mcmp(off_nl + 16, BPF_W,
+ (long)(~0 & hostmask), hostmask);
+ gen_or(b1, b2);
+ gen_and(b0, b2);
+ return b2;
+ }
+ bpf_error("only ether/ip broadcast filters supported");
+}
+
+struct block *
+gen_multicast(proto)
+ int proto;
+{
+ register struct block *b0, *b1;
+ register struct slist *s;
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ case Q_LINK:
+ if (linktype == DLT_EN10MB) {
+ /* ether[0] & 1 != 0 */
+ s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = 0;
+ b0 = new_block(JMP(BPF_JSET));
+ b0->s.k = 1;
+ b0->stmts = s;
+ return b0;
+ }
+
+ if (linktype == DLT_FDDI) {
+ /* XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX */
+ /* fddi[1] & 1 != 0 */
+ s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = 1;
+ b0 = new_block(JMP(BPF_JSET));
+ b0->s.k = 1;
+ b0->stmts = s;
+ return b0;
+ }
+ /* Link not known to support multicasts */
+ break;
+
+ case Q_IP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 16, BPF_B, (long)224);
+ b1->s.code = JMP(BPF_JGE);
+ gen_and(b0, b1);
+ return b1;
+ }
+ bpf_error("only IP multicast filters supported on ethernet/FDDI");
+}
+
+/*
+ * generate command for inbound/outbound. It's here so we can
+ * make it link-type specific. 'dir' = 0 implies "inbound",
+ * = 1 implies "outbound".
+ */
+struct block *
+gen_inbound(dir)
+ int dir;
+{
+ register struct block *b0;
+
+ b0 = gen_relation(BPF_JEQ,
+ gen_load(Q_LINK, gen_loadi(0), 1),
+ gen_loadi(0),
+ dir);
+ return (b0);
+}
diff --git a/lib/libpcap/gencode.h b/lib/libpcap/gencode.h
new file mode 100644
index 0000000..b202acf
--- /dev/null
+++ b/lib/libpcap/gencode.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: gencode.h,v 1.20 94/06/12 14:29:30 leres Exp $ (LBL)
+ */
+
+/*
+ * filter.h must be included before this file.
+ */
+
+/* Address qualifers. */
+
+#define Q_HOST 1
+#define Q_NET 2
+#define Q_PORT 3
+#define Q_GATEWAY 4
+#define Q_PROTO 5
+
+/* Protocol qualifiers. */
+
+#define Q_LINK 1
+#define Q_IP 2
+#define Q_ARP 3
+#define Q_RARP 4
+#define Q_TCP 5
+#define Q_UDP 6
+#define Q_ICMP 7
+
+#define Q_DECNET 8
+#define Q_LAT 9
+#define Q_MOPRC 10
+#define Q_MOPDL 11
+
+/* Directional qualifers. */
+
+#define Q_SRC 1
+#define Q_DST 2
+#define Q_OR 3
+#define Q_AND 4
+
+#define Q_DEFAULT 0
+#define Q_UNDEF 255
+
+struct stmt {
+ int code;
+ long k;
+};
+
+struct slist {
+ struct stmt s;
+ struct slist *next;
+};
+
+/*
+ * A bit vector to represent definition sets. We assume TOT_REGISTERS
+ * is smaller than 8*sizeof(atomset).
+ */
+typedef u_long atomset;
+#define ATOMMASK(n) (1 << (n))
+#define ATOMELEM(d, n) (d & ATOMMASK(n))
+
+/*
+ * An unbounded set.
+ */
+typedef u_long *uset;
+
+/*
+ * Total number of atomic entities, including accumulator (A) and index (X).
+ * We treat all these guys similarly during flow analysis.
+ */
+#define N_ATOMS (BPF_MEMWORDS+2)
+
+struct edge {
+ int id;
+ int code;
+ uset edom;
+ struct block *succ;
+ struct block *pred;
+ struct edge *next; /* link list of incoming edges for a node */
+};
+
+struct block {
+ int id;
+ struct slist *stmts; /* side effect stmts */
+ struct stmt s; /* branch stmt */
+ int mark;
+ int level;
+ int offset;
+ int sense;
+ struct edge et;
+ struct edge ef;
+ struct block *head;
+ struct block *link; /* link field used by optimizer */
+ uset dom;
+ uset closure;
+ struct edge *in_edges;
+ atomset def, kill;
+ atomset in_use;
+ atomset out_use;
+ long oval;
+ long val[N_ATOMS];
+};
+
+struct arth {
+ struct block *b; /* protocol checks */
+ struct slist *s; /* stmt list */
+ int regno; /* virtual register number of result */
+};
+
+struct qual {
+ unsigned char addr;
+ unsigned char proto;
+ unsigned char dir;
+ unsigned char pad;
+};
+
+#ifndef __GNUC__
+#define volatile
+#endif
+
+struct arth *gen_loadi(int);
+struct arth *gen_load(int, struct arth *, int);
+struct arth *gen_loadlen(void);
+struct arth *gen_neg(struct arth *);
+struct arth *gen_arth(int, struct arth *, struct arth *);
+
+void gen_and(struct block *, struct block *);
+void gen_or(struct block *, struct block *);
+void gen_not(struct block *);
+
+struct block *gen_scode(char *, struct qual);
+struct block *gen_ecode(u_char *, struct qual);
+struct block *gen_ncode(u_long, struct qual);
+struct block *gen_proto_abbrev(int);
+struct block *gen_relation(int, struct arth *, struct arth *, int);
+struct block *gen_less(int);
+struct block *gen_greater(int);
+struct block *gen_byteop(int, int, int);
+struct block *gen_broadcast(int);
+struct block *gen_multicast(int);
+struct block *gen_inbound(int);
+
+void bpf_optimize(struct block **);
+volatile void bpf_error(char *, ...);
+
+void finish_parse(struct block *);
+char *sdup(char *);
+
+struct bpf_insn *icode_to_fcode(struct block *, int *);
+int pcap_parse(void);
+void lex_init(char *);
+void sappend(struct slist *, struct slist *);
+
+/* XXX */
+#define JT(b) ((b)->et.succ)
+#define JF(b) ((b)->ef.succ)
diff --git a/lib/libpcap/grammar.y b/lib/libpcap/grammar.y
new file mode 100644
index 0000000..55fa198
--- /dev/null
+++ b/lib/libpcap/grammar.y
@@ -0,0 +1,264 @@
+%{
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: grammar.y,v 1.39 94/06/14 20:09:25 leres Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <stdio.h>
+#include <pcap.h>
+#include <pcap-namedb.h>
+
+#include "gencode.h"
+
+#define QSET(q, p, d, a) (q).proto = (p),\
+ (q).dir = (d),\
+ (q).addr = (a)
+
+int n_errors = 0;
+
+static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
+
+static void
+yyerror(char *msg)
+{
+ ++n_errors;
+ bpf_error(msg);
+ /* NOTREACHED */
+}
+
+#ifndef YYBISON
+pcap_parse()
+{
+ return (yyparse());
+}
+#endif
+
+%}
+
+%union {
+ int i;
+ u_long h;
+ u_char *e;
+ char *s;
+ struct stmt *stmt;
+ struct arth *a;
+ struct {
+ struct qual q;
+ struct block *b;
+ } blk;
+ struct block *rblk;
+}
+
+%type <blk> expr id nid pid term rterm qid
+%type <blk> head
+%type <i> pqual dqual aqual ndaqual
+%type <a> arth narth
+%type <i> byteop pname pnum relop irelop
+%type <blk> and or paren not null prog
+%type <rblk> other
+
+%token DST SRC HOST GATEWAY
+%token NET PORT LESS GREATER PROTO BYTE
+%token ARP RARP IP TCP UDP ICMP
+%token DECNET LAT MOPRC MOPDL
+%token TK_BROADCAST TK_MULTICAST
+%token NUM INBOUND OUTBOUND
+%token LINK
+%token GEQ LEQ NEQ
+%token ID EID HID
+%token LSH RSH
+%token LEN
+
+%type <s> ID
+%type <e> EID
+%type <h> HID
+%type <i> NUM
+
+%left OR AND
+%nonassoc '!'
+%left '|'
+%left '&'
+%left LSH RSH
+%left '+' '-'
+%left '*' '/'
+%nonassoc UMINUS
+%%
+prog: null expr
+{
+ finish_parse($2.b);
+}
+ | null
+ ;
+null: /* null */ { $$.q = qerr; }
+ ;
+expr: term
+ | expr and term { gen_and($1.b, $3.b); $$ = $3; }
+ | expr and id { gen_and($1.b, $3.b); $$ = $3; }
+ | expr or term { gen_or($1.b, $3.b); $$ = $3; }
+ | expr or id { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+and: AND { $$ = $<blk>0; }
+ ;
+or: OR { $$ = $<blk>0; }
+ ;
+id: nid
+ | pnum { $$.b = gen_ncode((u_long)$1,
+ $$.q = $<blk>0.q); }
+ | paren pid ')' { $$ = $2; }
+ ;
+nid: ID { $$.b = gen_scode($1, $$.q = $<blk>0.q); }
+ | HID {
+ /* Decide how to parse HID based on proto */
+ $$.q = $<blk>0.q;
+ switch ($$.q.proto) {
+ case Q_DECNET:
+ $$.b =
+ gen_ncode(__pcap_atodn((char *)$1),
+ $$.q);
+ break;
+ default:
+ $$.b =
+ gen_ncode(__pcap_atoin((char *)$1),
+ $$.q);
+ break;
+ }
+ }
+ | EID { $$.b = gen_ecode($1, $$.q = $<blk>0.q); }
+ | not id { gen_not($2.b); $$ = $2; }
+ ;
+not: '!' { $$ = $<blk>0; }
+ ;
+paren: '(' { $$ = $<blk>0; }
+ ;
+pid: nid
+ | qid and id { gen_and($1.b, $3.b); $$ = $3; }
+ | qid or id { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+qid: pnum { $$.b = gen_ncode((u_long)$1,
+ $$.q = $<blk>0.q); }
+ | pid
+ ;
+term: rterm
+ | not term { gen_not($2.b); $$ = $2; }
+ ;
+head: pqual dqual aqual { QSET($$.q, $1, $2, $3); }
+ | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); }
+ | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); }
+ | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); }
+ | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); }
+ ;
+rterm: head id { $$ = $2; }
+ | paren expr ')' { $$.b = $2.b; $$.q = $1.q; }
+ | pname { $$.b = gen_proto_abbrev($1); $$.q = qerr; }
+ | arth relop arth { $$.b = gen_relation($2, $1, $3, 0);
+ $$.q = qerr; }
+ | arth irelop arth { $$.b = gen_relation($2, $1, $3, 1);
+ $$.q = qerr; }
+ | other { $$.b = $1; $$.q = qerr; }
+ ;
+/* protocol level qualifiers */
+pqual: pname
+ | { $$ = Q_DEFAULT; }
+ ;
+/* 'direction' qualifiers */
+dqual: SRC { $$ = Q_SRC; }
+ | DST { $$ = Q_DST; }
+ | SRC OR DST { $$ = Q_OR; }
+ | DST OR SRC { $$ = Q_OR; }
+ | SRC AND DST { $$ = Q_AND; }
+ | DST AND SRC { $$ = Q_AND; }
+ ;
+/* address type qualifiers */
+aqual: HOST { $$ = Q_HOST; }
+ | NET { $$ = Q_NET; }
+ | PORT { $$ = Q_PORT; }
+ ;
+/* non-directional address type qualifiers */
+ndaqual: GATEWAY { $$ = Q_GATEWAY; }
+ ;
+pname: LINK { $$ = Q_LINK; }
+ | IP { $$ = Q_IP; }
+ | ARP { $$ = Q_ARP; }
+ | RARP { $$ = Q_RARP; }
+ | TCP { $$ = Q_TCP; }
+ | UDP { $$ = Q_UDP; }
+ | ICMP { $$ = Q_ICMP; }
+ | DECNET { $$ = Q_DECNET; }
+ | LAT { $$ = Q_LAT; }
+ | MOPDL { $$ = Q_MOPDL; }
+ | MOPRC { $$ = Q_MOPRC; }
+ ;
+other: pqual TK_BROADCAST { $$ = gen_broadcast($1); }
+ | pqual TK_MULTICAST { $$ = gen_multicast($1); }
+ | LESS NUM { $$ = gen_less($2); }
+ | GREATER NUM { $$ = gen_greater($2); }
+ | BYTE NUM byteop NUM { $$ = gen_byteop($3, $2, $4); }
+ | INBOUND { $$ = gen_inbound(0); }
+ | OUTBOUND { $$ = gen_inbound(1); }
+ ;
+relop: '>' { $$ = BPF_JGT; }
+ | GEQ { $$ = BPF_JGE; }
+ | '=' { $$ = BPF_JEQ; }
+ ;
+irelop: LEQ { $$ = BPF_JGT; }
+ | '<' { $$ = BPF_JGE; }
+ | NEQ { $$ = BPF_JEQ; }
+ ;
+arth: pnum { $$ = gen_loadi($1); }
+ | narth
+ ;
+narth: pname '[' arth ']' { $$ = gen_load($1, $3, 1); }
+ | pname '[' arth ':' NUM ']' { $$ = gen_load($1, $3, $5); }
+ | arth '+' arth { $$ = gen_arth(BPF_ADD, $1, $3); }
+ | arth '-' arth { $$ = gen_arth(BPF_SUB, $1, $3); }
+ | arth '*' arth { $$ = gen_arth(BPF_MUL, $1, $3); }
+ | arth '/' arth { $$ = gen_arth(BPF_DIV, $1, $3); }
+ | arth '&' arth { $$ = gen_arth(BPF_AND, $1, $3); }
+ | arth '|' arth { $$ = gen_arth(BPF_OR, $1, $3); }
+ | arth LSH arth { $$ = gen_arth(BPF_LSH, $1, $3); }
+ | arth RSH arth { $$ = gen_arth(BPF_RSH, $1, $3); }
+ | '-' arth %prec UMINUS { $$ = gen_neg($2); }
+ | paren narth ')' { $$ = $2; }
+ | LEN { $$ = gen_loadlen(); }
+ ;
+byteop: '&' { $$ = '&'; }
+ | '|' { $$ = '|'; }
+ | '<' { $$ = '<'; }
+ | '>' { $$ = '>'; }
+ | '=' { $$ = '='; }
+ ;
+pnum: NUM
+ | paren pnum ')' { $$ = $2; }
+ ;
+%%
diff --git a/lib/libpcap/inet.c b/lib/libpcap/inet.c
new file mode 100644
index 0000000..004e275
--- /dev/null
+++ b/lib/libpcap/inet.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: inet.c,v 1.4 94/06/07 01:16:50 leres Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef SOLARIS
+#include <sys/sockio.h>
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pcap.h>
+
+/* Not all systems have IFF_LOOPBACK */
+#ifdef IFF_LOOPBACK
+#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK)
+#else
+#define ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0)
+#endif
+
+/*
+ * Return the name of a network interface attached to the system, or NULL
+ * if none can be found. The interface must be configured up; the
+ * lowest unit number is preferred; loopback is ignored.
+ */
+char *
+pcap_lookupdev(errbuf)
+ register char *errbuf;
+{
+ register int fd, minunit, n;
+ register char *cp;
+ register struct ifreq *ifrp, *ifend, *ifnext, *mp;
+ struct ifconf ifc;
+ struct ifreq ibuf[16], ifr;
+ static char device[sizeof(ifrp->ifr_name) + 1];
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ (void)sprintf(errbuf, "socket: %s", pcap_strerror(errno));
+ return (NULL);
+ }
+ ifc.ifc_len = sizeof ibuf;
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ (void)sprintf(errbuf, "SIOCGIFCONF: %s", pcap_strerror(errno));
+ (void)close(fd);
+ return (NULL);
+ }
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ mp = NULL;
+ minunit = 666;
+ for (; ifrp < ifend; ifrp = ifnext) {
+#if BSD - 0 >= 199006
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ifnext = ifrp + 1;
+ else
+ ifnext = (struct ifreq *)((char *)ifrp + n);
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+#else
+ ifnext = ifrp + 1;
+#endif
+ /*
+ * Need a template to preserve address info that is
+ * used below to locate the next entry. (Otherwise,
+ * SIOCGIFFLAGS stomps over it because the requests
+ * are returned in a union.)
+ */
+ strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ (void)sprintf(errbuf, "SIOCGIFFLAGS: %s",
+ pcap_strerror(errno));
+ (void)close(fd);
+ return (NULL);
+ }
+
+ /* Must be up and not the loopback */
+ if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr))
+ continue;
+
+ for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
+ continue;
+ n = atoi(cp);
+ if (n < minunit) {
+ minunit = n;
+ mp = ifrp;
+ }
+ }
+ (void)close(fd);
+ if (mp == NULL) {
+ (void)strcpy(errbuf, "no suitable device found");
+ return (NULL);
+ }
+
+ (void)strncpy(device, mp->ifr_name, sizeof(device) - 1);
+ device[sizeof(device) - 1] = '\0';
+ return (device);
+}
+
+int
+pcap_lookupnet(device, netp, maskp, errbuf)
+ register char *device;
+ register u_long *netp, *maskp;
+ register char *errbuf;
+{
+ register int fd;
+ register struct sockaddr_in *sin;
+ struct ifreq ifr;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ (void)sprintf(errbuf, "socket: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+ (void)sprintf(errbuf, "SIOCGIFADDR: %s: %s",
+ device, pcap_strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+ sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ *netp = sin->sin_addr.s_addr;
+ if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
+ (void)sprintf(errbuf, "SIOCGIFNETMASK: %s: %s",
+ device, pcap_strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+ (void)close(fd);
+ *maskp = sin->sin_addr.s_addr;
+ if (*maskp == 0) {
+ if (IN_CLASSA(*netp))
+ *maskp = IN_CLASSA_NET;
+ else if (IN_CLASSB(*netp))
+ *maskp = IN_CLASSB_NET;
+ else if (IN_CLASSC(*netp))
+ *maskp = IN_CLASSC_NET;
+ else {
+ (void)sprintf(errbuf, "inet class for 0x%x unknown",
+ *netp);
+ return (-1);
+ }
+ }
+ *netp &= *maskp;
+ return (0);
+}
diff --git a/lib/libpcap/nametoaddr.c b/lib/libpcap/nametoaddr.c
new file mode 100644
index 0000000..0d8bbf7
--- /dev/null
+++ b/lib/libpcap/nametoaddr.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Name to id translation routines used by the scanner.
+ * These functions are not time critical.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: nametoaddr.c,v 1.21 94/06/20 19:07:54 leres Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pcap.h>
+#include <pcap-namedb.h>
+#include <stdio.h>
+
+#include "gencode.h"
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+#ifndef NTOHL
+#define NTOHL(x) (x) = ntohl(x)
+#define NTOHS(x) (x) = ntohs(x)
+#endif
+
+static inline int xdtoi(int);
+
+/*
+ * Convert host name to internet address.
+ * Return 0 upon failure.
+ */
+u_long **
+pcap_nametoaddr(const char *name)
+{
+#ifndef h_addr
+ static u_long *hlist[2];
+#endif
+ u_long **p;
+ struct hostent *hp;
+
+ if ((hp = gethostbyname(name)) != NULL) {
+#ifndef h_addr
+ hlist[0] = (u_long *)hp->h_addr;
+ NTOHL(hp->h_addr);
+ return hlist;
+#else
+ for (p = (u_long **)hp->h_addr_list; *p; ++p)
+ NTOHL(**p);
+ return (u_long **)hp->h_addr_list;
+#endif
+ }
+ else
+ return 0;
+}
+
+/*
+ * Convert net name to internet address.
+ * Return 0 upon failure.
+ */
+u_long
+pcap_nametonetaddr(const char *name)
+{
+ struct netent *np;
+
+ if ((np = getnetbyname(name)) != NULL)
+ return np->n_net;
+ else
+ return 0;
+}
+
+/*
+ * Convert a port name to its port and protocol numbers.
+ * We assume only TCP or UDP.
+ * Return 0 upon failure.
+ */
+int
+pcap_nametoport(const char *name, int *port, int *proto)
+{
+ struct servent *sp;
+ char *other;
+
+ sp = getservbyname(name, (char *)0);
+ if (sp != NULL) {
+ NTOHS(sp->s_port);
+ *port = sp->s_port;
+ *proto = pcap_nametoproto(sp->s_proto);
+ /*
+ * We need to check /etc/services for ambiguous entries.
+ * If we find the ambiguous entry, and it has the
+ * same port number, change the proto to PROTO_UNDEF
+ * so both TCP and UDP will be checked.
+ */
+ if (*proto == IPPROTO_TCP)
+ other = "udp";
+ else
+ other = "tcp";
+
+ sp = getservbyname(name, other);
+ if (sp != 0) {
+ NTOHS(sp->s_port);
+ if (*port != sp->s_port)
+ /* Can't handle ambiguous names that refer
+ to different port numbers. */
+#ifdef notdef
+ warning("ambiguous port %s in /etc/services",
+ name);
+#else
+ ;
+#endif
+ *proto = PROTO_UNDEF;
+ }
+ return 1;
+ }
+#if defined(ultrix) || defined(__osf__)
+ /* Special hack in case NFS isn't in /etc/services */
+ if (strcmp(name, "nfs") == 0) {
+ *port = 2049;
+ *proto = PROTO_UNDEF;
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+int
+pcap_nametoproto(const char *str)
+{
+ struct protoent *p;
+
+ p = getprotobyname(str);
+ if (p != 0)
+ return p->p_proto;
+ else
+ return PROTO_UNDEF;
+}
+
+#include "ethertype.h"
+
+struct eproto {
+ char *s;
+ u_short p;
+};
+
+/* Static data base of ether protocol types. */
+struct eproto eproto_db[] = {
+ { "pup", ETHERTYPE_PUP },
+ { "xns", ETHERTYPE_NS },
+ { "ip", ETHERTYPE_IP },
+ { "arp", ETHERTYPE_ARP },
+ { "rarp", ETHERTYPE_REVARP },
+ { "sprite", ETHERTYPE_SPRITE },
+ { "mopdl", ETHERTYPE_MOPDL },
+ { "moprc", ETHERTYPE_MOPRC },
+ { "decnet", ETHERTYPE_DN },
+ { "lat", ETHERTYPE_LAT },
+ { "lanbridge", ETHERTYPE_LANBRIDGE },
+ { "vexp", ETHERTYPE_VEXP },
+ { "vprod", ETHERTYPE_VPROD },
+ { "atalk", ETHERTYPE_ATALK },
+ { "atalkarp", ETHERTYPE_AARP },
+ { "loopback", ETHERTYPE_LOOPBACK },
+ { "decdts", ETHERTYPE_DECDTS },
+ { "decdns", ETHERTYPE_DECDNS },
+ { (char *)0, 0 }
+};
+
+int
+pcap_nametoeproto(const char *s)
+{
+ struct eproto *p = eproto_db;
+
+ while (p->s != 0) {
+ if (strcmp(p->s, s) == 0)
+ return p->p;
+ p += 1;
+ }
+ return PROTO_UNDEF;
+}
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+ register int c;
+{
+ if (isdigit(c))
+ return c - '0';
+ else if (islower(c))
+ return c - 'a' + 10;
+ else
+ return c - 'A' + 10;
+}
+
+u_long
+__pcap_atoin(const char *s)
+{
+ u_long addr = 0;
+ u_int n;
+
+ while (1) {
+ n = 0;
+ while (*s && *s != '.')
+ n = n * 10 + *s++ - '0';
+ addr <<= 8;
+ addr |= n & 0xff;
+ if (*s == '\0')
+ return addr;
+ ++s;
+ }
+ /* NOTREACHED */
+}
+
+u_long
+__pcap_atodn(const char *s)
+{
+#define AREASHIFT 10
+#define AREAMASK 0176000
+#define NODEMASK 01777
+
+ u_long addr = 0;
+ u_int node, area;
+
+ if (sscanf((char *)s, "%d.%d", &area, &node) != 2)
+ bpf_error("malformed decnet address '%s'", s);
+
+ addr = (area << AREASHIFT) & AREAMASK;
+ addr |= (node & NODEMASK);
+
+ return(addr);
+}
+
+/*
+ * Convert 's' which has the form "xx:xx:xx:xx:xx:xx" into a new
+ * ethernet address. Assumes 's' is well formed.
+ */
+u_char *
+pcap_ether_aton(const char *s)
+{
+ register u_char *ep, *e;
+ register u_int d;
+
+ e = ep = (u_char *)malloc(6);
+
+ while (*s) {
+ if (*s == ':')
+ s += 1;
+ d = xdtoi(*s++);
+ if (isxdigit(*s)) {
+ d <<= 4;
+ d |= xdtoi(*s++);
+ }
+ *ep++ = d;
+ }
+
+ return (e);
+}
+
+#ifndef ETHER_SERVICE
+/* Roll our own */
+u_char *
+pcap_ether_hostton(const char *name)
+{
+ register struct pcap_etherent *ep;
+ register u_char *ap;
+ static FILE *fp = NULL;
+ static init = 0;
+
+ if (!init) {
+ fp = fopen(PCAP_ETHERS_FILE, "r");
+ ++init;
+ if (fp == NULL)
+ return (NULL);
+ } else if (fp == NULL)
+ return (NULL);
+ else
+ rewind(fp);
+
+ while ((ep = pcap_next_etherent(fp)) != NULL) {
+ if (strcmp(ep->name, name) == 0) {
+ ap = (u_char *)malloc(6);
+ if (ap != NULL) {
+ memcpy(ap, ep->addr, 6);
+ return (ap);
+ }
+ break;
+ }
+ }
+ return (NULL);
+}
+#else
+/* Use the os supplied routines */
+u_char *
+pcap_ether_hostton(const char *name)
+{
+ register u_char *ap;
+ u_char a[6];
+#ifndef sgi
+ extern int ether_hostton(char *, struct ether_addr *);
+#endif
+
+ ap = NULL;
+ if (ether_hostton((char*)name, (struct ether_addr *)a) == 0) {
+ ap = (u_char *)malloc(6);
+ if (ap != NULL)
+ memcpy(ap, a, 6);
+ }
+ return (ap);
+}
+#endif
+
+u_short
+__pcap_nametodnaddr(const char *name)
+{
+#ifdef DECNETLIB
+ struct nodeent *getnodebyname();
+ struct nodeent *nep;
+ unsigned short res;
+
+ nep = getnodebyname(name);
+ if (nep == ((struct nodeent *)0))
+ bpf_error("unknown decnet host name '%s'\n", name);
+
+ memcpy((char *)&res, (char *)nep->n_addr, sizeof(unsigned short));
+ return(res);
+#else
+ bpf_error("decnet name support not included, '%s' cannot be translated\n",
+ name);
+#endif
+}
diff --git a/lib/libpcap/optimize.c b/lib/libpcap/optimize.c
new file mode 100644
index 0000000..50eb88e
--- /dev/null
+++ b/lib/libpcap/optimize.c
@@ -0,0 +1,1923 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Optimization module for tcpdump intermediate representation.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: optimize.c,v 1.45 94/06/20 19:07:55 leres Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <net/bpf.h>
+
+#include <stdio.h>
+#ifdef __osf__
+#include <stdlib.h>
+#include <malloc.h>
+#endif
+#include <memory.h>
+
+#include "gencode.h"
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+#define A_ATOM BPF_MEMWORDS
+#define X_ATOM (BPF_MEMWORDS+1)
+
+#define NOP -1
+
+/*
+ * This define is used to represent *both* the accumulator and
+ * x register in use-def computations.
+ * Currently, the use-def code assumes only one definition per instruction.
+ */
+#define AX_ATOM N_ATOMS
+
+/*
+ * A flag to indicate that further optimization is needed.
+ * Iterative passes are continued until a given pass yields no
+ * branch movement.
+ */
+static int done;
+
+/*
+ * A block is marked if only if its mark equals the current mark.
+ * Rather than traverse the code array, marking each item, 'cur_mark' is
+ * incremented. This automatically makes each element unmarked.
+ */
+static int cur_mark;
+#define isMarked(p) ((p)->mark == cur_mark)
+#define unMarkAll() cur_mark += 1
+#define Mark(p) ((p)->mark = cur_mark)
+
+static void opt_init(struct block *);
+static void opt_cleanup(void);
+
+static void make_marks(struct block *);
+static void mark_code(struct block *);
+
+static void intern_blocks(struct block *);
+
+static int eq_slist(struct slist *, struct slist *);
+
+static void find_levels_r(struct block *);
+
+static void find_levels(struct block *);
+static void find_dom(struct block *);
+static void propedom(struct edge *);
+static void find_edom(struct block *);
+static void find_closure(struct block *);
+static int atomuse(struct stmt *);
+static int atomdef(struct stmt *);
+static void compute_local_ud(struct block *);
+static void find_ud(struct block *);
+static void init_val(void);
+static long F(int, long, long);
+static inline void vstore(struct stmt *, long *, long, int);
+static void opt_blk(struct block *, int);
+static int use_conflict(struct block *, struct block *);
+static void opt_j(struct edge *);
+static void or_pullup(struct block *);
+static void and_pullup(struct block *);
+static void opt_blks(struct block *, int);
+static inline void link_inedge(struct edge *, struct block *);
+static void find_inedges(struct block *);
+static void opt_root(struct block **);
+static void opt_loop(struct block *, int);
+static void fold_op(struct stmt *, long, long);
+static inline struct slist *this_op(struct slist *);
+static void opt_not(struct block *);
+static void opt_peep(struct block *);
+static void opt_stmt(struct stmt *, long[], int);
+static void deadstmt(struct stmt *, struct stmt *[]);
+static void opt_deadstores(struct block *);
+static void opt_blk(struct block *, int);
+static int use_conflict(struct block *, struct block *);
+static void opt_j(struct edge *);
+static struct block *fold_edge(struct block *, struct edge *);
+static inline int eq_blk(struct block *, struct block *);
+static int slength(struct slist *);
+static int count_blocks(struct block *);
+static void number_blks_r(struct block *);
+static int count_stmts(struct block *);
+static void convert_code_r(struct block *);
+
+static int n_blocks;
+struct block **blocks;
+static int n_edges;
+struct edge **edges;
+
+/*
+ * A bit vector set representation of the dominators.
+ * We round up the set size to the next power of two.
+ */
+static int nodewords;
+static int edgewords;
+struct block **levels;
+u_long *space;
+#define BITS_PER_WORD (8*sizeof(u_long))
+/*
+ * True if a is in uset {p}
+ */
+#define SET_MEMBER(p, a) \
+((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))
+
+/*
+ * Add 'a' to uset p.
+ */
+#define SET_INSERT(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * Delete 'a' from uset p.
+ */
+#define SET_DELETE(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * a := a intersect b
+ */
+#define SET_INTERSECT(a, b, n)\
+{\
+ register u_long *_x = a, *_y = b;\
+ register int _n = n;\
+ while (--_n >= 0) *_x++ &= *_y++;\
+}
+
+/*
+ * a := a - b
+ */
+#define SET_SUBTRACT(a, b, n)\
+{\
+ register u_long *_x = a, *_y = b;\
+ register int _n = n;\
+ while (--_n >= 0) *_x++ &=~ *_y++;\
+}
+
+/*
+ * a := a union b
+ */
+#define SET_UNION(a, b, n)\
+{\
+ register u_long *_x = a, *_y = b;\
+ register int _n = n;\
+ while (--_n >= 0) *_x++ |= *_y++;\
+}
+
+static uset all_dom_sets;
+static uset all_closure_sets;
+static uset all_edge_sets;
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+static void
+find_levels_r(b)
+ struct block *b;
+{
+ int level;
+
+ if (isMarked(b))
+ return;
+
+ Mark(b);
+ b->link = 0;
+
+ if (JT(b)) {
+ find_levels_r(JT(b));
+ find_levels_r(JF(b));
+ level = MAX(JT(b)->level, JF(b)->level) + 1;
+ } else
+ level = 0;
+ b->level = level;
+ b->link = levels[level];
+ levels[level] = b;
+}
+
+/*
+ * Level graph. The levels go from 0 at the leaves to
+ * N_LEVELS at the root. The levels[] array points to the
+ * first node of the level list, whose elements are linked
+ * with the 'link' field of the struct block.
+ */
+static void
+find_levels(root)
+ struct block *root;
+{
+ memset((char *)levels, 0, n_blocks * sizeof(*levels));
+ unMarkAll();
+ find_levels_r(root);
+}
+
+/*
+ * Find dominator relationships.
+ * Assumes graph has been leveled.
+ */
+static void
+find_dom(root)
+ struct block *root;
+{
+ int i;
+ struct block *b;
+ u_long *x;
+
+ /*
+ * Initialize sets to contain all nodes.
+ */
+ x = all_dom_sets;
+ i = n_blocks * nodewords;
+ while (--i >= 0)
+ *x++ = ~0;
+ /* Root starts off empty. */
+ for (i = nodewords; --i >= 0;)
+ root->dom[i] = 0;
+
+ /* root->level is the highest level no found. */
+ for (i = root->level; i >= 0; --i) {
+ for (b = levels[i]; b; b = b->link) {
+ SET_INSERT(b->dom, b->id);
+ if (JT(b) == 0)
+ continue;
+ SET_INTERSECT(JT(b)->dom, b->dom, nodewords);
+ SET_INTERSECT(JF(b)->dom, b->dom, nodewords);
+ }
+ }
+}
+
+static void
+propedom(ep)
+ struct edge *ep;
+{
+ SET_INSERT(ep->edom, ep->id);
+ if (ep->succ) {
+ SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords);
+ SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords);
+ }
+}
+
+/*
+ * Compute edge dominators.
+ * Assumes graph has been leveled and predecessors established.
+ */
+static void
+find_edom(root)
+ struct block *root;
+{
+ int i;
+ uset x;
+ struct block *b;
+
+ x = all_edge_sets;
+ for (i = n_edges * edgewords; --i >= 0; )
+ x[i] = ~0;
+
+ /* root->level is the highest level no found. */
+ memset(root->et.edom, 0, edgewords * sizeof(*(uset)0));
+ memset(root->ef.edom, 0, edgewords * sizeof(*(uset)0));
+ for (i = root->level; i >= 0; --i) {
+ for (b = levels[i]; b != 0; b = b->link) {
+ propedom(&b->et);
+ propedom(&b->ef);
+ }
+ }
+}
+
+/*
+ * Find the backwards transitive closure of the flow graph. These sets
+ * are backwards in the sense that we find the set of nodes that reach
+ * a given node, not the set of nodes that can be reached by a node.
+ *
+ * Assumes graph has been leveled.
+ */
+static void
+find_closure(root)
+ struct block *root;
+{
+ int i;
+ struct block *b;
+
+ /*
+ * Initialize sets to contain no nodes.
+ */
+ memset((char *)all_closure_sets, 0,
+ n_blocks * nodewords * sizeof(*all_closure_sets));
+
+ /* root->level is the highest level no found. */
+ for (i = root->level; i >= 0; --i) {
+ for (b = levels[i]; b; b = b->link) {
+ SET_INSERT(b->closure, b->id);
+ if (JT(b) == 0)
+ continue;
+ SET_UNION(JT(b)->closure, b->closure, nodewords);
+ SET_UNION(JF(b)->closure, b->closure, nodewords);
+ }
+ }
+}
+
+/*
+ * Return the register number that is used by s. If A and X are both
+ * used, return AX_ATOM. If no register is used, return -1.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomuse(s)
+ struct stmt *s;
+{
+ register int c = s->code;
+
+ if (c == NOP)
+ return -1;
+
+ switch (BPF_CLASS(c)) {
+
+ case BPF_RET:
+ return (BPF_RVAL(c) == BPF_A) ? A_ATOM :
+ (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
+
+ case BPF_LD:
+ case BPF_LDX:
+ return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
+ (BPF_MODE(c) == BPF_MEM) ? s->k : -1;
+
+ case BPF_ST:
+ return A_ATOM;
+
+ case BPF_STX:
+ return X_ATOM;
+
+ case BPF_JMP:
+ case BPF_ALU:
+ if (BPF_SRC(c) == BPF_X)
+ return AX_ATOM;
+ return A_ATOM;
+
+ case BPF_MISC:
+ return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * Return the register number that is defined by 's'. We assume that
+ * a single stmt cannot define more than one register. If no register
+ * is defined, return -1.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomdef(s)
+ struct stmt *s;
+{
+ if (s->code == NOP)
+ return -1;
+
+ switch (BPF_CLASS(s->code)) {
+
+ case BPF_LD:
+ case BPF_ALU:
+ return A_ATOM;
+
+ case BPF_LDX:
+ return X_ATOM;
+
+ case BPF_ST:
+ case BPF_STX:
+ return s->k;
+
+ case BPF_MISC:
+ return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
+ }
+ return -1;
+}
+
+static void
+compute_local_ud(b)
+ struct block *b;
+{
+ struct slist *s;
+ atomset def = 0, use = 0, kill = 0;
+ int atom;
+
+ for (s = b->stmts; s; s = s->next) {
+ if (s->s.code == NOP)
+ continue;
+ atom = atomuse(&s->s);
+ if (atom >= 0) {
+ if (atom == AX_ATOM) {
+ if (!ATOMELEM(def, X_ATOM))
+ use |= ATOMMASK(X_ATOM);
+ if (!ATOMELEM(def, A_ATOM))
+ use |= ATOMMASK(A_ATOM);
+ }
+ else if (atom < N_ATOMS) {
+ if (!ATOMELEM(def, atom))
+ use |= ATOMMASK(atom);
+ }
+ else
+ abort();
+ }
+ atom = atomdef(&s->s);
+ if (atom >= 0) {
+ if (!ATOMELEM(use, atom))
+ kill |= ATOMMASK(atom);
+ def |= ATOMMASK(atom);
+ }
+ }
+ if (!ATOMELEM(def, A_ATOM) && BPF_CLASS(b->s.code) == BPF_JMP)
+ use |= ATOMMASK(A_ATOM);
+
+ b->def = def;
+ b->kill = kill;
+ b->in_use = use;
+}
+
+/*
+ * Assume graph is already leveled.
+ */
+static void
+find_ud(root)
+ struct block *root;
+{
+ int i, maxlevel;
+ struct block *p;
+
+ /*
+ * root->level is the highest level no found;
+ * count down from there.
+ */
+ maxlevel = root->level;
+ for (i = maxlevel; i >= 0; --i)
+ for (p = levels[i]; p; p = p->link) {
+ compute_local_ud(p);
+ p->out_use = 0;
+ }
+
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = levels[i]; p; p = p->link) {
+ p->out_use |= JT(p)->in_use | JF(p)->in_use;
+ p->in_use |= p->out_use &~ p->kill;
+ }
+ }
+}
+
+/*
+ * These data structures are used in a Cocke and Shwarz style
+ * value numbering scheme. Since the flowgraph is acyclic,
+ * exit values can be propagated from a node's predecessors
+ * provided it is uniquely defined.
+ */
+struct valnode {
+ int code;
+ long v0, v1;
+ long val;
+ struct valnode *next;
+};
+
+#define MODULUS 213
+static struct valnode *hashtbl[MODULUS];
+static int curval;
+static int maxval;
+
+/* Integer constants mapped with the load immediate opcode. */
+#define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L)
+
+struct vmapinfo {
+ int is_const;
+ long const_val;
+};
+
+struct vmapinfo *vmap;
+struct valnode *vnode_base;
+struct valnode *next_vnode;
+
+static void
+init_val()
+{
+ curval = 0;
+ next_vnode = vnode_base;
+ memset((char *)vmap, 0, maxval * sizeof(*vmap));
+ memset((char *)hashtbl, 0, sizeof hashtbl);
+}
+
+/* Because we really don't have an IR, this stuff is a little messy. */
+static long
+F(code, v0, v1)
+ int code;
+ long v0, v1;
+{
+ u_int hash;
+ int val;
+ struct valnode *p;
+
+ hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
+ hash %= MODULUS;
+
+ for (p = hashtbl[hash]; p; p = p->next)
+ if (p->code == code && p->v0 == v0 && p->v1 == v1)
+ return p->val;
+
+ val = ++curval;
+ if (BPF_MODE(code) == BPF_IMM &&
+ (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
+ vmap[val].const_val = v0;
+ vmap[val].is_const = 1;
+ }
+ p = next_vnode++;
+ p->val = val;
+ p->code = code;
+ p->v0 = v0;
+ p->v1 = v1;
+ p->next = hashtbl[hash];
+ hashtbl[hash] = p;
+
+ return val;
+}
+
+static inline void
+vstore(s, valp, newval, alter)
+ struct stmt *s;
+ long *valp;
+ long newval;
+ int alter;
+{
+ if (alter && *valp == newval)
+ s->code = NOP;
+ else
+ *valp = newval;
+}
+
+static void
+fold_op(s, v0, v1)
+ struct stmt *s;
+ long v0, v1;
+{
+ long a, b;
+
+ a = vmap[v0].const_val;
+ b = vmap[v1].const_val;
+
+ switch (BPF_OP(s->code)) {
+ case BPF_ADD:
+ a += b;
+ break;
+
+ case BPF_SUB:
+ a -= b;
+ break;
+
+ case BPF_MUL:
+ a *= b;
+ break;
+
+ case BPF_DIV:
+ if (b == 0)
+ bpf_error("division by zero");
+ a /= b;
+ break;
+
+ case BPF_AND:
+ a &= b;
+ break;
+
+ case BPF_OR:
+ a |= b;
+ break;
+
+ case BPF_LSH:
+ a <<= b;
+ break;
+
+ case BPF_RSH:
+ a >>= b;
+ break;
+
+ case BPF_NEG:
+ a = -a;
+ break;
+
+ default:
+ abort();
+ }
+ s->k = a;
+ s->code = BPF_LD|BPF_IMM;
+ done = 0;
+}
+
+static inline struct slist *
+this_op(s)
+ struct slist *s;
+{
+ while (s != 0 && s->s.code == NOP)
+ s = s->next;
+ return s;
+}
+
+static void
+opt_not(b)
+ struct block *b;
+{
+ struct block *tmp = JT(b);
+
+ JT(b) = JF(b);
+ JF(b) = tmp;
+}
+
+static void
+opt_peep(b)
+ struct block *b;
+{
+ struct slist *s;
+ struct slist *next, *last;
+ int val;
+ long v;
+
+ s = b->stmts;
+ if (s == 0)
+ return;
+
+ last = s;
+ while (1) {
+ s = this_op(s);
+ if (s == 0)
+ break;
+ next = this_op(s->next);
+ if (next == 0)
+ break;
+ last = next;
+
+ /*
+ * st M[k] --> st M[k]
+ * ldx M[k] tax
+ */
+ if (s->s.code == BPF_ST &&
+ next->s.code == (BPF_LDX|BPF_MEM) &&
+ s->s.k == next->s.k) {
+ done = 0;
+ next->s.code = BPF_MISC|BPF_TAX;
+ }
+ /*
+ * ld #k --> ldx #k
+ * tax txa
+ */
+ if (s->s.code == (BPF_LD|BPF_IMM) &&
+ next->s.code == (BPF_MISC|BPF_TAX)) {
+ s->s.code = BPF_LDX|BPF_IMM;
+ next->s.code = BPF_MISC|BPF_TXA;
+ done = 0;
+ }
+ /*
+ * This is an ugly special case, but it happens
+ * when you say tcp[k] or udp[k] where k is a constant.
+ */
+ if (s->s.code == (BPF_LD|BPF_IMM)) {
+ struct slist *add, *tax, *ild;
+
+ /*
+ * Check that X isn't used on exit from this
+ * block (which the optimizer might cause).
+ * We know the code generator won't generate
+ * any local dependencies.
+ */
+ if (ATOMELEM(b->out_use, X_ATOM))
+ break;
+
+ if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
+ add = next;
+ else
+ add = this_op(next->next);
+ if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X))
+ break;
+
+ tax = this_op(add->next);
+ if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX))
+ break;
+
+ ild = this_op(tax->next);
+ if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD ||
+ BPF_MODE(ild->s.code) != BPF_IND)
+ break;
+ /*
+ * XXX We need to check that X is not
+ * subsequently used. We know we can eliminate the
+ * accumulator modifications since it is defined
+ * by the last stmt of this sequence.
+ *
+ * We want to turn this sequence:
+ *
+ * (004) ldi #0x2 {s}
+ * (005) ldxms [14] {next} -- optional
+ * (006) addx {add}
+ * (007) tax {tax}
+ * (008) ild [x+0] {ild}
+ *
+ * into this sequence:
+ *
+ * (004) nop
+ * (005) ldxms [14]
+ * (006) nop
+ * (007) nop
+ * (008) ild [x+2]
+ *
+ */
+ ild->s.k += s->s.k;
+ s->s.code = NOP;
+ add->s.code = NOP;
+ tax->s.code = NOP;
+ done = 0;
+ }
+ s = next;
+ }
+ /*
+ * If we have a subtract to do a comparison, and the X register
+ * is a known constant, we can merge this value into the
+ * comparison.
+ */
+ if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X) &&
+ !ATOMELEM(b->out_use, A_ATOM)) {
+ val = b->val[X_ATOM];
+ if (vmap[val].is_const) {
+ b->s.k += vmap[val].const_val;
+ last->s.code = NOP;
+ done = 0;
+ } else if (b->s.k == 0) {
+ /*
+ * sub x -> nop
+ * j #0 j x
+ */
+ last->s.code = NOP;
+ b->s.code = BPF_CLASS(b->s.code) | BPF_OP(b->s.code) |
+ BPF_X;
+ done = 0;
+ }
+ }
+ /*
+ * Likewise, a constant subtract can be simplified.
+ */
+ else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K) &&
+ !ATOMELEM(b->out_use, A_ATOM)) {
+ b->s.k += last->s.k;
+ last->s.code = NOP;
+ done = 0;
+ }
+ /*
+ * and #k nop
+ * jeq #0 -> jset #k
+ */
+ if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) &&
+ !ATOMELEM(b->out_use, A_ATOM) && b->s.k == 0) {
+ b->s.k = last->s.k;
+ b->s.code = BPF_JMP|BPF_K|BPF_JSET;
+ last->s.code = NOP;
+ done = 0;
+ opt_not(b);
+ }
+ /*
+ * If the accumulator is a known constant, we can compute the
+ * comparison result.
+ */
+ val = b->val[A_ATOM];
+ if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
+ v = vmap[val].const_val;
+ switch (BPF_OP(b->s.code)) {
+
+ case BPF_JEQ:
+ v = v == b->s.k;
+ break;
+
+ case BPF_JGT:
+ v = v > b->s.k;
+ break;
+
+ case BPF_JGE:
+ v = v >= b->s.k;
+ break;
+
+ case BPF_JSET:
+ v &= b->s.k;
+ break;
+
+ default:
+ abort();
+ }
+ if (JF(b) != JT(b))
+ done = 0;
+ if (v)
+ JF(b) = JT(b);
+ else
+ JT(b) = JF(b);
+ }
+}
+
+/*
+ * Compute the symbolic value of expression of 's', and update
+ * anything it defines in the value table 'val'. If 'alter' is true,
+ * do various optimizations. This code would be cleaner if symbolic
+ * evaluation and code transformations weren't folded together.
+ */
+static void
+opt_stmt(s, val, alter)
+ struct stmt *s;
+ long val[];
+ int alter;
+{
+ int op;
+ long v;
+
+ switch (s->code) {
+
+ case BPF_LD|BPF_ABS|BPF_W:
+ case BPF_LD|BPF_ABS|BPF_H:
+ case BPF_LD|BPF_ABS|BPF_B:
+ v = F(s->code, s->k, 0L);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_IND|BPF_W:
+ case BPF_LD|BPF_IND|BPF_H:
+ case BPF_LD|BPF_IND|BPF_B:
+ v = val[X_ATOM];
+ if (alter && vmap[v].is_const) {
+ s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
+ s->k += vmap[v].const_val;
+ v = F(s->code, s->k, 0L);
+ done = 0;
+ }
+ else
+ v = F(s->code, s->k, v);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_LEN:
+ v = F(s->code, 0L, 0L);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_IMM:
+ v = K(s->k);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LDX|BPF_IMM:
+ v = K(s->k);
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ v = F(s->code, s->k, 0L);
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_ALU|BPF_NEG:
+ if (alter && vmap[val[A_ATOM]].is_const) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = -vmap[val[A_ATOM]].const_val;
+ val[A_ATOM] = K(s->k);
+ }
+ else
+ val[A_ATOM] = F(s->code, val[A_ATOM], 0L);
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ case BPF_ALU|BPF_SUB|BPF_K:
+ case BPF_ALU|BPF_MUL|BPF_K:
+ case BPF_ALU|BPF_DIV|BPF_K:
+ case BPF_ALU|BPF_AND|BPF_K:
+ case BPF_ALU|BPF_OR|BPF_K:
+ case BPF_ALU|BPF_LSH|BPF_K:
+ case BPF_ALU|BPF_RSH|BPF_K:
+ op = BPF_OP(s->code);
+ if (alter) {
+ if (s->k == 0) {
+ if (op == BPF_ADD || op == BPF_SUB ||
+ op == BPF_LSH || op == BPF_RSH ||
+ op == BPF_OR) {
+ s->code = NOP;
+ break;
+ }
+ if (op == BPF_MUL || op == BPF_AND) {
+ s->code = BPF_LD|BPF_IMM;
+ val[A_ATOM] = K(s->k);
+ break;
+ }
+ }
+ if (vmap[val[A_ATOM]].is_const) {
+ fold_op(s, val[A_ATOM], K(s->k));
+ val[A_ATOM] = K(s->k);
+ break;
+ }
+ }
+ val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k));
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ case BPF_ALU|BPF_SUB|BPF_X:
+ case BPF_ALU|BPF_MUL|BPF_X:
+ case BPF_ALU|BPF_DIV|BPF_X:
+ case BPF_ALU|BPF_AND|BPF_X:
+ case BPF_ALU|BPF_OR|BPF_X:
+ case BPF_ALU|BPF_LSH|BPF_X:
+ case BPF_ALU|BPF_RSH|BPF_X:
+ op = BPF_OP(s->code);
+ if (alter && vmap[val[X_ATOM]].is_const) {
+ if (vmap[val[A_ATOM]].is_const) {
+ fold_op(s, val[A_ATOM], val[X_ATOM]);
+ val[A_ATOM] = K(s->k);
+ }
+ else {
+ s->code = BPF_ALU|BPF_K|op;
+ s->k = vmap[val[X_ATOM]].const_val;
+ done = 0;
+ val[A_ATOM] =
+ F(s->code, val[A_ATOM], K(s->k));
+ }
+ break;
+ }
+ /*
+ * Check if we're doing something to an accumulator
+ * that is 0, and simplify. This may not seem like
+ * much of a simplification but it could open up further
+ * optimizations.
+ * XXX We could also check for mul by 1, and -1, etc.
+ */
+ if (alter && vmap[val[A_ATOM]].is_const
+ && vmap[val[A_ATOM]].const_val == 0) {
+ if (op == BPF_ADD || op == BPF_OR ||
+ op == BPF_LSH || op == BPF_RSH || op == BPF_SUB) {
+ s->code = BPF_MISC|BPF_TXA;
+ vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+ break;
+ }
+ else if (op == BPF_MUL || op == BPF_DIV ||
+ op == BPF_AND) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = 0;
+ vstore(s, &val[A_ATOM], K(s->k), alter);
+ break;
+ }
+ else if (op == BPF_NEG) {
+ s->code = NOP;
+ break;
+ }
+ }
+ val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]);
+ break;
+
+ case BPF_MISC|BPF_TXA:
+ vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+ break;
+
+ case BPF_LD|BPF_MEM:
+ v = val[s->k];
+ if (alter && vmap[v].is_const) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = vmap[v].const_val;
+ done = 0;
+ }
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_MISC|BPF_TAX:
+ vstore(s, &val[X_ATOM], val[A_ATOM], alter);
+ break;
+
+ case BPF_LDX|BPF_MEM:
+ v = val[s->k];
+ if (alter && vmap[v].is_const) {
+ s->code = BPF_LDX|BPF_IMM;
+ s->k = vmap[v].const_val;
+ done = 0;
+ }
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_ST:
+ vstore(s, &val[s->k], val[A_ATOM], alter);
+ break;
+
+ case BPF_STX:
+ vstore(s, &val[s->k], val[X_ATOM], alter);
+ break;
+ }
+}
+
+static void
+deadstmt(s, last)
+ register struct stmt *s;
+ register struct stmt *last[];
+{
+ register int atom;
+
+ atom = atomuse(s);
+ if (atom >= 0) {
+ if (atom == AX_ATOM) {
+ last[X_ATOM] = 0;
+ last[A_ATOM] = 0;
+ }
+ else
+ last[atom] = 0;
+ }
+ atom = atomdef(s);
+ if (atom >= 0) {
+ if (last[atom]) {
+ done = 0;
+ last[atom]->code = NOP;
+ }
+ last[atom] = s;
+ }
+}
+
+static void
+opt_deadstores(b)
+ register struct block *b;
+{
+ register struct slist *s;
+ register int atom;
+ struct stmt *last[N_ATOMS];
+
+ memset((char *)last, 0, sizeof last);
+
+ for (s = b->stmts; s != 0; s = s->next)
+ deadstmt(&s->s, last);
+ deadstmt(&b->s, last);
+
+ for (atom = 0; atom < N_ATOMS; ++atom)
+ if (last[atom] && !ATOMELEM(b->out_use, atom)) {
+ last[atom]->code = NOP;
+ done = 0;
+ }
+}
+
+static void
+opt_blk(b, do_stmts)
+ struct block *b;
+ int do_stmts;
+{
+ struct slist *s;
+ struct edge *p;
+ int i;
+ long aval;
+
+ /*
+ * Initialize the atom values.
+ * If we have no predecessors, everything is undefined.
+ * Otherwise, we inherent our values from our predecessors.
+ * If any register has an ambiguous value (i.e. control paths are
+ * merging) give it the undefined value of 0.
+ */
+ p = b->in_edges;
+ if (p == 0)
+ memset((char *)b->val, 0, sizeof(b->val));
+ else {
+ memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val));
+ while ((p = p->next) != NULL) {
+ for (i = 0; i < N_ATOMS; ++i)
+ if (b->val[i] != p->pred->val[i])
+ b->val[i] = 0;
+ }
+ }
+ aval = b->val[A_ATOM];
+ for (s = b->stmts; s; s = s->next)
+ opt_stmt(&s->s, b->val, do_stmts);
+
+ /*
+ * This is a special case: if we don't use anything from this
+ * block, and we load the accumulator with value that is
+ * already there, eliminate all the statements.
+ */
+ if (do_stmts && b->out_use == 0 && aval != 0 &&
+ b->val[A_ATOM] == aval)
+ b->stmts = 0;
+ else {
+ opt_peep(b);
+ opt_deadstores(b);
+ }
+ /*
+ * Set up values for branch optimizer.
+ */
+ if (BPF_SRC(b->s.code) == BPF_K)
+ b->oval = K(b->s.k);
+ else
+ b->oval = b->val[X_ATOM];
+ b->et.code = b->s.code;
+ b->ef.code = -b->s.code;
+}
+
+/*
+ * Return true if any register that is used on exit from 'succ', has
+ * an exit value that is different from the corresponding exit value
+ * from 'b'.
+ */
+static int
+use_conflict(b, succ)
+ struct block *b, *succ;
+{
+ int atom;
+ atomset use = succ->out_use;
+
+ if (use == 0)
+ return 0;
+
+ for (atom = 0; atom < N_ATOMS; ++atom)
+ if (ATOMELEM(use, atom))
+ if (b->val[atom] != succ->val[atom])
+ return 1;
+ return 0;
+}
+
+static struct block *
+fold_edge(child, ep)
+ struct block *child;
+ struct edge *ep;
+{
+ int sense;
+ int aval0, aval1, oval0, oval1;
+ int code = ep->code;
+
+ if (code < 0) {
+ code = -code;
+ sense = 0;
+ } else
+ sense = 1;
+
+ if (child->s.code != code)
+ return 0;
+
+ aval0 = child->val[A_ATOM];
+ oval0 = child->oval;
+ aval1 = ep->pred->val[A_ATOM];
+ oval1 = ep->pred->oval;
+
+ if (aval0 != aval1)
+ return 0;
+
+ if (oval0 == oval1)
+ /*
+ * The operands are identical, so the
+ * result is true if a true branch was
+ * taken to get here, otherwise false.
+ */
+ return sense ? JT(child) : JF(child);
+
+ if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
+ /*
+ * At this point, we only know the comparison if we
+ * came down the true branch, and it was an equality
+ * comparison with a constant. We rely on the fact that
+ * distinct constants have distinct value numbers.
+ */
+ return JF(child);
+
+ return 0;
+}
+
+static void
+opt_j(ep)
+ struct edge *ep;
+{
+ register int i, k;
+ register struct block *target;
+
+ if (JT(ep->succ) == 0)
+ return;
+
+ if (JT(ep->succ) == JF(ep->succ)) {
+ /*
+ * Common branch targets can be eliminated, provided
+ * there is no data dependency.
+ */
+ if (!use_conflict(ep->pred, ep->succ->et.succ)) {
+ done = 0;
+ ep->succ = JT(ep->succ);
+ }
+ }
+ /*
+ * For each edge dominator that matches the successor of this
+ * edge, promote the edge successor to the its grandchild.
+ *
+ * XXX We violate the set abstraction here in favor a reasonably
+ * efficient loop.
+ */
+ top:
+ for (i = 0; i < edgewords; ++i) {
+ register u_long x = ep->edom[i];
+
+ while (x != 0) {
+ k = ffs(x) - 1;
+ x &=~ (1 << k);
+ k += i * BITS_PER_WORD;
+
+ target = fold_edge(ep->succ, edges[k]);
+ /*
+ * Check that there is no data dependency between
+ * nodes that will be violated if we move the edge.
+ */
+ if (target != 0 && !use_conflict(ep->pred, target)) {
+ done = 0;
+ ep->succ = target;
+ if (JT(target) != 0)
+ /*
+ * Start over unless we hit a leaf.
+ */
+ goto top;
+ return;
+ }
+ }
+ }
+}
+
+
+static void
+or_pullup(b)
+ struct block *b;
+{
+ int val, at_top;
+ struct block *pull;
+ struct block **diffp, **samep;
+ struct edge *ep;
+
+ ep = b->in_edges;
+ if (ep == 0)
+ return;
+
+ /*
+ * Make sure each predecessor loads the same value.
+ * XXX why?
+ */
+ val = ep->pred->val[A_ATOM];
+ for (ep = ep->next; ep != 0; ep = ep->next)
+ if (val != ep->pred->val[A_ATOM])
+ return;
+
+ if (JT(b->in_edges->pred) == b)
+ diffp = &JT(b->in_edges->pred);
+ else
+ diffp = &JF(b->in_edges->pred);
+
+ at_top = 1;
+ while (1) {
+ if (*diffp == 0)
+ return;
+
+ if (JT(*diffp) != JT(b))
+ return;
+
+ if (!SET_MEMBER((*diffp)->dom, b->id))
+ return;
+
+ if ((*diffp)->val[A_ATOM] != val)
+ break;
+
+ diffp = &JF(*diffp);
+ at_top = 0;
+ }
+ samep = &JF(*diffp);
+ while (1) {
+ if (*samep == 0)
+ return;
+
+ if (JT(*samep) != JT(b))
+ return;
+
+ if (!SET_MEMBER((*samep)->dom, b->id))
+ return;
+
+ if ((*samep)->val[A_ATOM] == val)
+ break;
+
+ /* XXX Need to check that there are no data dependencies
+ between dp0 and dp1. Currently, the code generator
+ will not produce such dependencies. */
+ samep = &JF(*samep);
+ }
+#ifdef notdef
+ /* XXX This doesn't cover everything. */
+ for (i = 0; i < N_ATOMS; ++i)
+ if ((*samep)->val[i] != pred->val[i])
+ return;
+#endif
+ /* Pull up the node. */
+ pull = *samep;
+ *samep = JF(pull);
+ JF(pull) = *diffp;
+
+ /*
+ * At the top of the chain, each predecessor needs to point at the
+ * pulled up node. Inside the chain, there is only one predecessor
+ * to worry about.
+ */
+ if (at_top) {
+ for (ep = b->in_edges; ep != 0; ep = ep->next) {
+ if (JT(ep->pred) == b)
+ JT(ep->pred) = pull;
+ else
+ JF(ep->pred) = pull;
+ }
+ }
+ else
+ *diffp = pull;
+
+ done = 0;
+}
+
+static void
+and_pullup(b)
+ struct block *b;
+{
+ int val, at_top;
+ struct block *pull;
+ struct block **diffp, **samep;
+ struct edge *ep;
+
+ ep = b->in_edges;
+ if (ep == 0)
+ return;
+
+ /*
+ * Make sure each predecessor loads the same value.
+ */
+ val = ep->pred->val[A_ATOM];
+ for (ep = ep->next; ep != 0; ep = ep->next)
+ if (val != ep->pred->val[A_ATOM])
+ return;
+
+ if (JT(b->in_edges->pred) == b)
+ diffp = &JT(b->in_edges->pred);
+ else
+ diffp = &JF(b->in_edges->pred);
+
+ at_top = 1;
+ while (1) {
+ if (*diffp == 0)
+ return;
+
+ if (JF(*diffp) != JF(b))
+ return;
+
+ if (!SET_MEMBER((*diffp)->dom, b->id))
+ return;
+
+ if ((*diffp)->val[A_ATOM] != val)
+ break;
+
+ diffp = &JT(*diffp);
+ at_top = 0;
+ }
+ samep = &JT(*diffp);
+ while (1) {
+ if (*samep == 0)
+ return;
+
+ if (JF(*samep) != JF(b))
+ return;
+
+ if (!SET_MEMBER((*samep)->dom, b->id))
+ return;
+
+ if ((*samep)->val[A_ATOM] == val)
+ break;
+
+ /* XXX Need to check that there are no data dependencies
+ between diffp and samep. Currently, the code generator
+ will not produce such dependencies. */
+ samep = &JT(*samep);
+ }
+#ifdef notdef
+ /* XXX This doesn't cover everything. */
+ for (i = 0; i < N_ATOMS; ++i)
+ if ((*samep)->val[i] != pred->val[i])
+ return;
+#endif
+ /* Pull up the node. */
+ pull = *samep;
+ *samep = JT(pull);
+ JT(pull) = *diffp;
+
+ /*
+ * At the top of the chain, each predecessor needs to point at the
+ * pulled up node. Inside the chain, there is only one predecessor
+ * to worry about.
+ */
+ if (at_top) {
+ for (ep = b->in_edges; ep != 0; ep = ep->next) {
+ if (JT(ep->pred) == b)
+ JT(ep->pred) = pull;
+ else
+ JF(ep->pred) = pull;
+ }
+ }
+ else
+ *diffp = pull;
+
+ done = 0;
+}
+
+static void
+opt_blks(root, do_stmts)
+ struct block *root;
+ int do_stmts;
+{
+ int i, maxlevel;
+ struct block *p;
+
+ init_val();
+ maxlevel = root->level;
+ for (i = maxlevel; i >= 0; --i)
+ for (p = levels[i]; p; p = p->link)
+ opt_blk(p, do_stmts);
+
+ if (do_stmts)
+ /*
+ * No point trying to move branches; it can't possibly
+ * make a difference at this point.
+ */
+ return;
+
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = levels[i]; p; p = p->link) {
+ opt_j(&p->et);
+ opt_j(&p->ef);
+ }
+ }
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = levels[i]; p; p = p->link) {
+ or_pullup(p);
+ and_pullup(p);
+ }
+ }
+}
+
+static inline void
+link_inedge(parent, child)
+ struct edge *parent;
+ struct block *child;
+{
+ parent->next = child->in_edges;
+ child->in_edges = parent;
+}
+
+static void
+find_inedges(root)
+ struct block *root;
+{
+ int i;
+ struct block *b;
+
+ for (i = 0; i < n_blocks; ++i)
+ blocks[i]->in_edges = 0;
+
+ /*
+ * Traverse the graph, adding each edge to the predecessor
+ * list of its successors. Skip the leaves (i.e. level 0).
+ */
+ for (i = root->level; i > 0; --i) {
+ for (b = levels[i]; b != 0; b = b->link) {
+ link_inedge(&b->et, JT(b));
+ link_inedge(&b->ef, JF(b));
+ }
+ }
+}
+
+static void
+opt_root(b)
+ struct block **b;
+{
+ struct slist *tmp, *s;
+
+ s = (*b)->stmts;
+ (*b)->stmts = 0;
+ while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
+ *b = JT(*b);
+
+ tmp = (*b)->stmts;
+ if (tmp != 0)
+ sappend(s, tmp);
+ (*b)->stmts = s;
+}
+
+static void
+opt_loop(root, do_stmts)
+ struct block *root;
+ int do_stmts;
+{
+
+#ifdef BDEBUG
+ if (dflag > 1)
+ opt_dump(root);
+#endif
+ do {
+ done = 1;
+ find_levels(root);
+ find_dom(root);
+ find_closure(root);
+ find_inedges(root);
+ find_ud(root);
+ find_edom(root);
+ opt_blks(root, do_stmts);
+#ifdef BDEBUG
+ if (dflag > 1)
+ opt_dump(root);
+#endif
+ } while (!done);
+}
+
+/*
+ * Optimize the filter code in its dag representation.
+ */
+void
+bpf_optimize(rootp)
+ struct block **rootp;
+{
+ struct block *root;
+
+ root = *rootp;
+
+ opt_init(root);
+ opt_loop(root, 0);
+ opt_loop(root, 1);
+ intern_blocks(root);
+ opt_root(rootp);
+ opt_cleanup();
+}
+
+static void
+make_marks(p)
+ struct block *p;
+{
+ if (!isMarked(p)) {
+ Mark(p);
+ if (BPF_CLASS(p->s.code) != BPF_RET) {
+ make_marks(JT(p));
+ make_marks(JF(p));
+ }
+ }
+}
+
+/*
+ * Mark code array such that isMarked(i) is true
+ * only for nodes that are alive.
+ */
+static void
+mark_code(p)
+ struct block *p;
+{
+ cur_mark += 1;
+ make_marks(p);
+}
+
+/*
+ * True iff the two stmt lists load the same value from the packet into
+ * the accumulator.
+ */
+static int
+eq_slist(x, y)
+ struct slist *x, *y;
+{
+ while (1) {
+ while (x && x->s.code == NOP)
+ x = x->next;
+ while (y && y->s.code == NOP)
+ y = y->next;
+ if (x == 0)
+ return y == 0;
+ if (y == 0)
+ return x == 0;
+ if (x->s.code != y->s.code || x->s.k != y->s.k)
+ return 0;
+ x = x->next;
+ y = y->next;
+ }
+}
+
+static inline int
+eq_blk(b0, b1)
+ struct block *b0, *b1;
+{
+ if (b0->s.code == b1->s.code &&
+ b0->s.k == b1->s.k &&
+ b0->et.succ == b1->et.succ &&
+ b0->ef.succ == b1->ef.succ)
+ return eq_slist(b0->stmts, b1->stmts);
+ return 0;
+}
+
+static void
+intern_blocks(root)
+ struct block *root;
+{
+ struct block *p;
+ int i, j;
+ int done;
+ top:
+ done = 1;
+ for (i = 0; i < n_blocks; ++i)
+ blocks[i]->link = 0;
+
+ mark_code(root);
+
+ for (i = n_blocks - 1; --i >= 0; ) {
+ if (!isMarked(blocks[i]))
+ continue;
+ for (j = i + 1; j < n_blocks; ++j) {
+ if (!isMarked(blocks[j]))
+ continue;
+ if (eq_blk(blocks[i], blocks[j])) {
+ blocks[i]->link = blocks[j]->link ?
+ blocks[j]->link : blocks[j];
+ break;
+ }
+ }
+ }
+ for (i = 0; i < n_blocks; ++i) {
+ p = blocks[i];
+ if (JT(p) == 0)
+ continue;
+ if (JT(p)->link) {
+ done = 0;
+ JT(p) = JT(p)->link;
+ }
+ if (JF(p)->link) {
+ done = 0;
+ JF(p) = JF(p)->link;
+ }
+ }
+ if (!done)
+ goto top;
+}
+
+static void
+opt_cleanup()
+{
+ free((void *)vnode_base);
+ free((void *)vmap);
+ free((void *)edges);
+ free((void *)space);
+ free((void *)levels);
+ free((void *)blocks);
+}
+
+/*
+ * Return the number of stmts in 's'.
+ */
+static int
+slength(s)
+ struct slist *s;
+{
+ int n = 0;
+
+ for (; s; s = s->next)
+ if (s->s.code != NOP)
+ ++n;
+ return n;
+}
+
+/*
+ * Return the number of nodes reachable by 'p'.
+ * All nodes should be initially unmarked.
+ */
+static int
+count_blocks(p)
+ struct block *p;
+{
+ if (p == 0 || isMarked(p))
+ return 0;
+ Mark(p);
+ return count_blocks(JT(p)) + count_blocks(JF(p)) + 1;
+}
+
+/*
+ * Do a depth first search on the flow graph, numbering the
+ * the basic blocks, and entering them into the 'blocks' array.`
+ */
+static void
+number_blks_r(p)
+ struct block *p;
+{
+ int n;
+
+ if (p == 0 || isMarked(p))
+ return;
+
+ Mark(p);
+ n = n_blocks++;
+ p->id = n;
+ blocks[n] = p;
+
+ number_blks_r(JT(p));
+ number_blks_r(JF(p));
+}
+
+/*
+ * Return the number of stmts in the flowgraph reachable by 'p'.
+ * The nodes should be unmarked before calling.
+ */
+static int
+count_stmts(p)
+ struct block *p;
+{
+ int n;
+
+ if (p == 0 || isMarked(p))
+ return 0;
+ Mark(p);
+ n = count_stmts(JT(p)) + count_stmts(JF(p));
+ return slength(p->stmts) + n + 1;
+}
+
+/*
+ * Allocate memory. All allocation is done before optimization
+ * is begun. A linear bound on the size of all data structures is computed
+ * from the total number of blocks and/or statements.
+ */
+static void
+opt_init(root)
+ struct block *root;
+{
+ u_long *p;
+ int i, n, max_stmts;
+
+ /*
+ * First, count the blocks, so we can malloc an array to map
+ * block number to block. Then, put the blocks into the array.
+ */
+ unMarkAll();
+ n = count_blocks(root);
+ blocks = (struct block **)malloc(n * sizeof(*blocks));
+ unMarkAll();
+ n_blocks = 0;
+ number_blks_r(root);
+
+ n_edges = 2 * n_blocks;
+ edges = (struct edge **)malloc(n_edges * sizeof(*edges));
+
+ /*
+ * The number of levels is bounded by the number of nodes.
+ */
+ levels = (struct block **)malloc(n_blocks * sizeof(*levels));
+
+ edgewords = n_edges / (8 * sizeof(u_long)) + 1;
+ nodewords = n_blocks / (8 * sizeof(u_long)) + 1;
+
+ /* XXX */
+ space = (u_long *)malloc(2 * n_blocks * nodewords * sizeof(*space)
+ + n_edges * edgewords * sizeof(*space));
+ p = space;
+ all_dom_sets = p;
+ for (i = 0; i < n; ++i) {
+ blocks[i]->dom = p;
+ p += nodewords;
+ }
+ all_closure_sets = p;
+ for (i = 0; i < n; ++i) {
+ blocks[i]->closure = p;
+ p += nodewords;
+ }
+ all_edge_sets = p;
+ for (i = 0; i < n; ++i) {
+ register struct block *b = blocks[i];
+
+ b->et.edom = p;
+ p += edgewords;
+ b->ef.edom = p;
+ p += edgewords;
+ b->et.id = i;
+ edges[i] = &b->et;
+ b->ef.id = n_blocks + i;
+ edges[n_blocks + i] = &b->ef;
+ b->et.pred = b;
+ b->ef.pred = b;
+ }
+ max_stmts = 0;
+ for (i = 0; i < n; ++i)
+ max_stmts += slength(blocks[i]->stmts) + 1;
+ /*
+ * We allocate at most 3 value numbers per statement,
+ * so this is an upper bound on the number of valnodes
+ * we'll need.
+ */
+ maxval = 3 * max_stmts;
+ vmap = (struct vmapinfo *)malloc(maxval * sizeof(*vmap));
+ vnode_base = (struct valnode *)malloc(maxval * sizeof(*vmap));
+}
+
+/*
+ * Some pointers used to convert the basic block form of the code,
+ * into the array form that BPF requires. 'fstart' will point to
+ * the malloc'd array while 'ftail' is used during the recursive traversal.
+ */
+static struct bpf_insn *fstart;
+static struct bpf_insn *ftail;
+
+#ifdef BDEBUG
+int bids[1000];
+#endif
+
+static void
+convert_code_r(p)
+ struct block *p;
+{
+ struct bpf_insn *dst;
+ struct slist *src;
+ int slen;
+ u_int off;
+
+ if (p == 0 || isMarked(p))
+ return;
+ Mark(p);
+
+ convert_code_r(JF(p));
+ convert_code_r(JT(p));
+
+ slen = slength(p->stmts);
+ dst = ftail -= slen + 1;
+
+ p->offset = dst - fstart;
+
+ for (src = p->stmts; src; src = src->next) {
+ if (src->s.code == NOP)
+ continue;
+ dst->code = (u_short)src->s.code;
+ dst->k = src->s.k;
+ ++dst;
+ }
+#ifdef BDEBUG
+ bids[dst - fstart] = p->id + 1;
+#endif
+ dst->code = (u_short)p->s.code;
+ dst->k = p->s.k;
+ if (JT(p)) {
+ off = JT(p)->offset - (p->offset + slen) - 1;
+ if (off >= 256)
+ bpf_error("long jumps not supported");
+ dst->jt = off;
+ off = JF(p)->offset - (p->offset + slen) - 1;
+ if (off >= 256)
+ bpf_error("long jumps not supported");
+ dst->jf = off;
+ }
+}
+
+
+/*
+ * Convert flowgraph intermediate representation to the
+ * BPF array representation. Set *lenp to the number of instructions.
+ */
+struct bpf_insn *
+icode_to_fcode(root, lenp)
+ struct block *root;
+ int *lenp;
+{
+ int n;
+ struct bpf_insn *fp;
+
+ unMarkAll();
+ n = *lenp = count_stmts(root);
+
+ fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
+ memset((char *)fp, 0, sizeof(*fp) * n);
+ fstart = fp;
+ ftail = fp + n;
+
+ unMarkAll();
+ convert_code_r(root);
+
+ return fp;
+}
+
+#ifdef BDEBUG
+opt_dump(root)
+ struct block *root;
+{
+ struct bpf_program f;
+
+ memset(bids, 0, sizeof bids);
+ f.bf_insns = icode_to_fcode(root, &f.bf_len);
+ bpf_dump(&f, 1);
+ putchar('\n');
+ free((char *)f.bf_insns);
+}
+#endif
diff --git a/lib/libpcap/pcap-bpf.c b/lib/libpcap/pcap-bpf.c
new file mode 100644
index 0000000..39e6197
--- /dev/null
+++ b/lib/libpcap/pcap-bpf.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: pcap-bpf.c,v 1.14 94/06/03 19:58:49 leres Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h> /* optionally get BSD define */
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <string.h>
+
+#include "pcap-int.h"
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ struct bpf_stat s;
+
+ if (ioctl(p->fd, BIOCGSTATS, &s) < 0) {
+ sprintf(p->errbuf, "BIOCGSTATS: %s", pcap_strerror(errno));
+ return (-1);
+ }
+
+ ps->ps_recv = s.bs_recv;
+ ps->ps_drop = s.bs_drop;
+ return (0);
+}
+
+int
+pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ int cc;
+ int n = 0;
+ register u_char *bp, *ep;
+
+ again:
+ cc = p->cc;
+ if (p->cc == 0) {
+ cc = read(p->fd, (char *)p->buffer, p->bufsize);
+ if (cc < 0) {
+ /* Don't choke when we get ptraced */
+ switch (errno) {
+
+ case EINTR:
+ goto again;
+
+ case EWOULDBLOCK:
+ return (0);
+#if defined(sun) && !defined(BSD)
+ /*
+ * Due to a SunOS bug, after 2^31 bytes, the kernel
+ * file offset overflows and read fails with EINVAL.
+ * The lseek() to 0 will fix things.
+ */
+ case EINVAL:
+ if ((long)(tell(p->fd) + p->bufsize) < 0) {
+ (void)lseek(p->fd, 0, 0);
+ goto again;
+ }
+ /* fall through */
+#endif
+ }
+ sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ bp = p->buffer;
+ } else
+ bp = p->bp;
+
+ /*
+ * Loop through each packet.
+ */
+#define bhp ((struct bpf_hdr *)bp)
+ ep = bp + cc;
+ while (bp < ep) {
+ register int caplen, hdrlen;
+ caplen = bhp->bh_caplen;
+ hdrlen = bhp->bh_hdrlen;
+ /*
+ * XXX A bpf_hdr matches a pcap_pkthdr.
+ */
+ (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
+ bp += BPF_WORDALIGN(caplen + hdrlen);
+ if (++n >= cnt && cnt > 0) {
+ p->bp = bp;
+ p->cc = ep - bp;
+ return (n);
+ }
+ }
+#undef bhp
+ p->cc = 0;
+ return (n);
+}
+
+static inline int
+bpf_open(pcap_t *p, char *errbuf)
+{
+ int fd;
+ int n = 0;
+ char device[sizeof "/dev/bpf000"];
+
+ /*
+ * Go through all the minors and find one that isn't in use.
+ */
+ do {
+ (void)sprintf(device, "/dev/bpf%d", n++);
+ fd = open(device, O_RDONLY);
+ } while (fd < 0 && errno == EBUSY);
+
+ /*
+ * XXX better message for all minors used
+ */
+ if (fd < 0)
+ sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
+
+ return (fd);
+}
+
+pcap_t *
+pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+{
+ int fd;
+ struct ifreq ifr;
+ struct bpf_version bv;
+ u_int v;
+ pcap_t *p;
+
+ p = (pcap_t *)malloc(sizeof(*p));
+ if (p == NULL) {
+ sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
+ return (NULL);
+ }
+ bzero(p, sizeof(*p));
+ fd = bpf_open(p, ebuf);
+ if (fd < 0)
+ goto bad;
+
+ p->fd = fd;
+ p->snapshot = snaplen;
+
+ if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
+ sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ if (bv.bv_major != BPF_MAJOR_VERSION ||
+ bv.bv_minor < BPF_MINOR_VERSION) {
+ sprintf(ebuf, "kernel bpf filter out of date");
+ goto bad;
+ }
+ (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
+ goto bad;
+ }
+ /* Get the data link layer type. */
+ if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
+ sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ p->linktype = v;
+
+ /* set timeout */
+ if (to_ms != 0) {
+ struct timeval to;
+ to.tv_sec = to_ms / 1000;
+ to.tv_usec = (to_ms * 1000) % 1000000;
+ if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
+ sprintf(ebuf, "BIOCSRTIMEOUT: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+ }
+ if (promisc)
+ /* set promiscuous mode, okay if it fails */
+ (void)ioctl(p->fd, BIOCPROMISC, NULL);
+
+ if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
+ sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ p->bufsize = v;
+ p->buffer = (u_char*)malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
+ goto bad;
+ }
+
+ return (p);
+ bad:
+ free(p);
+ return (NULL);
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+ if (p->sf.rfile != NULL)
+ p->fcode = *fp;
+ else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
+ sprintf(p->errbuf, "BIOCSETF: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
diff --git a/lib/libpcap/pcap-dlpi.c b/lib/libpcap/pcap-dlpi.c
new file mode 100644
index 0000000..adcffcd
--- /dev/null
+++ b/lib/libpcap/pcap-dlpi.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk),
+ * University College London.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: pcap-dlpi.c,v 1.22x 94/10/12 20:08:15 leres Exp $ (LBL)";
+#endif
+
+/*
+ * Packet capture routine for dlpi under SunOS 5
+ *
+ * Notes:
+ *
+ * - Apparently the DLIOCRAW ioctl() is specific to SunOS.
+ *
+ * - There is a bug in bufmod(7) such that setting the snapshot
+ * length results in data being left of the front of the packet.
+ *
+ * - It might be desirable to use pfmod(7) to filter packets in the
+ * kernel.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/bufmod.h>
+#include <sys/dlpi.h>
+#include <sys/stream.h>
+#include <sys/systeminfo.h>
+
+#include <net/bpf.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stropts.h>
+#include <unistd.h>
+
+#include "pcap-int.h"
+
+#define MAXDLBUF 8192
+
+/* Forwards */
+static int send_request(int, char *, int, char *, char *);
+static int dlattachreq(int, u_long, char *);
+static int dlinfoack(int, char *, char *);
+static int dlinforeq(int, char *);
+static int dlpromisconreq(int, u_long, char *);
+static int dlokack(int, char *, char *);
+static int strioctl(int, int, int, char *);
+#ifdef SOLARIS
+static char *getrelease(long *, long *, long *);
+#endif
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+
+ *ps = p->md.stat;
+ return (0);
+}
+
+int
+pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ register int cc, n;
+ register u_char *bp, *ep, *pk;
+ register struct bpf_insn *fcode;
+ register struct sb_hdr *sbp;
+ int flags;
+ struct strbuf data;
+ struct pcap_pkthdr pkthdr;
+
+ flags = 0;
+ cc = p->cc;
+ if (cc == 0) {
+ data.buf = (char *)p->buffer;
+ data.maxlen = MAXDLBUF;
+ data.len = 0;
+ do {
+ if (getmsg(p->fd, NULL, &data, &flags) < 0) {
+ /* Don't choke when we get ptraced */
+ if (errno == EINTR) {
+ cc = 0;
+ continue;
+ }
+ strcpy(p->errbuf, pcap_strerror(errno));
+ return (-1);
+ }
+ cc = data.len;
+ } while (cc == 0);
+ bp = p->buffer;
+ } else
+ bp = p->bp;
+
+ /* Loop through packets */
+ fcode = p->fcode.bf_insns;
+ ep = bp + cc;
+ n = 0;
+ while (bp < ep) {
+ sbp = (struct sb_hdr *)bp;
+ p->md.stat.ps_drop += sbp->sbh_drops;
+ ++p->md.stat.ps_recv;
+ pk = bp + sizeof(*sbp);
+ bp += sbp->sbh_totlen;
+ if (bpf_filter(fcode, pk, sbp->sbh_origlen, sbp->sbh_msglen)) {
+ pkthdr.ts = sbp->sbh_timestamp;
+ pkthdr.len = sbp->sbh_origlen;
+ pkthdr.caplen = sbp->sbh_msglen;
+ (*callback)(user, &pkthdr, pk);
+ if (++n >= cnt && cnt >= 0) {
+ p->cc = ep - bp;
+ p->bp = bp;
+ return (n);
+ }
+ }
+ }
+ p->cc = 0;
+ return (n);
+}
+
+pcap_t *
+pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+{
+ register pcap_t *p;
+ long buf[MAXDLBUF];
+ int ppa;
+ int cppa;
+ register dl_info_ack_t *infop;
+ u_long ss, flag;
+#ifdef SOLARIS
+ char *release;
+ long osmajor, osminor, osmicro;
+#endif
+ char dname[100];
+
+ p = (pcap_t *)malloc(sizeof(*p));
+ if (p == NULL) {
+ strcpy(ebuf, pcap_strerror(errno));
+ return (NULL);
+ }
+ memset(p, 0, sizeof(*p));
+
+ /*
+ ** 1) In order to get the ppa take the last character of the device
+ ** name if it is a number then fail the open.
+ **
+ ** 2) If the name starts with a '/' then this is an absolute pathname,
+ ** otherwise prepend '/dev/'.
+ **
+ ** 3) Remove the trailing digit and try and open the device
+ ** not staggeringly intuitive but it should work.
+ **
+ ** If there are more than 9 devices this code will fail.
+ */
+
+ cppa = device[strlen(device) - 1];
+ if (!isdigit(cppa)) {
+ sprintf(ebuf, "%c is not a digit, therefore not a valid ppa",
+ cppa);
+ goto bad;
+ }
+
+ dname[0] = '\0';
+ if (device[0] != '/')
+ strcpy(dname, "/dev/");
+
+ strcat(dname, device);
+ dname[strlen(dname) - 1] = '\0';
+
+ if ((p->fd = open(dname, O_RDWR)) < 0) {
+ sprintf(ebuf, "%s: %s", dname, pcap_strerror(errno));
+ goto bad;
+ }
+ p->snapshot = snaplen;
+
+ ppa = cppa - '0';
+ /*
+ ** Attach.
+ */
+ if (dlattachreq(p->fd, ppa, ebuf) < 0 ||
+ dlokack(p->fd, (char *)buf, ebuf) < 0)
+ goto bad;
+
+ if (promisc) {
+ /*
+ ** enable promiscuous.
+ */
+ if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
+ dlokack(p->fd, (char *)buf, ebuf) < 0)
+ goto bad;
+ if (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
+ dlokack(p->fd, (char *)buf, ebuf) < 0)
+ goto bad;
+
+ /*
+ ** enable multicast, you would have thought promiscuous
+ ** would be sufficient.
+ */
+ if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
+ dlokack(p->fd, (char *)buf, ebuf) < 0)
+ goto bad;
+ }
+
+ /*
+ ** Determine link type
+ */
+ if (dlinforeq(p->fd, ebuf) < 0 ||
+ dlinfoack(p->fd, (char *)buf, ebuf) < 0)
+ goto bad;
+
+ infop = &((union DL_primitives *)buf)->info_ack;
+ switch (infop->dl_mac_type) {
+
+ case DL_ETHER:
+ p->linktype = DLT_EN10MB;
+ break;
+
+ case DL_FDDI:
+ p->linktype = DLT_FDDI;
+ break;
+
+ default:
+ sprintf(ebuf, "unknown mac type 0x%lu", infop->dl_mac_type);
+ goto bad;
+ }
+
+#ifdef DLIOCRAW
+ /*
+ ** This is a non standard SunOS hack to get the ethernet header.
+ */
+ if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
+ sprintf(ebuf, "DLIOCRAW: %s", pcap_strerror(errno));
+ goto bad;
+ }
+#endif
+
+ /*
+ ** Another non standard call to get the data nicely buffered
+ */
+ if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
+ sprintf(ebuf, "I_PUSH bufmod: %s", pcap_strerror(errno));
+ goto bad;
+ }
+
+ /*
+ ** Now that the bufmod is pushed lets configure it.
+ **
+ ** There is a bug in bufmod(7). When dealing with messages of
+ ** less than snaplen size it strips data from the beginning not
+ ** the end.
+ **
+ ** This bug is supposed to be fixed in 5.3.2. Also, there is a
+ ** patch available. Ask for bugid 1149065.
+ */
+ ss = snaplen;
+#ifdef SOLARIS
+ release = getrelease(&osmajor, &osminor, &osmicro);
+ if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
+ getenv("BUFMOD_FIXED") == NULL) {
+ fprintf(stderr,
+ "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n",
+ release);
+ ss = 0;
+ }
+#endif
+ if (ss > 0 &&
+ strioctl(p->fd, SBIOCSSNAP, sizeof(u_long), (char *)&ss) != 0) {
+ sprintf(ebuf, "SBIOCSSNAP: %s", pcap_strerror(errno));
+ goto bad;
+ }
+
+ /*
+ ** Set up the bufmod flags
+ */
+ if (strioctl(p->fd, SBIOCGFLAGS, sizeof(u_long), (char *)&flag) < 0) {
+ sprintf(ebuf, "SBIOCGFLAGS: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ flag |= SB_NO_DROPS;
+ if (strioctl(p->fd, SBIOCSFLAGS, sizeof(u_long), (char *)&flag) != 0) {
+ sprintf(ebuf, "SBIOCSFLAGS: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ /*
+ ** Set up the bufmod timeout
+ */
+ if (to_ms != 0) {
+ struct timeval to;
+
+ to.tv_sec = to_ms / 1000;
+ to.tv_usec = (to_ms * 1000) % 1000000;
+ if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
+ sprintf(ebuf, "SBIOCSTIME: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ }
+
+ /*
+ ** As the last operation flush the read side.
+ */
+ if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
+ sprintf(ebuf, "FLUSHR: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ /* Allocate data buffer */
+ p->bufsize = MAXDLBUF * sizeof(long);
+ p->buffer = (u_char *)malloc(p->bufsize);
+ return (p);
+bad:
+ free(p);
+ return (NULL);
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+
+ p->fcode = *fp;
+ return (0);
+}
+
+static int
+send_request(int fd, char *ptr, int len, char *what, char *ebuf)
+{
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = 0;
+ ctl.len = len;
+ ctl.buf = ptr;
+
+ flags = 0;
+ if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) {
+ sprintf(ebuf, "putmsg \"%s\"failed: %s",
+ what, pcap_strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+dlattachreq(int fd, u_long ppa, char *ebuf)
+{
+ dl_attach_req_t req;
+
+ req.dl_primitive = DL_ATTACH_REQ;
+ req.dl_ppa = ppa;
+
+ return (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf));
+}
+
+static int
+dlpromisconreq(int fd, u_long level, char *ebuf)
+{
+ dl_promiscon_req_t req;
+
+ req.dl_primitive = DL_PROMISCON_REQ;
+ req.dl_level = level;
+
+ return (send_request(fd, (char *)&req, sizeof(req), "promiscon", ebuf));
+}
+
+static int
+dlokack(int fd, char *bufp, char *ebuf)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ flags = 0;
+ if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) {
+ sprintf(ebuf, "getmsg: %s", pcap_strerror(errno));
+ return (-1);
+ }
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ if (dlp->dl_primitive != DL_OK_ACK) {
+ sprintf(ebuf, "dlokack unexpected primitive %d",
+ dlp->dl_primitive);
+ return (-1);
+ }
+
+ if (ctl.len != sizeof(dl_ok_ack_t)) {
+ sprintf(ebuf, "dlokack incorrect size returned");
+ return (-1);
+ }
+ return (0);
+}
+
+
+static int
+dlinforeq(int fd, char *ebuf)
+{
+ dl_info_req_t req;
+
+ req.dl_primitive = DL_INFO_REQ;
+
+ return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf));
+}
+
+static int
+dlinfoack(int fd, char *bufp, char *ebuf)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ flags = 0;
+ if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) {
+ sprintf(ebuf, "dlinfoack: getmsg: %s", pcap_strerror(errno));
+ return (-1);
+ }
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ if (dlp->dl_primitive != DL_INFO_ACK) {
+ sprintf(ebuf, "dlinfoack: unexpected primitive %ld",
+ dlp->dl_primitive);
+ return (-1);
+ }
+
+ /* Extra stuff like the broadcast address can be returned */
+ if (ctl.len < DL_INFO_ACK_SIZE) {
+ sprintf(ebuf, "dlinfoack: incorrect size returned");
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+strioctl(int fd, int cmd, int len, char *dp)
+{
+ struct strioctl str;
+ int rc;
+
+ str.ic_cmd = cmd;
+ str.ic_timout = -1;
+ str.ic_len = len;
+ str.ic_dp = dp;
+ rc = ioctl(fd, I_STR, &str);
+
+ if (rc < 0)
+ return (rc);
+ else
+ return (str.ic_len);
+}
+
+#ifdef SOLARIS
+static char *
+getrelease(long *majorp, long *minorp, long *microp)
+{
+ char *cp;
+ static char buf[32];
+
+ *majorp = 0;
+ *minorp = 0;
+ *microp = 0;
+ if (sysinfo(SI_RELEASE, buf, sizeof(buf)) < 0)
+ return ("?");
+ cp = buf;
+ if (!isdigit(*cp))
+ return (buf);
+ *majorp = strtol(cp, &cp, 10);
+ if (*cp++ != '.')
+ return (buf);
+ *minorp = strtol(cp, &cp, 10);
+ if (*cp++ != '.')
+ return (buf);
+ *microp = strtol(cp, &cp, 10);
+ return (buf);
+}
+#endif
diff --git a/lib/libpcap/pcap-enet.c b/lib/libpcap/pcap-enet.c
new file mode 100644
index 0000000..3f4189b
--- /dev/null
+++ b/lib/libpcap/pcap-enet.c
@@ -0,0 +1,227 @@
+/*
+ * Stanford Enetfilter subroutines for tcpdump
+ *
+ * Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c
+ * subroutines.
+ *
+ * Rayan Zachariassen, CA*Net
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+#include <net/enet.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "interface.h"
+
+struct packet_header {
+#ifdef IBMRTPC
+ struct LengthWords length;
+ struct tap_header tap;
+#endif /* IBMRTPC */
+ u_char packet[8]
+};
+
+extern int errno;
+
+#define BUFSPACE (4*1024)
+
+/* Forwards */
+static void efReadError(int, char *);
+
+void
+readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit)
+{
+#ifdef IBMRTPC
+ register struct packet_header *ph;
+ register u_char *bp;
+ register int inc;
+#else /* !IBMRTPC */
+ static struct timeval tv = { 0 };
+#endif /* IBMRTPC */
+ register int cc, caplen;
+ register struct bpf_insn *fcode = fp->bf_insns;
+ union {
+ struct packet_header hdr;
+ u_char p[BUFSPACE];
+ u_short s;
+ } buf;
+
+ while (1) {
+ if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0)
+ efReadError(if_fd, "reader");
+
+#ifdef IBMRTPC
+ /*
+ * Loop through each packet.
+ */
+ bp = buf.p;
+ while (cc > 0) {
+ ph = (struct packet_header *)bp;
+ caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap
+.th_wirelen ;
+ if (bpf_filter(fcode, (char *)ph->packet,
+ ph->tap.th_wirelen, caplen)) {
+ if (cnt >= 0 && --cnt < 0)
+ goto out;
+ (*printit)((char *)ph->packet,
+ (struct timeval *)ph->tap.th_timestamp,
+ ph->tap.th_wirelen, caplen);
+ }
+ inc = ph->length.PacketOffset;
+ cc -= inc;
+ bp += inc;
+ }
+#else /* !IBMRTPC */
+ caplen = cc > snaplen ? snaplen : cc ;
+ if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) {
+ if (cnt >= 0 && --cnt < 0)
+ goto out;
+ (*printit)(buf.hdr.packet, &tv, cc, caplen);
+ }
+#endif /* IBMRTPC */
+ }
+ out:
+ wrapup(if_fd);
+}
+
+/* Call ONLY if read() has returned an error on packet filter */
+static void
+efReadError(int fid, char *msg)
+{
+ if (errno == EINVAL) { /* read MAXINT bytes already! */
+ if (lseek(fid, 0, 0) < 0) {
+ perror("tcpdump: efReadError/lseek");
+ exit(-1);
+ }
+ else
+ return;
+ }
+ else {
+ (void) fprintf(stderr, "tcpdump: ");
+ perror(msg);
+ exit(-1);
+ }
+}
+
+void
+wrapup(int fd)
+{
+#ifdef IBMRTPC
+ struct enstats es;
+
+ if (ioctl(fd, EIOSTATS, &es) == -1) {
+ perror("tcpdump: enet ioctl EIOSTATS error");
+ exit(-1);
+ }
+
+ fprintf(stderr, "%d packets queued", es.enStat_Rcnt);
+ if (es.enStat_Rdrops > 0)
+ fprintf(stderr, ", %d dropped", es.enStat_Rdrops);
+ if (es.enStat_Reads > 0)
+ fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads,
+ es.enStat_Reads > 1 ? "reads" : "read");
+ if (es.enStat_MaxRead > 1)
+ fprintf(stderr, ", %d packets in largest read",
+ es.enStat_MaxRead);
+ putc('\n', stderr);
+#endif /* IBMRTPC */
+ close(fd);
+}
+
+int
+initdevice(char *device, int pflag, int *linktype)
+{
+ struct eniocb ctl;
+ struct enfilter filter;
+ u_int maxwaiting;
+ int if_fd;
+
+#ifdef IBMRTPC
+ GETENETDEVICE(0, O_RDONLY, &if_fd);
+#else /* !IBMRTPC */
+ if_fd = open("/dev/enet", O_RDONLY, 0);
+#endif /* IBMRTPC */
+
+ if (if_fd == -1) {
+ perror("tcpdump: enet open error");
+ error(
+"your system may not be properly configured; see \"man enet(4)\"");
+ exit(-1);
+ }
+
+ /* Get operating parameters. */
+
+ if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) {
+ perror("tcpdump: enet ioctl EIOCGETP error");
+ exit(-1);
+ }
+
+ /* Set operating parameters. */
+
+#ifdef IBMRTPC
+ ctl.en_rtout = 1 * ctl.en_hz;
+ ctl.en_tr_etherhead = 1;
+ ctl.en_tap_network = 1;
+ ctl.en_multi_packet = 1;
+ ctl.en_maxlen = BUFSPACE;
+#else /* !IBMRTPC */
+ ctl.en_rtout = 64; /* randomly picked value for HZ */
+#endif /* IBMRTPC */
+ if (ioctl(if_fd, EIOCSETP, &ctl) == -1) {
+ perror("tcpdump: enet ioctl EIOCSETP error");
+ exit(-1);
+ }
+
+ /* Flush the receive queue, since we've changed
+ the operating parameters and we otherwise might
+ receive data without headers. */
+
+ if (ioctl(if_fd, EIOCFLUSH) == -1) {
+ perror("tcpdump: enet ioctl EIOCFLUSH error");
+ exit(-1);
+ }
+
+ /* Set the receive queue depth to its maximum. */
+
+ maxwaiting = ctl.en_maxwaiting;
+ if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) {
+ perror("tcpdump: enet ioctl EIOCSETW error");
+ exit(-1);
+ }
+
+#ifdef IBMRTPC
+ /* Clear statistics. */
+
+ if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) {
+ perror("tcpdump: enet ioctl EIOCLRSTAT error");
+ exit(-1);
+ }
+#endif /* IBMRTPC */
+
+ /* Set the filter (accept all packets). */
+
+ filter.enf_Priority = 3;
+ filter.enf_FilterLen = 0;
+ if (ioctl(if_fd, EIOCSETF, &filter) == -1) {
+ perror("tcpdump: enet ioctl EIOCSETF error");
+ exit(-1);
+ }
+ /*
+ * "enetfilter" supports only ethernets.
+ */
+ *linktype = DLT_EN10MB;
+
+ return(if_fd);
+}
diff --git a/lib/libpcap/pcap-int.h b/lib/libpcap/pcap-int.h
new file mode 100644
index 0000000..1f5da22
--- /dev/null
+++ b/lib/libpcap/pcap-int.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: pcap-int.h,v 1.7 94/06/14 20:03:33 leres Exp $ (LBL)
+ */
+
+#ifndef pcap_int_h
+#define pcap_int_h
+
+#include <pcap.h>
+
+/*
+ * Savefile
+ */
+struct pcap_sf {
+ FILE *rfile;
+ int swapped;
+ int version_major;
+ int version_minor;
+ u_char *base;
+};
+
+struct pcap_md {
+ struct pcap_stat stat;
+#ifdef PCAP_PF
+ int use_bpf;
+ u_long TotPkts; /* can't oflow for 79 hrs on ether */
+ u_long TotAccepted; /* count accepted by filter */
+ u_long TotDrops; /* count of dropped packets */
+ long TotMissed; /* missed by i/f during this run */
+ long OrigMissed; /* missed by i/f before this run */
+#endif
+};
+
+struct pcap {
+ int fd;
+ int snapshot;
+ int linktype;
+ int tzoff; /* timezone offset */
+
+ struct pcap_sf sf;
+ struct pcap_md md;
+
+ /*
+ * Read buffer.
+ */
+ int bufsize;
+ u_char *buffer;
+ u_char *bp;
+ int cc;
+
+ /*
+ * Place holder for pcap_next().
+ */
+ u_char *pkt;
+
+
+ /*
+ * Placeholder for filter code if bpf not in kernel.
+ */
+ struct bpf_program fcode;
+
+ char errbuf[PCAP_ERRBUF_SIZE];
+};
+
+/* XXX should these be in pcap.h? */
+int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
+int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *);
+#endif
diff --git a/lib/libpcap/pcap-namedb.h b/lib/libpcap/pcap-namedb.h
new file mode 100644
index 0000000..3471227
--- /dev/null
+++ b/lib/libpcap/pcap-namedb.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: pcap-namedb.h,v 1.2 94/06/14 20:03:34 leres Exp $ (LBL)
+ */
+
+#ifndef lib_pcap_ethers_h
+#define lib_pcap_ethers_h
+
+/*
+ * As returned by the pcap_next_etherent()
+ * XXX this stuff doesn't belong in this inteface, but this
+ * library already must do name to address translation, so
+ * on systems that don't have support for /etc/ethers, we
+ * export these hooks since they'll
+ */
+struct pcap_etherent {
+ u_char addr[6];
+ char name[122];
+};
+#ifndef PCAP_ETHERS_FILE
+#define PCAP_ETHERS_FILE "/etc/ethers"
+#endif
+struct pcap_etherent *pcap_next_etherent(FILE *);
+u_char *pcap_ether_hostton(const char*);
+u_char *pcap_ether_aton(const char *);
+
+u_long **pcap_nametoaddr(const char *);
+u_long pcap_nametonetaddr(const char *);
+
+int pcap_nametoport(const char *, int *, int *);
+int pcap_nametoproto(const char *);
+int pcap_nametoeproto(const char *);
+/*
+ * If a protocol is unknown, PROTO_UNDEF is returned.
+ * Also, pcap_nametoport() returns the protocol along with the port number.
+ * If there are ambiguous entried in /etc/services (i.e. domain
+ * can be either tcp or udp) PROTO_UNDEF is returned.
+ */
+#define PROTO_UNDEF -1
+
+/* XXX move these to pcap-int.h? */
+u_long __pcap_atodn(const char *);
+u_long __pcap_atoin(const char *);
+u_short __pcap_nametodnaddr(const char *);
+
+#endif
diff --git a/lib/libpcap/pcap-nit.c b/lib/libpcap/pcap-nit.c
new file mode 100644
index 0000000..125e14f
--- /dev/null
+++ b/lib/libpcap/pcap-nit.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: pcap-nit.c,v 1.24 94/02/10 23:02:37 leres Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/nit.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "pcap-int.h"
+
+/*
+ * The chunk size for NIT. This is the amount of buffering
+ * done for read calls.
+ */
+#define CHUNKSIZE (2*1024)
+
+/*
+ * The total buffer space used by NIT.
+ */
+#define BUFSPACE (4*CHUNKSIZE)
+
+/* Forwards */
+static int nit_setflags(int, int, int, char *);
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+
+ *ps = p->md.stat;
+ return (0);
+}
+
+int
+pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ register int cc, n;
+ register struct bpf_insn *fcode = p->fcode.bf_insns;
+ register u_char *bp, *cp, *ep;
+ register struct nit_hdr *nh;
+ register int caplen;
+
+ cc = p->cc;
+ if (cc == 0) {
+ cc = read(p->fd, (char *)p->buffer, p->bufsize);
+ if (cc < 0) {
+ if (errno == EWOULDBLOCK)
+ return (0);
+ sprintf(p->errbuf, "pcap_read: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+ bp = p->buffer;
+ } else
+ bp = p->bp;
+
+ /*
+ * Loop through each packet. The increment expression
+ * rounds up to the next int boundary past the end of
+ * the previous packet.
+ */
+ n = 0;
+ ep = bp + cc;
+ while (bp < ep) {
+ nh = (struct nit_hdr *)bp;
+ cp = bp + sizeof(*nh);
+
+ switch (nh->nh_state) {
+
+ case NIT_CATCH:
+ break;
+
+ case NIT_NOMBUF:
+ case NIT_NOCLUSTER:
+ case NIT_NOSPACE:
+ p->md.stat.ps_drop = nh->nh_dropped;
+ continue;
+
+ case NIT_SEQNO:
+ continue;
+
+ default:
+ sprintf(p->errbuf, "bad nit state %d", nh->nh_state);
+ return (-1);
+ }
+ ++p->md.stat.ps_recv;
+ bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
+ sizeof(int) - 1) & ~(sizeof(int) - 1));
+
+ caplen = nh->nh_wirelen;
+ if (caplen > p->snapshot)
+ caplen = p->snapshot;
+ if (bpf_filter(fcode, cp, nh->nh_wirelen, caplen)) {
+ struct pcap_pkthdr h;
+ h.ts = nh->nh_timestamp;
+ h.len = nh->nh_wirelen;
+ h.caplen = caplen;
+ (*callback)(user, &h, cp);
+ if (++n >= cnt && cnt >= 0) {
+ p->cc = ep - bp;
+ p->bp = bp;
+ return (n);
+ }
+ }
+ }
+ p->cc = 0;
+ return (n);
+}
+
+static int
+nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
+{
+ struct nit_ioc nioc;
+
+ bzero((char *)&nioc, sizeof(nioc));
+ nioc.nioc_bufspace = BUFSPACE;
+ nioc.nioc_chunksize = CHUNKSIZE;
+ nioc.nioc_typetomatch = NT_ALLTYPES;
+ nioc.nioc_snaplen = p->snapshot;
+ nioc.nioc_bufalign = sizeof(int);
+ nioc.nioc_bufoffset = 0;
+
+ if (to_ms != 0) {
+ nioc.nioc_flags |= NF_TIMEOUT;
+ nioc.nioc_timeout.tv_sec = to_ms / 1000;
+ nioc.nioc_timeout.tv_usec = (to_ms * 1000) % 1000000;
+ }
+ if (promisc)
+ nioc.nioc_flags |= NF_PROMISC;
+
+ if (ioctl(fd, SIOCSNIT, &nioc) < 0) {
+ sprintf(ebuf, "SIOCSNIT: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
+
+pcap_t *
+pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+{
+ int fd;
+ struct sockaddr_nit snit;
+ register pcap_t *p;
+
+ p = (pcap_t *)malloc(sizeof(*p));
+ if (p == NULL) {
+ strcpy(ebuf, pcap_strerror(errno));
+ return (NULL);
+ }
+
+ if (snaplen < 96)
+ /*
+ * NIT requires a snapshot length of at least 96.
+ */
+ snaplen = 96;
+
+ bzero(p, sizeof(*p));
+ p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
+ if (fd < 0) {
+ sprintf(ebuf, "socket: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ snit.snit_family = AF_NIT;
+ (void)strncpy(snit.snit_ifname, device, NITIFSIZ);
+
+ if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
+ sprintf(ebuf, "bind: %s: %s", snit.snit_ifname,
+ pcap_strerror(errno));
+ goto bad;
+ }
+ p->snapshot = snaplen;
+ nit_setflags(p->fd, promisc, to_ms, ebuf);
+
+ /*
+ * NIT supports only ethernets.
+ */
+ p->linktype = DLT_EN10MB;
+
+ p->bufsize = BUFSPACE;
+ p->buffer = (u_char *)malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ strcpy(ebuf, pcap_strerror(errno));
+ goto bad;
+ }
+ return (p);
+ bad:
+ if (fd >= 0)
+ close(fd);
+ free(p);
+ return (NULL);
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+
+ p->fcode = *fp;
+ return (0);
+}
diff --git a/lib/libpcap/pcap-nit.h b/lib/libpcap/pcap-nit.h
new file mode 100644
index 0000000..dc1c9e8
--- /dev/null
+++ b/lib/libpcap/pcap-nit.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 1990, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Lawrence Berkeley Laboratory,
+ * Berkeley, CA. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: pcap-nit.h,v 1.2 94/06/14 20:06:03 leres Exp $ (LBL)
+ */
diff --git a/lib/libpcap/pcap-pf.c b/lib/libpcap/pcap-pf.c
new file mode 100644
index 0000000..483dc97
--- /dev/null
+++ b/lib/libpcap/pcap-pf.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: pcap-pf.c,v 1.32 94/06/10 17:41:01 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * packet filter subroutines for tcpdump
+ * Extraction/creation by Jeffrey Mogul, DECWRL
+ *
+ * Extracted from tcpdump.c.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <net/pfilt.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcap-int.h"
+
+/*
+ * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump
+ * applications aren't going to need more than 200 bytes of packet header
+ * and the read shouldn't return more packets than packetfilter's internal
+ * queue limit (bounded at 256).
+ */
+#define BUFSPACE (200*256)
+
+int
+pcap_read(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
+{
+ u_char *p;
+ struct bpf_insn *fcode;
+ int cc;
+ register u_char *bp;
+ int buflen, inc;
+ struct enstamp stamp;
+ int n;
+ fcode = pc->md.use_bpf ? 0 : pc->fcode.bf_insns;
+ again:
+ cc = pc->cc;
+ if (cc == 0) {
+ cc = read(pc->fd, (char *)pc->buffer, pc->bufsize);
+ if (cc < 0) {
+ if (errno == EWOULDBLOCK)
+ return (0);
+ if (errno == EINVAL &&
+ (long)(tell(pc->fd) + pc->bufsize) < 0) {
+ /*
+ * Due to a kernel bug, after 2^31 bytes,
+ * the kernel file offset overflows and
+ * read fails with EINVAL. The lseek()
+ * to 0 will fix things.
+ */
+ (void)lseek(pc->fd, 0L, 0);
+ goto again;
+ }
+ sprintf(pc->errbuf, "pf read: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+ bp = pc->buffer;
+ } else
+ bp = pc->bp;
+ /*
+ * Loop through each packet.
+ */
+ n = 0;
+ while (cc > 0) {
+ /* avoid alignment issues here */
+ bcopy((char *)bp, (char *)&stamp, sizeof(stamp));
+ if (stamp.ens_stamplen != sizeof(stamp))
+ /* buffer is garbage, treat it as poison */
+ break;
+
+ p = bp + stamp.ens_stamplen;
+
+ buflen = stamp.ens_count;
+ if (buflen > pc->snapshot)
+ buflen = pc->snapshot;
+
+ /*
+ * Short-circuit evaluation: if using BPF filter
+ * in kernel, no need to do it now.
+ */
+ if (fcode == 0 ||
+ bpf_filter(fcode, p, stamp.ens_count, buflen)) {
+ struct pcap_pkthdr h;
+ pc->md.TotAccepted++;
+ h.ts = stamp.ens_tstamp;
+ h.len = stamp.ens_count;
+ h.caplen = buflen;
+ (*callback)(user, &h, p);
+ if (++n >= cnt && cnt > 0) {
+ inc = ENALIGN(buflen + stamp.ens_stamplen);
+ cc -= inc;
+ bp += inc;
+ pc->cc = cc;
+ pc->bp = bp;
+ return (n);
+ }
+ }
+ pc->md.TotPkts++;
+ pc->md.TotDrops += stamp.ens_dropped;
+ pc->md.TotMissed = stamp.ens_ifoverflows;
+ if (pc->md.OrigMissed < 0)
+ pc->md.OrigMissed = pc->md.TotMissed;
+
+ inc = ENALIGN(buflen + stamp.ens_stamplen);
+ cc -= inc;
+ bp += inc;
+ }
+ pc->cc = 0;
+ return (n);
+}
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ ps->ps_recv = p->md.TotAccepted;
+ ps->ps_drop = p->md.TotDrops;
+ ps->ps_ifdrop = p->md.TotMissed - p->md.OrigMissed;
+ return (0);
+}
+
+pcap_t *
+pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+{
+ pcap_t *p;
+ short enmode;
+ int backlog = -1; /* request the most */
+ struct enfilter Filter;
+ struct endevp devparams;
+
+ p = (pcap_t *)malloc(sizeof(*p));
+ if (p == 0) {
+ strcpy(ebuf, "no swap");
+ return (0);
+ }
+ bzero(p, sizeof(*p));
+ p->fd = pfopen(device, 0);
+ if (p->fd < 0) {
+ sprintf(ebuf, "pf open: %s: %s\n\
+your system may not be properly configured; see \"man packetfilter(4)\"\n",
+ device, pcap_strerror(errno));
+ goto bad;
+ }
+ p->md.OrigMissed = -1;
+ enmode = ENTSTAMP|ENBATCH|ENNONEXCL;
+ if (promisc)
+ enmode |= ENPROMISC;
+ if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) {
+ sprintf(ebuf, "EIOCMBIS: %s", pcap_strerror(errno));
+ goto bad;
+ }
+#ifdef ENCOPYALL
+ /* Try to set COPYALL mode so that we see packets to ourself */
+ enmode = ENCOPYALL;
+ (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */
+#endif
+ /* set the backlog */
+ if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) {
+ sprintf(ebuf, "EIOCSETW: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ /* set truncation */
+ if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&snaplen) < 0) {
+ sprintf(ebuf, "EIOCTRUNCATE: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ p->snapshot = snaplen;
+ /* accept all packets */
+ Filter.enf_Priority = 37; /* anything > 2 */
+ Filter.enf_FilterLen = 0; /* means "always true" */
+ if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) {
+ sprintf(ebuf, "EIOCSETF: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ /* discover interface type */
+ if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) {
+ sprintf(ebuf, "EIOCDEVP: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ /* HACK: to compile prior to Ultrix 4.2 */
+#ifndef ENDT_FDDI
+#define ENDT_FDDI 4
+#endif
+ switch (devparams.end_dev_type) {
+ case ENDT_10MB:
+ p->linktype = DLT_EN10MB;
+ break;
+
+ case ENDT_FDDI:
+ p->linktype = DLT_FDDI;
+ break;
+
+ default:
+ /*
+ * XXX
+ * Currently, the Ultrix packet filter supports only
+ * Ethernet and FDDI. Eventually, support for SLIP and PPP
+ * (and possibly others: T1?) should be added.
+ */
+#ifdef notdef
+ warning(
+ "Packet filter data-link type %d unknown, assuming Ethernet",
+ devparams.end_dev_type);
+#endif
+ p->linktype = DLT_EN10MB;
+ break;
+ }
+
+ if (to_ms != 0) {
+ struct timeval timeout;
+ timeout.tv_sec = to_ms / 1000;
+ timeout.tv_usec = (to_ms * 1000) % 1000000;
+ if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) {
+ sprintf(ebuf, "EIOCSRTIMEOUT: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+ }
+ p->bufsize = BUFSPACE;
+ p->buffer = (u_char*)malloc(p->bufsize);
+
+ return (p);
+ bad:
+ free(p);
+ return (0);
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+ /*
+ * See if BIOCSETF works. If it does, the kernel supports
+ * BPF-style filters, and we do not need to do post-filtering.
+ */
+ p->md.use_bpf = (ioctl(p->fd, BIOCSETF, (caddr_t)fp) >= 0);
+ if (p->md.use_bpf) {
+ struct bpf_version bv;
+
+ if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) < 0) {
+ sprintf(p->errbuf, "BIOCVERSION: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+ else if (bv.bv_major != BPF_MAJOR_VERSION ||
+ bv.bv_minor < BPF_MINOR_VERSION) {
+ fprintf(stderr,
+ "requires bpf language %d.%d or higher; kernel is %d.%d",
+ BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
+ bv.bv_major, bv.bv_minor);
+ /* don't give up, just be inefficient */
+ p->md.use_bpf = 0;
+ }
+ } else
+ p->fcode = *fp;
+
+ /*XXX this goes in tcpdump*/
+ if (p->md.use_bpf)
+ fprintf(stderr, "tcpdump: Using kernel BPF filter\n");
+ else
+ fprintf(stderr, "tcpdump: Filtering in user process\n");
+ return (0);
+}
diff --git a/lib/libpcap/pcap-pf.h b/lib/libpcap/pcap-pf.h
new file mode 100644
index 0000000..65ca067
--- /dev/null
+++ b/lib/libpcap/pcap-pf.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 1990, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Lawrence Berkeley Laboratory,
+ * Berkeley, CA. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: pcap-pf.h,v 1.2 94/06/14 20:06:33 leres Exp $ (LBL)
+ */
diff --git a/lib/libpcap/pcap-snit.c b/lib/libpcap/pcap-snit.c
new file mode 100644
index 0000000..562b965
--- /dev/null
+++ b/lib/libpcap/pcap-snit.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: pcap-snit.c,v 1.33 94/06/23 13:51:17 leres Exp $ (LBL)";
+#endif
+
+/*
+ * Modifications made to accomodate the new SunOS4.0 NIT facility by
+ * Micky Liu, micky@cunixc.cc.columbia.edu, Columbia University in May, 1989.
+ * This module now handles the STREAMS based NIT.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/dir.h>
+#include <sys/fcntlcom.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stropts.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/nit.h>
+#include <net/nit_if.h>
+#include <net/nit_pf.h>
+#include <net/nit_buf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pcap-int.h"
+
+/*
+ * The chunk size for NIT. This is the amount of buffering
+ * done for read calls.
+ */
+#define CHUNKSIZE (2*1024)
+
+/*
+ * The total buffer space used by NIT.
+ */
+#define BUFSPACE (4*CHUNKSIZE)
+
+/* Forwards */
+static int nit_setflags(int, int, int, char *);
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+
+ *ps = p->md.stat;
+ return (0);
+}
+
+int
+pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ register int cc, n;
+ register struct bpf_insn *fcode = p->fcode.bf_insns;
+ register u_char *bp, *cp, *ep;
+ register struct nit_bufhdr *hdrp;
+ register struct nit_iftime *ntp;
+ register struct nit_iflen *nlp;
+ register struct nit_ifdrops *ndp;
+ register int caplen;
+
+ cc = p->cc;
+ if (cc == 0) {
+ cc = read(p->fd, (char *)p->buffer, p->bufsize);
+ if (cc < 0) {
+ if (errno == EWOULDBLOCK)
+ return (0);
+ sprintf(p->errbuf, "pcap_read: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+ bp = p->buffer;
+ } else
+ bp = p->bp;
+
+ /*
+ * loop through each snapshot in the chunk
+ */
+ n = 0;
+ ep = bp + cc;
+ while (bp < ep) {
+ ++p->md.stat.ps_recv;
+ cp = bp;
+
+ /* get past NIT buffer */
+ hdrp = (struct nit_bufhdr *)cp;
+ cp += sizeof(*hdrp);
+
+ /* get past NIT timer */
+ ntp = (struct nit_iftime *)cp;
+ cp += sizeof(*ntp);
+
+ ndp = (struct nit_ifdrops *)cp;
+ p->md.stat.ps_drop = ndp->nh_drops;
+ cp += sizeof *ndp;
+
+ /* get past packet len */
+ nlp = (struct nit_iflen *)cp;
+ cp += sizeof(*nlp);
+
+ /* next snapshot */
+ bp += hdrp->nhb_totlen;
+
+ caplen = nlp->nh_pktlen;
+ if (caplen > p->snapshot)
+ caplen = p->snapshot;
+
+ if (bpf_filter(fcode, cp, nlp->nh_pktlen, caplen)) {
+ struct pcap_pkthdr h;
+ h.ts = ntp->nh_timestamp;
+ h.len = nlp->nh_pktlen;
+ h.caplen = caplen;
+ (*callback)(user, &h, cp);
+ if (++n >= cnt && cnt >= 0) {
+ p->cc = ep - bp;
+ p->bp = bp;
+ return (n);
+ }
+ }
+ }
+ p->cc = 0;
+ return (n);
+}
+
+static int
+nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
+{
+ u_long flags;
+ struct strioctl si;
+ struct timeval timeout;
+
+ si.ic_timout = INFTIM;
+ if (to_ms != 0) {
+ timeout.tv_sec = to_ms / 1000;
+ timeout.tv_usec = (to_ms * 1000) % 1000000;
+ si.ic_cmd = NIOCSTIME;
+ si.ic_len = sizeof(timeout);
+ si.ic_dp = (char *)&timeout;
+ if (ioctl(fd, I_STR, (char *)&si) < 0) {
+ sprintf(ebuf, "NIOCSTIME: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ }
+ flags = NI_TIMESTAMP | NI_LEN | NI_DROPS;
+ if (promisc)
+ flags |= NI_PROMISC;
+ si.ic_cmd = NIOCSFLAGS;
+ si.ic_len = sizeof(flags);
+ si.ic_dp = (char *)&flags;
+ if (ioctl(fd, I_STR, (char *)&si) < 0) {
+ sprintf(ebuf, "NIOCSFLAGS: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
+
+pcap_t *
+pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+{
+ struct strioctl si; /* struct for ioctl() */
+ struct ifreq ifr; /* interface request struct */
+ int chunksize = CHUNKSIZE;
+ int fd;
+ static char dev[] = "/dev/nit";
+ register pcap_t *p;
+
+ p = (pcap_t *)malloc(sizeof(*p));
+ if (p == NULL) {
+ strcpy(ebuf, pcap_strerror(errno));
+ return (NULL);
+ }
+
+ if (snaplen < 96)
+ /*
+ * NIT requires a snapshot length of at least 96.
+ */
+ snaplen = 96;
+
+ bzero(p, sizeof(*p));
+ p->fd = fd = open(dev, O_RDONLY);
+ if (fd < 0) {
+ sprintf(ebuf, "%s: %s", dev, pcap_strerror(errno));
+ goto bad;
+ }
+
+ /* arrange to get discrete messages from the STREAM and use NIT_BUF */
+ if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) {
+ sprintf(ebuf, "I_SRDOPT: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ if (ioctl(fd, I_PUSH, "nbuf") < 0) {
+ sprintf(ebuf, "push nbuf: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ /* set the chunksize */
+ si.ic_cmd = NIOCSCHUNK;
+ si.ic_timout = INFTIM;
+ si.ic_len = sizeof(chunksize);
+ si.ic_dp = (char *)&chunksize;
+ if (ioctl(fd, I_STR, (char *)&si) < 0) {
+ sprintf(ebuf, "NIOCSCHUNK: %s", pcap_strerror(errno));
+ goto bad;
+ }
+
+ /* request the interface */
+ strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = ' ';
+ si.ic_cmd = NIOCBIND;
+ si.ic_len = sizeof(ifr);
+ si.ic_dp = (char *)&ifr;
+ if (ioctl(fd, I_STR, (char *)&si) < 0) {
+ sprintf(ebuf, "NIOCBIND: %s: %s",
+ ifr.ifr_name, pcap_strerror(errno));
+ goto bad;
+ }
+
+ /* set the snapshot length */
+ si.ic_cmd = NIOCSSNAP;
+ si.ic_len = sizeof(snaplen);
+ si.ic_dp = (char *)&snaplen;
+ if (ioctl(fd, I_STR, (char *)&si) < 0) {
+ sprintf(ebuf, "NIOCSSNAP: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ p->snapshot = snaplen;
+ if (nit_setflags(p->fd, promisc, to_ms, ebuf) < 0)
+ goto bad;
+
+ (void)ioctl(fd, I_FLUSH, (char *)FLUSHR);
+ /*
+ * NIT supports only ethernets.
+ */
+ p->linktype = DLT_EN10MB;
+
+ p->bufsize = BUFSPACE;
+ p->buffer = (u_char *)malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ strcpy(ebuf, pcap_strerror(errno));
+ goto bad;
+ }
+ return (p);
+ bad:
+ if (fd >= 0)
+ close(fd);
+ free(p);
+ return (NULL);
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+
+ p->fcode = *fp;
+ return (0);
+}
diff --git a/lib/libpcap/pcap-snoop.c b/lib/libpcap/pcap-snoop.c
new file mode 100644
index 0000000..50f9785
--- /dev/null
+++ b/lib/libpcap/pcap-snoop.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: pcap-snoop.c,v 1.6 94/01/31 05:26:09 leres Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <net/raw.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <net/bpf.h>
+
+#include "pcap-int.h"
+
+static int hdrpad; /* XXX */
+
+int
+pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ int cc;
+ register struct snoopheader *sh;
+ register int datalen;
+ register int caplen;
+ register u_char *cp;
+ again:
+ cc = read(p->fd, (char *)p->buffer, p->bufsize);
+ if (cc < 0) {
+ switch (errno) {
+ case EWOULDBLOCK:
+ return (0); /* XXX */
+ }
+ sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ sh = (struct snoopheader *)p->buffer;
+ datalen = sh->snoop_packetlen;
+ caplen = (datalen < p->snapshot) ? datalen : p->snapshot;
+ cp = (u_char *)(sh + 1) + hdrpad; /* XXX */
+
+ if (p->fcode.bf_insns == NULL ||
+ bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) {
+ struct pcap_pkthdr h;
+ ++p->md.stat.ps_recv;
+ h.ts = sh->snoop_timestamp;
+ h.len = datalen;
+ h.caplen = caplen;
+ (*callback)(user, &h, cp);
+ return (1);
+ }
+ return (0);
+}
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ register struct rawstats *rs;
+ struct rawstats rawstats;
+
+ rs = &rawstats;
+ bzero((char *)rs, sizeof(*rs));
+ if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) {
+ sprintf(p->errbuf, "SIOCRAWSTATS: %s", pcap_strerror(errno));
+ return (-1);
+ }
+
+ p->md.stat.ps_drop =
+ rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops +
+ rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops;
+
+ *ps = p->md.stat;
+ return (0);
+}
+
+/* XXX can't disable promiscuous */
+pcap_t *
+pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+{
+ pcap_t *p;
+ struct sockaddr_raw sr;
+ int fd;
+ int v;
+ struct snoopfilter sf;
+
+ p = (pcap_t *)malloc(sizeof(*p));
+ if (p == NULL) {
+ strcpy(ebuf, "no swap");
+ return (0);
+ }
+ bzero(p, sizeof(*p));
+ p->fd = -1;
+ p->bufsize = 4096; /* XXX */
+ p->buffer = (u_char *)malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ strcpy(ebuf, "no swap");
+ goto bad;
+ }
+ fd = p->fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP);
+ if (fd < 0) {
+ sprintf(ebuf, "snoop socket: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ sr.sr_family = AF_RAW;
+ sr.sr_port = 0;
+ (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname));
+ if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) {
+ sprintf(ebuf, "snoop bind: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ bzero((char *)&sf, sizeof(sf));
+ if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) {
+ sprintf(ebuf, "SIOCADDSNOOP: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ v = 64 * 1024;
+ (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v));
+ if (ioctl(fd, SIOCSNOOPLEN, &snaplen) < 0) {
+ sprintf(ebuf, "SIOCSNOOPLEN: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ p->snapshot = snaplen;
+ v = 1;
+ if (ioctl(fd, SIOCSNOOPING, &v) < 0) {
+ sprintf(ebuf, "SIOCSNOOPING: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ /*
+ * XXX hack - map device name to link later type
+ */
+ if (strncmp("et", device, 2) == 0 ||
+ strncmp("ec", device, 2) == 0) {
+ p->linktype = DLT_EN10MB;
+ hdrpad = RAW_HDRPAD(sizeof(struct ether_header));
+ } else if (strncmp("ipg", device, 3) == 0 ||
+ strncmp("xpi", device, 3) == 0) {
+ p->linktype = DLT_FDDI;
+ hdrpad = 3; /* XXX yeah? */
+ } else {
+ sprintf(ebuf, "snoop: unknown physical layer type");
+ goto bad;
+ }
+ return (p);
+ bad:
+ if (fd >= 0)
+ close(fd);
+ if (p->buffer != NULL)
+ free(p->buffer);
+ free(p);
+ return (0);
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+
+ p->fcode = *fp;
+ return (0);
+}
diff --git a/lib/libpcap/pcap.3 b/lib/libpcap/pcap.3
new file mode 100644
index 0000000..2159c4d
--- /dev/null
+++ b/lib/libpcap/pcap.3
@@ -0,0 +1,323 @@
+.\" Copyright (c) 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+.\" the University nor the names of its contributors may be used to endorse
+.\" or promote products derived from this software without specific prior
+.\" written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.TH PCAP 3 "14 Jun 1994"
+.SH NAME
+pcap \- Packet Capture library
+.SH SYNOPSIS
+.nf
+.ft B
+#include <pcap.h>
+.ft
+.LP
+.ft B
+pcap_t *pcap_open_live(char *device, int snaplen,
+.ti +8
+int promisc, int to_ms, char *ebuf)
+pcap_t *pcap_open_offline(char *fname, char *ebuf)
+pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname)
+.ft
+.LP
+.ft B
+char errbuf[PCAP_ERRBUF_SIZE];
+char *pcap_lookupdev(char *errbuf)
+int pcap_lookupnet(char *device, u_long *netp,
+.ti +8
+u_long *maskp, char *errbuf)
+.ft
+.LP
+.ft B
+int pcap_dispatch(pcap_t *p, int cnt,
+.ti +8
+pcap_handler callback, u_char *user)
+int pcap_loop(pcap_t *p, int cnt,
+.ti +8
+pcap_handler callback, u_char *user)
+void pcap_dump(u_char *user, struct pcap_pkthdr *h,
+.ti +8
+u_char *sp)
+.ft
+.LP
+.ft B
+int pcap_immediate(pcap_t *p)
+.ft
+.LP
+.ft B
+int pcap_compile(pcap_t *p, struct bpf_program *fp,
+.ti +8
+char *str, int optimize, u_long netmask)
+int pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+.ft
+.LP
+.ft B
+u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
+.ft
+.LP
+.ft B
+int pcap_datalink(pcap_t *p)
+int pcap_snapshot(pcap_t *p)
+int pcap_is_swapped(pcap_t *p)
+int pcap_major_version(pcap_t *p)
+int pcap_minor_version(pcap_t *p)
+int pcap_stats(pcap_t *p, struct pcap_stat *ps)
+FILE *pcap_file(pcap_t *p)
+int pcap_fileno(pcap_t *p)
+void pcap_perror(pcap_t *p, char *prefix)
+char *pcap_geterr(pcap_t *p)
+char *pcap_strerror(int error)
+.ft
+.LP
+.ft B
+void pcap_close(pcap_t *p)
+void pcap_dump_close(pcap_dumper_t *p)
+.ft
+.fi
+.SH DESCRIPTION
+The Packet Capture library
+provides a high level interface to packet capture systems. All packets
+on the network, even those destined for other hosts, are accessible
+through this mechanism.
+.PP
+.SH ROUTINES
+.B pcap_open_live()
+is used to obtain a packet capture descriptor to look
+at packets on the network.
+.I device
+is a string that specifies the network device to open.
+.I snaplen
+specifies the maximum number of bytes to capture.
+.I to_ms
+specifies the read timeout in milliseconds.
+.I ebuf
+is used to return error text and is only set when
+.B pcap_open_live()
+fails and returns
+.BR NULL .
+.PP
+.B pcap_open_offline()
+is called to open a ``savefile'' for reading.
+.I fname
+specifies the name of the file to open. The file has
+the same format as those used by
+.B tcpdump(1)
+and
+.BR tcpslice(1) .
+The name "-" in a synonym for
+.BR stdin .
+.I ebuf
+is used to return error text and is only set when
+.B pcap_open_offline()
+fails and returns
+.BR NULL .
+.PP
+.B pcap_dump_open()
+is called to open a ``savefile'' for writing. The name "-" in a synonym
+for
+.BR stdin .
+.B NULL
+is returned on failure.
+.I p
+is a
+.I pcap
+struct as returned by
+.B pcap_open_offline()
+or
+.BR pcap_open_live() .
+.I fname
+specifies the name of the file to open.
+If
+.B NULL
+is returned,
+.B pcap_geterr()
+can be used to get the error text.
+.PP
+.B pcap_lookupdev()
+returns a pointer to a network device suitable for use with
+.B pcap_open_live()
+and
+.BR pcap_lookupnet() .
+If there is an error,
+.B NULL
+is returned and
+.I errbuf
+is filled in with with an appropriate error message.
+.PP
+.B pcap_lookupnet()
+is used to determine the network number and mask
+associated with the network device
+.BR device .
+Both
+.I netp
+and
+.I maskp
+are
+.I u_long
+pointers.
+A return of -1 indicates an error in which case
+.I errbuf
+is filled in with with an appropriate error message.
+.PP
+.B pcap_dispatch()
+is used to collect and process packets.
+.I cnt
+specifies the maximum number of packets to process before returning. A
+.I cnt
+of -1 processes all the packets received in one buffer. A
+.I cnt
+of 0 processes all packets until an error occurs (or
+.B EOF
+is reached).
+.I callback
+specifies a routine to be called with three arguments:
+a
+.I u_char
+pointer which is passed in from
+.BR pcap_dispatch() ,
+a pointer to the
+.I pcap_pkthdr
+struct (which precede the actual network headers and data),
+and a length. The number of packets read is returned.
+Zero is returned when
+.B EOF
+is reached in a ``savefile.'' A return of -1 indicates
+an error in which case
+.B pcap_perror()
+or
+.BR pcap_geterr()
+may be used to display the error text.
+.PP
+.B pcap_dump()
+outputs a packet to the ``savefile'' opened with
+.BR pcap_dump_open() .
+Note that its calling arguments are suitable for use with
+.BR pcap_dispatch() .
+.ft B
+(??? this guy is kind of weird.)
+.ft
+.PP
+.B pcap_immediate()
+sets ``immediate'' mode.
+If this isn't supported by the under lying packet capture, -1 is
+returned and the error text can be obtained with
+.B pcap_perror()
+or
+.BR pcap_geterr() .
+.PP
+.B pcap_compile()
+is used to compile the string
+.I str
+into a filter program.
+.I program
+is a pointer to a
+.I bpf_program
+struct and is filled in by
+.BR pcap_compile() .
+.I optimize
+controls whether optimization on the resulting code is performed.
+.I netmask
+specifies the netmask of the local net.
+.PP
+.B pcap_setfilter()
+is used to specify the a filter program.
+.I fp
+is a pointer to an array of
+.I bpf_program
+struct, usually the result of a call to
+.BR pcap_compile() .
+.PP
+.B pcap_loop()
+is similar to
+.B pcap_dispatch()
+except it keeps reading packets until
+.I cnt
+packets are processed or an error occurs.
+A negative
+.I cnt
+causes
+.B pcap_loop()
+to loop forever (or at least until an error occurs).
+.PP
+.B pcap_next()
+returns a
+.I u_char
+pointer to the next packet.
+.PP
+.B pcap_datalink()
+returns the link layer type, e.g.
+.BR DLT_EN10MB .
+.PP
+.B pcap_snapshot()
+returns the snapshot length specified when
+.B pcap_open_live
+was called.
+.PP
+.B pcap_is_swapped()
+returns true if the current ``savefile'' uses a different byte order
+than the current system.
+.PP
+.B pcap_major_version()
+returns the major number of the version of the pcap used to write the
+savefile.
+.PP
+.B pcap_minor_version()
+returns the major number of the version of the pcap used to write the
+savefile.
+.PP
+.B pcap_file()
+returns the name of the ``savefile.''
+.PP
+.B int pcap_stats()
+returns 0 and fills in a
+.B pcap_stat
+struct with packet statistics. If there is an error or the under lying
+packet capture doesn't support packet statistics, -1 is returned and
+the error text can be obtained with
+.B pcap_perror()
+or
+.BR pcap_geterr() .
+.PP
+.B pcap_fileno()
+returns the file descriptor number of the ``savefile.''
+.PP
+.B pcap_perror()
+prints the text of the last pcap library error on
+.BR stderr ,
+prefixed by
+.IR prefix .
+.PP
+.B pcap_geterr()
+returns the error text pertaining to the last pcap library error.
+.PP
+.B pcap_strerror()
+is provided in case
+.BR strerror (1)
+isn't available.
+.PP
+.B pcap_close()
+closes the files associated with
+.I p
+and deallocates resources.
+.PP
+.B pcap_dump_close()
+closes the ``savefile.''
+.PP
+.SH SEE ALSO
+tcpdump(1), tcpslice(1)
+.SH BUGS
+.SH HISTORY
diff --git a/lib/libpcap/pcap.c b/lib/libpcap/pcap.c
new file mode 100644
index 0000000..82070d2
--- /dev/null
+++ b/lib/libpcap/pcap.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: pcap.c,v 1.12 94/06/12 14:32:23 leres Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+
+#include <unistd.h>
+
+#include "pcap-int.h"
+
+int
+pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ if (p->sf.rfile != NULL)
+ return (pcap_offline_read(p, cnt, callback, user));
+ else
+ return (pcap_read(p, cnt, callback, user));
+}
+
+int
+pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ for (;;) {
+ int n = pcap_dispatch(p, cnt, callback, user);
+ if (n < 0)
+ return (n);
+ if (cnt > 0) {
+ cnt -= n;
+ if (cnt <= 0)
+ return (0);
+ }
+ }
+}
+
+struct singleton {
+ struct pcap_pkthdr *hdr;
+ const u_char *pkt;
+};
+
+
+static void
+pcap_oneshot(u_char *userData, const struct pcap_pkthdr *h, const u_char *pkt)
+{
+ struct singleton *sp = (struct singleton *)userData;
+ *sp->hdr = *h;
+ sp->pkt = pkt;
+}
+
+const u_char *
+pcap_next(pcap_t *p, struct pcap_pkthdr *h)
+{
+ struct singleton s;
+
+ s.hdr = h;
+ if (pcap_dispatch(p, 1, pcap_oneshot, (u_char*)&s) < 0)
+ return (0);
+ return (s.pkt);
+}
+
+int
+pcap_datalink(pcap_t *p)
+{
+ return (p->linktype);
+}
+
+int
+pcap_snapshot(pcap_t *p)
+{
+ return (p->snapshot);
+}
+
+int
+pcap_is_swapped(pcap_t *p)
+{
+ return (p->sf.swapped);
+}
+
+int
+pcap_major_version(pcap_t *p)
+{
+ return (p->sf.version_major);
+}
+
+int
+pcap_minor_version(pcap_t *p)
+{
+ return (p->sf.version_minor);
+}
+
+FILE *
+pcap_file(pcap_t *p)
+{
+ return (p->sf.rfile);
+}
+
+int
+pcap_fileno(pcap_t *p)
+{
+ return (p->fd);
+}
+
+void
+pcap_perror(pcap_t *p, char *prefix)
+{
+ fprintf(stderr, "%s: %s\n", prefix, p->errbuf);
+}
+
+char *
+pcap_geterr(pcap_t *p)
+{
+ return (p->errbuf);
+}
+
+/*
+ * Not all systems have strerror().
+ */
+char *
+pcap_strerror(int errnum)
+{
+ extern int sys_nerr;
+/*
+ extern char *sys_errlist[];
+*/
+ static char ebuf[20];
+
+ if ((unsigned int)errnum < sys_nerr)
+ return (sys_errlist[errnum]);
+ (void)sprintf(ebuf, "Unknown error: %d", errnum);
+ return(ebuf);
+}
+
+void
+pcap_close(pcap_t *p)
+{
+ /*XXX*/
+ if (p->fd >= 0)
+ close(p->fd);
+ if (p->sf.rfile != NULL) {
+ fclose(p->sf.rfile);
+ if (p->sf.base != NULL)
+ free(p->sf.base);
+ } else if (p->buffer != NULL)
+ free(p->buffer);
+
+ free(p);
+}
diff --git a/lib/libpcap/pcap.h b/lib/libpcap/pcap.h
new file mode 100644
index 0000000..506b15b
--- /dev/null
+++ b/lib/libpcap/pcap.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: pcap.h,v 1.15 94/06/14 20:03:34 leres Exp $ (LBL)
+ */
+
+#ifndef lib_pcap_h
+#define lib_pcap_h
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <net/bpf.h>
+
+#include <stdio.h>
+
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+
+#define PCAP_ERRBUF_SIZE 256
+
+/*
+ * Compatibility for systems that have a bpf.h that
+ * predates the bpf typedefs for 64-bit support.
+ */
+#if BPF_RELEASE - 0 < 199406
+typedef long bpf_int32;
+typedef u_long bpf_u_int32;
+#endif
+
+typedef struct pcap pcap_t;
+typedef struct pcap_dumper pcap_dumper_t;
+
+/*
+ * The first record in the file contains saved values for some
+ * of the flags used in the printout phases of tcpdump.
+ * Many fields here are longs so compilers won't insert unwanted
+ * padding; these files need to be interchangeable across architectures.
+ */
+struct pcap_file_header {
+ bpf_u_int32 magic;
+ u_short version_major;
+ u_short version_minor;
+ bpf_int32 thiszone; /* gmt to local correction */
+ bpf_u_int32 sigfigs; /* accuracy of timestamps */
+ bpf_u_int32 snaplen; /* max length saved portion of each pkt */
+ bpf_u_int32 linktype; /* data link type (DLT_*) */
+};
+
+/*
+ * Each packet in the dump file is prepended with this generic header.
+ * This gets around the problem of different headers for different
+ * packet interfaces.
+ */
+struct pcap_pkthdr {
+ struct timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length this packet (off wire) */
+};
+
+/*
+ * As returned by the pcap_stats()
+ */
+struct pcap_stat {
+ u_int ps_recv; /* number of packets received */
+ u_int ps_drop; /* number of packets dropped */
+ u_int ps_ifdrop; /* drops by interface XXX not yet supported */
+};
+
+typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
+ const u_char *);
+
+char *pcap_lookupdev(char *);
+int pcap_lookupnet(char *, u_long *, u_long *, char *);
+pcap_t *pcap_open_live(char *, int, int, int, char *);
+pcap_t *pcap_open_offline(char *, char *);
+void pcap_close(pcap_t *);
+int pcap_loop(pcap_t *, int, pcap_handler, u_char *);
+int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *);
+const u_char*
+ pcap_next(pcap_t *, struct pcap_pkthdr *);
+int pcap_stats(pcap_t *, struct pcap_stat *);
+int pcap_setfilter(pcap_t *, struct bpf_program *);
+void pcap_perror(pcap_t *, char *);
+char *pcap_strerror(int);
+char *pcap_geterr(pcap_t *);
+int pcap_compile(pcap_t *, struct bpf_program *, char *, int, u_long);
+/* XXX */
+int pcap_freecode(pcap_t *, struct bpf_program *);
+int pcap_datalink(pcap_t *);
+int pcap_snapshot(pcap_t *);
+int pcap_is_swapped(pcap_t *);
+int pcap_major_version(pcap_t *);
+int pcap_minor_version(pcap_t *);
+
+/* XXX */
+FILE *pcap_file(pcap_t *);
+int pcap_fileno(pcap_t *);
+
+pcap_dumper_t *pcap_dump_open(pcap_t *, char *);
+void pcap_dump_close(pcap_dumper_t *);
+void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *);
+
+/* XXX this guy lives in the bpf tree */
+u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
+char *bpf_image(struct bpf_insn *, int);
+
+#endif
diff --git a/lib/libpcap/savefile.c b/lib/libpcap/savefile.c
new file mode 100644
index 0000000..90ee723
--- /dev/null
+++ b/lib/libpcap/savefile.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: savefile.c,v 1.16 94/06/20 19:07:56 leres Exp $ (LBL)";
+#endif
+
+/*
+ * savefile.c - supports offline use of tcpdump
+ * Extraction/creation by Jeffrey Mogul, DECWRL
+ * Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <net/bpf.h>
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pcap-int.h"
+
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+
+/*
+ * We use the "receiver-makes-right" approach to byte order,
+ * because time is at a premium when we are writing the file.
+ * In other words, the pcap_file_header and pcap_pkthdr,
+ * records are written in host byte order.
+ * Note that the packets are always written in network byte order.
+ *
+ * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
+ * machine (if the file was written in little-end order).
+ */
+#define SWAPLONG(y) \
+((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
+#define SWAPSHORT(y) \
+ ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) )
+
+#define SFERR_TRUNC 1
+#define SFERR_BADVERSION 2
+#define SFERR_BADF 3
+#define SFERR_EOF 4 /* not really an error, just a status */
+
+static int
+sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen)
+{
+ struct pcap_file_header hdr;
+
+ hdr.magic = TCPDUMP_MAGIC;
+ hdr.version_major = PCAP_VERSION_MAJOR;
+ hdr.version_minor = PCAP_VERSION_MINOR;
+
+ hdr.thiszone = thiszone;
+ hdr.snaplen = snaplen;
+ hdr.sigfigs = 0;
+ hdr.linktype = linktype;
+
+ if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
+ return (-1);
+
+ return (0);
+}
+
+static void
+swap_hdr(struct pcap_file_header *hp)
+{
+ hp->version_major = SWAPSHORT(hp->version_major);
+ hp->version_minor = SWAPSHORT(hp->version_minor);
+ hp->thiszone = SWAPLONG(hp->thiszone);
+ hp->sigfigs = SWAPLONG(hp->sigfigs);
+ hp->snaplen = SWAPLONG(hp->snaplen);
+ hp->linktype = SWAPLONG(hp->linktype);
+}
+
+pcap_t *
+pcap_open_offline(char *fname, char *errbuf)
+{
+ register pcap_t *p;
+ register FILE *fp;
+ struct pcap_file_header hdr;
+ int linklen;
+
+ p = (pcap_t *)malloc(sizeof(*p));
+ if (p == NULL) {
+ strcpy(errbuf, "out of swap");
+ return (NULL);
+ }
+
+#ifdef notdef
+ bzero(p, sizeof(*p));
+#else
+ memset(p, 0, sizeof(*p));
+#endif
+ /*
+ * Set this field so we don't close stdin in pcap_close!
+ */
+ p->fd = -1;
+
+ if (fname[0] == '-' && fname[1] == '\0')
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ sprintf(errbuf, "%s: %s", fname, pcap_strerror(errno));
+ goto bad;
+ }
+ }
+ if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
+ sprintf(errbuf, "fread: %s", pcap_strerror(errno));
+ goto bad;
+ }
+ if (hdr.magic != TCPDUMP_MAGIC) {
+ if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC) {
+ sprintf(errbuf, "bad dump file format");
+ goto bad;
+ }
+ p->sf.swapped = 1;
+ swap_hdr(&hdr);
+ }
+ if (hdr.version_major < PCAP_VERSION_MAJOR) {
+ sprintf(errbuf, "archaic file format");
+ goto bad;
+ }
+ p->tzoff = hdr.thiszone;
+ p->snapshot = hdr.snaplen;
+ p->linktype = hdr.linktype;
+ p->sf.rfile = fp;
+ p->bufsize = hdr.snaplen;
+ /* Align link header as required for proper data alignment */
+ linklen = 14; /* XXX */
+ p->sf.base = (u_char *)malloc(p->bufsize + BPF_ALIGNMENT);
+ p->buffer = p->sf.base + BPF_ALIGNMENT - (linklen % BPF_ALIGNMENT);
+ p->sf.version_major = hdr.version_major;
+ p->sf.version_minor = hdr.version_minor;
+
+ return (p);
+ bad:
+ free(p);
+ return (NULL);
+}
+
+/*
+ * Read sf_readfile and return the next packet. Return the header in hdr
+ * and the contents in buf. Return 0 on success, SFERR_EOF if there were
+ * no more packets, and SFERR_TRUNC if a partial packet was encountered.
+ */
+static int
+sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen)
+{
+ FILE *fp = p->sf.rfile;
+
+ /* read the stamp */
+ if (fread((char *)hdr, sizeof(struct pcap_pkthdr), 1, fp) != 1) {
+ /* probably an EOF, though could be a truncated packet */
+ return (1);
+ }
+
+ if (p->sf.swapped) {
+ /* these were written in opposite byte order */
+ hdr->caplen = SWAPLONG(hdr->caplen);
+ hdr->len = SWAPLONG(hdr->len);
+ hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
+ hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
+ }
+ /*
+ * We interchanged the caplen and len fields at version 2.3,
+ * in order to match the bpf header layout. But unfortunately
+ * some files were written with version 2.3 in their headers
+ * but without the interchanged fields.
+ */
+ if (p->sf.version_minor < 3 ||
+ (p->sf.version_minor == 3 && hdr->caplen > hdr->len)) {
+ int t = hdr->caplen;
+ hdr->caplen = hdr->len;
+ hdr->len = t;
+ }
+
+ if (hdr->caplen > buflen) {
+ sprintf(p->errbuf, "bad dump file format");
+ return (-1);
+ }
+
+ /* read the packet itself */
+
+ if (fread((char *)buf, hdr->caplen, 1, fp) != 1) {
+ sprintf(p->errbuf, "truncated dump file");
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Print out packets stored in the file initialized by sf_read_init().
+ * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
+ */
+int
+pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ struct bpf_insn *fcode = p->fcode.bf_insns;
+ int status = 0;
+ int n = 0;
+
+ while (status == 0) {
+ struct pcap_pkthdr h;
+
+ status = sf_next_packet(p, &h, p->buffer, p->bufsize);
+ if (status)
+ return (-1);
+
+ if (fcode == NULL ||
+ bpf_filter(fcode, p->buffer, h.len, h.caplen)) {
+ (*callback)(user, &h, p->buffer);
+ if (++n >= cnt && cnt > 0)
+ break;
+ }
+ }
+ /*XXX this breaks semantics tcpslice expects */
+ return (n);
+}
+
+/*
+ * Output a packet to the initialized dump file.
+ */
+void
+pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
+{
+ FILE * f = (FILE *)user;
+ (void)fwrite((char *)h, sizeof(*h), 1, f);
+ (void)fwrite((char *)sp, h->caplen, 1, f);
+}
+
+/*
+ * Initialize so that sf_write() will output to the file named 'fname'.
+ */
+pcap_dumper_t *
+pcap_dump_open(pcap_t *p, char *fname)
+{
+ FILE *f;
+ if (fname[0] == '-' && fname[1] == '\0')
+ f = stdout;
+ else {
+ f = fopen(fname, "w");
+ if (f == NULL) {
+ sprintf(p->errbuf, "%s: %s",
+ fname, pcap_strerror(errno));
+ return (NULL);
+ }
+ }
+ (void)sf_write_header(f, p->linktype, p->tzoff, p->snapshot);
+ return ((pcap_dumper_t *)f);
+}
+
+void
+pcap_dump_close(pcap_dumper_t *p)
+{
+ fclose((FILE *)p);
+}
diff --git a/lib/libpcap/scanner.l b/lib/libpcap/scanner.l
new file mode 100644
index 0000000..c2ff10d
--- /dev/null
+++ b/lib/libpcap/scanner.l
@@ -0,0 +1,193 @@
+%{
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: scanner.l,v 1.40 94/06/10 17:21:44 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <pcap.h>
+#include <pcap-namedb.h>
+
+#include "gencode.h"
+#include "tokdefs.h"
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+static int stoi(char *);
+static inline int xdtoi(int);
+
+#ifdef FLEX_SCANNER
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max)\
+ {\
+ char *src = in_buffer;\
+ int i;\
+\
+ if (*src == 0)\
+ result = YY_NULL;\
+ else {\
+ for (i = 0; *src && i < max; ++i)\
+ buf[i] = *src++;\
+ in_buffer += i;\
+ result = i;\
+ }\
+ }
+#else
+#undef getc
+#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++)
+#endif
+
+#define yylval pcap_lval
+extern YYSTYPE yylval;
+
+static char *in_buffer;
+
+%}
+
+N ([0-9]+|(0X|0x)[0-9A-Fa-f]+)
+B ([0-9A-Fa-f][0-9A-Fa-f]?)
+
+%a 3000
+
+%%
+dst return DST;
+src return SRC;
+
+link|ether|ppp|slip return LINK;
+fddi return LINK;
+arp return ARP;
+rarp return RARP;
+ip return IP;
+tcp return TCP;
+udp return UDP;
+icmp return ICMP;
+
+decnet return DECNET;
+lat return LAT;
+moprc return MOPRC;
+mopdl return MOPDL;
+
+host return HOST;
+net return NET;
+port return PORT;
+proto return PROTO;
+
+gateway return GATEWAY;
+
+less return LESS;
+greater return GREATER;
+byte return BYTE;
+broadcast return TK_BROADCAST;
+multicast return TK_MULTICAST;
+
+and|"&&" return AND;
+or|"||" return OR;
+not return '!';
+
+len|length return LEN;
+inbound return INBOUND;
+outbound return OUTBOUND;
+
+[ \n\t] ;
+[+\-*/:\[\]!<>()&|=] return yytext[0];
+">=" return GEQ;
+"<=" return LEQ;
+"!=" return NEQ;
+"==" return '=';
+"<<" return LSH;
+">>" return RSH;
+{N} { yylval.i = stoi((char *)yytext); return NUM; }
+({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) {
+ yylval.s = sdup((char *)yytext); return HID;
+}
+{B}:{B}:{B}:{B}:{B}:{B} { yylval.e = pcap_ether_aton((char *)yytext);
+ return EID; }
+{B}:+({B}:+)+ { bpf_error("bogus ethernet address %s", yytext); }
+[A-Za-z][-_.A-Za-z0-9]* { yylval.s = sdup((char *)yytext); return ID; }
+"\\"[^ !()\n\t]+ { yylval.s = sdup((char *)yytext + 1); return ID; }
+[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { bpf_error("illegal token: %s\n", yytext); }
+. { bpf_error("illegal char '%c'", *yytext); }
+%%
+void
+lex_init(buf)
+ char *buf;
+{
+ in_buffer = buf;
+}
+
+/*
+ * Also define a yywrap. Note that if we're using flex, it will
+ * define a macro to map this identifier to pcap_wrap.
+ */
+int
+yywrap()
+{
+ return 1;
+}
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+ register int c;
+{
+ if (isdigit(c))
+ return c - '0';
+ else if (islower(c))
+ return c - 'a' + 10;
+ else
+ return c - 'A' + 10;
+}
+
+/*
+ * Convert string to integer. Just like atoi(), but checks for
+ * preceding 0x or 0 and uses hex or octal instead of decimal.
+ */
+static int
+stoi(s)
+ char *s;
+{
+ int base = 10;
+ int n = 0;
+
+ if (*s == '0') {
+ if (s[1] == 'x' || s[1] == 'X') {
+ s += 2;
+ base = 16;
+ }
+ else {
+ base = 8;
+ s += 1;
+ }
+ }
+ while (*s)
+ n = n * base + xdtoi(*s++);
+
+ return n;
+}
+
OpenPOWER on IntegriCloud