summaryrefslogtreecommitdiff
path: root/lib/libpcap
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /lib/libpcap
initial import of NetBSD tree
Diffstat (limited to 'lib/libpcap')
-rw-r--r--lib/libpcap/CHANGES22
-rw-r--r--lib/libpcap/Makefile24
-rw-r--r--lib/libpcap/README62
-rw-r--r--lib/libpcap/bpf_image.c286
-rw-r--r--lib/libpcap/etherent.c150
-rw-r--r--lib/libpcap/ethertype.h76
-rw-r--r--lib/libpcap/gencode.c1757
-rw-r--r--lib/libpcap/gencode.h175
-rw-r--r--lib/libpcap/grammar.y266
-rw-r--r--lib/libpcap/inet.c198
-rw-r--r--lib/libpcap/nametoaddr.c363
-rw-r--r--lib/libpcap/optimize.c1928
-rw-r--r--lib/libpcap/pcap-bpf.c238
-rw-r--r--lib/libpcap/pcap-int.h100
-rw-r--r--lib/libpcap/pcap-namedb.h78
-rw-r--r--lib/libpcap/pcap.3325
-rw-r--r--lib/libpcap/pcap.c175
-rw-r--r--lib/libpcap/pcap.h139
-rw-r--r--lib/libpcap/savefile.c287
-rw-r--r--lib/libpcap/scanner.l194
-rw-r--r--lib/libpcap/shlib_version2
21 files changed, 6845 insertions, 0 deletions
diff --git a/lib/libpcap/CHANGES b/lib/libpcap/CHANGES
new file mode 100644
index 00000000000..4053d1c0a24
--- /dev/null
+++ b/lib/libpcap/CHANGES
@@ -0,0 +1,22 @@
+$NetBSD: CHANGES,v 1.2 1995/03/06 11:37:58 mycroft Exp $
+@(#) Header: CHANGES,v 1.4 94/06/20 19:22:33 leres Exp (LBL)
+
+v0.0 Mon Jun 20 19:20:16 PDT 1994
+
+- Initial release.
+
+- Fixed bug with greater/less keywords, reported by Mark Andrews
+ (mandrews@alias.com).
+
+- Fix bug where '|' was defined as BPF_AND instead of BPF_OR, reported
+ by Elan Amir (elan@leeb.cs.berkeley.edu).
+
+- Machines with little-endian byte ordering are supported thanks to
+ Jeff Mogul.
+
+- Add hack for version 2.3 savefiles which don't have caplen and len
+ swapped thanks to Vern Paxson.
+
+- Added "&&" and "||" aliases for "and" and "or" thanks to Vern Paxson.
+
+- Added length, inbound and outbound keywords.
diff --git a/lib/libpcap/Makefile b/lib/libpcap/Makefile
new file mode 100644
index 00000000000..2037374a59c
--- /dev/null
+++ b/lib/libpcap/Makefile
@@ -0,0 +1,24 @@
+# $NetBSD: Makefile,v 1.1 1995/03/06 11:38:04 mycroft Exp $
+
+LIB= pcap
+MAN= pcap.3
+
+CFLAGS+=-I. -I${.CURDIR}
+
+HDRS= pcap.h pcap-namedb.h
+SRCS= pcap.c inet.c gencode.c optimize.c nametoaddr.c etherent.c \
+ savefile.c bpf_filter.c bpf_image.c grammar.y scanner.l \
+ pcap-bpf.c
+.PATH: ${.CURDIR}/../../sys/net
+
+CLEANFILES+= grammar.c scanner.c y.tab.h
+
+beforeinstall:
+ @cd ${.CURDIR}; for i in $(HDRS); do \
+ cmp -s $$i ${DESTDIR}/usr/include/$$i || \
+ { j="install -c -o ${BINOWN} -g ${BINGRP} -m 444 $$i \
+ ${DESTDIR}/usr/include"; \
+ echo $$j; $$j; } \
+ done
+
+.include <bsd.lib.mk>
diff --git a/lib/libpcap/README b/lib/libpcap/README
new file mode 100644
index 00000000000..d4d7b634c00
--- /dev/null
+++ b/lib/libpcap/README
@@ -0,0 +1,62 @@
+$NetBSD: README,v 1.2 1995/03/06 11:38:07 mycroft Exp $
+@(#) Header: README,v 1.7 94/06/20 18:56:55 leres Exp (LBL)
+
+LIBPCAP 0.0
+Lawrence Berkeley Laboratory
+Network Research Group
+libpcap@ee.lbl.gov
+ftp://ftp.ee.lbl.gov/libpcap-*.tar.Z
+
+This directory contains source code for libpcap, a system-independent
+interface for user-level packet capture. libpcap provides a portable
+framework for low-level network monitoring. Applications include
+network statistics collection, security monitoring, network debugging,
+etc. Since almost every system vendor provides a different interface
+for packet capture, and since we've developed several tools that require
+these interfaces, we've created this system-independent API to ease in
+porting and to alleviate the need for several system-dependent packet
+capture modules in each application.
+
+THIS IS AN ALPHA-QUALITY RELEASE. The interface is brand new and is
+likely to change. If you code to this interface, and want to track
+future versions, be prepared to update your code. We admit that this
+release is premature, but we're releasing it anyway because the tcpdump-3.0
+distribution requires it.
+
+libpcap has been built and tested under SGI Irix 4.x & 5.2, SunOS 4.x,
+Solaris 2.3, BSD/386 v1.1, DEC/OSF v1.3 v2.0, and Ultrix 4.x. SunOS 3.5
+4.3BSD Reno/Tahoe and 4.4BSD are supported as well, but we currently
+do not have the resources to carry out testing in these environments
+(we suspect you'll run into problems under these systems -- please
+send us the patches if you fix any porting problems).
+
+The libpcap interface supports a filtering mechanism based on the
+architecture in the BSD packet filter. BPF is described in the
+1993 Winter Usenix paper ``The BSD Packet Filter: A New Architecture
+for User-level Packet Capture''. A compressed postscript version is in
+
+ ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z.
+
+Although most packet capture interfaces support in-kernel filtering,
+libpcap utilizes in-kernel filtering only for the BPF interface.
+On systems that don't have BPF, all packets are read into user-space
+and the BPF filters are evaluated in the libpcap library, incurring
+added overhead (especially, for selective filters). We haven't tried
+taking advantage of other packet filter models first because they
+aren't general enough (i.e., only simple filters can be evaluated),
+and second because we don't have the time to modify the code generator
+(or write a filter translator) and BPF is more efficient anyway.
+
+BPF is standard in 4.4BSD, BSD/386, NetBSD, and FreeBSD. DEC OSF/1
+uses the packetfilter interface but has been extended to accept
+BPF filters (which libpcap utilizes). Also, you can add BPF filter
+support to Ultrix using the kernel source and/or object patches
+available in
+
+ ftp://gatekeeper.dec.com/pub/DEC/net/bpfext42.tar.Z.
+
+Please send bugs and comments to libpcap@ee.lbl.gov.
+
+ - Steve McCanne (mccanne@ee.lbl.gov)
+ Craig Leres (leres@ee.lbl.gov)
+ Van Jacobson (van@ee.lbl.gov)
diff --git a/lib/libpcap/bpf_image.c b/lib/libpcap/bpf_image.c
new file mode 100644
index 00000000000..963effb9915
--- /dev/null
+++ b/lib/libpcap/bpf_image.c
@@ -0,0 +1,286 @@
+/* $NetBSD: bpf_image.c,v 1.2 1995/03/06 11:38:11 mycroft Exp $ */
+
+/*
+ * 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 00000000000..227e674f70c
--- /dev/null
+++ b/lib/libpcap/etherent.c
@@ -0,0 +1,150 @@
+/* $NetBSD: etherent.c,v 1.2 1995/03/06 11:38:14 mycroft Exp $ */
+
+/*
+ * 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 00000000000..21c0a6d4095
--- /dev/null
+++ b/lib/libpcap/ethertype.h
@@ -0,0 +1,76 @@
+/* $NetBSD: ethertype.h,v 1.2 1995/03/06 11:38:17 mycroft Exp $ */
+
+/*
+ * 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 00000000000..4cdfc31265c
--- /dev/null
+++ b/lib/libpcap/gencode.c
@@ -0,0 +1,1757 @@
+/* $NetBSD: gencode.c,v 1.2 1995/03/06 11:38:21 mycroft Exp $ */
+
+/*
+ * 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 00000000000..28ee5d49890
--- /dev/null
+++ b/lib/libpcap/gencode.h
@@ -0,0 +1,175 @@
+/* $NetBSD: gencode.h,v 1.2 1995/03/06 11:38:24 mycroft Exp $ */
+
+/*
+ * 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 00000000000..c005228fe73
--- /dev/null
+++ b/lib/libpcap/grammar.y
@@ -0,0 +1,266 @@
+%{
+/* $NetBSD: grammar.y,v 1.2 1995/03/06 11:38:27 mycroft Exp $ */
+
+/*
+ * 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 00000000000..09bac3deb9f
--- /dev/null
+++ b/lib/libpcap/inet.c
@@ -0,0 +1,198 @@
+/* $NetBSD: inet.c,v 1.2 1995/03/06 11:38:29 mycroft Exp $ */
+
+/*
+ * 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 00000000000..d7ac9fdf616
--- /dev/null
+++ b/lib/libpcap/nametoaddr.c
@@ -0,0 +1,363 @@
+/* $NetBSD: nametoaddr.c,v 1.3 1995/04/29 05:42:23 cgd Exp $ */
+
+/*
+ * 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>
+#ifdef __NetBSD__
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#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 00000000000..c416d70ecb7
--- /dev/null
+++ b/lib/libpcap/optimize.c
@@ -0,0 +1,1928 @@
+/* $NetBSD: optimize.c,v 1.3 1995/04/29 05:42:28 cgd Exp $ */
+
+/*
+ * 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
+#ifdef __NetBSD__
+#include <stdlib.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 00000000000..b73c86cc5a5
--- /dev/null
+++ b/lib/libpcap/pcap-bpf.c
@@ -0,0 +1,238 @@
+/* $NetBSD: pcap-bpf.c,v 1.3 1995/04/29 05:42:31 cgd Exp $ */
+
+/*
+ * 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>
+#ifdef __NetBSD__
+#include <stdlib.h>
+#endif
+
+#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-int.h b/lib/libpcap/pcap-int.h
new file mode 100644
index 00000000000..c3d6f5c705b
--- /dev/null
+++ b/lib/libpcap/pcap-int.h
@@ -0,0 +1,100 @@
+/* $NetBSD: pcap-int.h,v 1.2 1995/03/06 11:38:47 mycroft Exp $ */
+
+/*
+ * 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 00000000000..7093c4a2bf4
--- /dev/null
+++ b/lib/libpcap/pcap-namedb.h
@@ -0,0 +1,78 @@
+/* $NetBSD: pcap-namedb.h,v 1.2 1995/03/06 11:38:48 mycroft Exp $ */
+
+/*
+ * 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.3 b/lib/libpcap/pcap.3
new file mode 100644
index 00000000000..ac8c422a901
--- /dev/null
+++ b/lib/libpcap/pcap.3
@@ -0,0 +1,325 @@
+.\" $NetBSD: pcap.3,v 1.2 1995/03/06 11:39:03 mycroft Exp $
+.\"
+.\" 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 00000000000..a59f65a127d
--- /dev/null
+++ b/lib/libpcap/pcap.c
@@ -0,0 +1,175 @@
+/* $NetBSD: pcap.c,v 1.2 1995/03/06 11:39:05 mycroft Exp $ */
+
+/*
+ * 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 <string.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)
+{
+
+ return (strerror(errnum));
+}
+
+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 00000000000..e839e643d6a
--- /dev/null
+++ b/lib/libpcap/pcap.h
@@ -0,0 +1,139 @@
+/* $NetBSD: pcap.h,v 1.2 1995/03/06 11:39:07 mycroft Exp $ */
+
+/*
+ * 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 00000000000..ae15ce6f81e
--- /dev/null
+++ b/lib/libpcap/savefile.c
@@ -0,0 +1,287 @@
+/* $NetBSD: savefile.c,v 1.2 1995/03/06 11:39:10 mycroft Exp $ */
+
+/*
+ * 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 00000000000..fb203f42527
--- /dev/null
+++ b/lib/libpcap/scanner.l
@@ -0,0 +1,194 @@
+%{
+/* $NetBSD: scanner.l,v 1.2 1995/03/06 11:39:12 mycroft Exp $ */
+
+/*
+ * 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 "y.tab.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
+
+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;
+}
+
diff --git a/lib/libpcap/shlib_version b/lib/libpcap/shlib_version
new file mode 100644
index 00000000000..97c9f92d6b8
--- /dev/null
+++ b/lib/libpcap/shlib_version
@@ -0,0 +1,2 @@
+major=0
+minor=0