*/
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.118 2000-09-18 06:39:44 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.129 2000-10-28 09:30:21 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
#include <net/if.h>
#include <netinet/in.h>
-#include <netinet/if_ether.h>
#include <stdlib.h>
+#include <string.h>
#include <memory.h>
#include <setjmp.h>
#include <stdarg.h>
#include "pcap-int.h"
#include "ethertype.h"
+#include "nlpid.h"
#include "gencode.h"
#include "ppp.h"
#include <pcap-namedb.h>
#include <sys/socket.h>
#endif /*INET6*/
+#define LLC_ISO_LSAP 0xfe
+
+#define ETHERMTU 1500
+
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
static void backpatch(struct block *, struct block *);
static void merge(struct block *, struct block *);
static struct block *gen_cmp(u_int, u_int, bpf_int32);
+static struct block *gen_cmp_gt(u_int, u_int, bpf_int32);
static struct block *gen_mcmp(u_int, u_int, bpf_int32, bpf_u_int32);
static struct block *gen_bcmp(u_int, u_int, const 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_snap(bpf_u_int32, bpf_u_int32, u_int);
static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);
#ifdef INET6
static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int);
static struct block *gen_port6(int, int, int);
#endif
static int lookup_proto(const char *, int);
+static struct block *gen_protochain(int, int, int);
static struct block *gen_proto(int, int, int);
static struct slist *xfer_to_x(struct arth *);
static struct slist *xfer_to_a(struct arth *);
program->bf_insns = icode_to_fcode(root, &len);
program->bf_len = len;
+ lex_cleanup();
freechunks();
return (0);
}
return (0);
}
+/*
+ * Clean up a "struct bpf_program" by freeing all the memory allocated
+ * in it.
+ */
+void
+pcap_freecode(struct bpf_program *program)
+{
+ program->bf_len = 0;
+ if (program->bf_insns != NULL) {
+ free((char *)program->bf_insns);
+ program->bf_insns = NULL;
+ }
+}
+
/*
* 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
return b;
}
+static struct block *
+gen_cmp_gt(offset, size, v)
+ u_int offset, size;
+ bpf_int32 v;
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(BPF_LD|BPF_ABS|size);
+ s->s.k = offset;
+
+ b = new_block(JMP(BPF_JGT));
+ b->stmts = s;
+ b->s.k = v;
+
+ return b;
+}
+
static struct block *
gen_mcmp(offset, size, v, mask)
u_int offset, size;
init_linktype(type)
int type;
{
- /*
- * Map DLT_ codes that don't have the same value as the
- * equivalent PCAP_ENCAP_ codes to the corresponding PCAP_ENCAP_
- * code.
- *
- * Even though "pcap_open_live()" in "pcap-bpf.c" does a
- * similar mapping, we do that mapping here as well, to
- * handle filters constructed for savefiles.
- *
- * XXX - should we do this mapping in "savefile.c"? Doing so
- * might cause programs that read one or more capture files
- * and write another capture file with the same type as
- * the input file(s) to use PCAP_ENCAP_ values that aren't
- * supported by the libpcap on the system that wrote the original
- * capture file, so we might not want to do that.
- */
- switch (type) {
-
-#ifdef DLT_ATM_RFC1483
- case DLT_ATM_RFC1483:
- linktype = PCAP_ENCAP_ATM_RFC1483;
- break;
-#endif
-
-#ifdef DLT_RAW
- case DLT_RAW:
- linktype = PCAP_ENCAP_RAW;
- break;
-#endif
-
-#ifdef DLT_SLIP_BSDOS
- case DLT_SLIP_BSDOS:
- linktype = PCAP_ENCAP_SLIP_BSDOS;
- break;
-#endif
-
-#ifdef DLT_PPP_BSDOS
- case DLT_PPP_BSDOS:
- linktype = PCAP_ENCAP_PPP_BSDOS;
- break;
-#endif
-
-#ifdef DLT_CIP
- case DLT_CIP:
- linktype = PCAP_ENCAP_ATM_CLIP;
- break;
-#endif
+ linktype = type;
-#ifdef DLT_ATM_CLIP
- case DLT_ATM_CLIP:
- linktype = PCAP_ENCAP_ATM_CLIP;
- break;
-#endif
-
-#ifdef DLT_PPP_SERIAL
- case DLT_PPP_SERIAL:
- linktype = PCAP_ENCAP_PPP_HDLC;
- break;
-#endif
-
- default:
- linktype = type;
- break;
- }
-
- switch (linktype) {
+ switch (type) {
- case PCAP_ENCAP_ETHERNET:
+ case DLT_EN10MB:
off_linktype = 12;
off_nl = 14;
return;
- case PCAP_ENCAP_SLIP:
+ case DLT_SLIP:
/*
* SLIP doesn't have a link level type. The 16 byte
* header is hacked into our SLIP driver.
off_nl = 16;
return;
- case PCAP_ENCAP_SLIP_BSDOS:
- /* XXX this may be the same as the PCAP_ENCAP_PPP_BSDOS case */
+ case DLT_SLIP_BSDOS:
+ /* XXX this may be the same as the DLT_PPP_BSDOS case */
off_linktype = -1;
/* XXX end */
off_nl = 24;
return;
- case PCAP_ENCAP_NULL:
+ case DLT_NULL:
off_linktype = 0;
off_nl = 4;
return;
- case PCAP_ENCAP_PPP:
- case PCAP_ENCAP_C_HDLC:
- case PCAP_ENCAP_PPP_HDLC:
+ case DLT_PPP:
+ case DLT_C_HDLC:
+ case DLT_PPP_SERIAL:
off_linktype = 2;
off_nl = 4;
return;
- case PCAP_ENCAP_PPP_BSDOS:
+ case DLT_PPP_BSDOS:
off_linktype = 5;
off_nl = 24;
return;
- case PCAP_ENCAP_FDDI:
+ case DLT_FDDI:
/*
* FDDI doesn't really have a link-level type field.
* We assume that SSAP = SNAP is being used and pick
#endif
return;
- case PCAP_ENCAP_TOKEN_RING:
+ case DLT_IEEE802:
/*
* Token Ring doesn't really have a link-level type field.
* We assume that SSAP = SNAP is being used and pick
off_nl = 22;
return;
- case PCAP_ENCAP_ATM_RFC1483:
+ case DLT_ATM_RFC1483:
/*
* assume routed, non-ISO PDUs
* (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00)
off_nl = 8;
return;
- case PCAP_ENCAP_RAW:
+ case DLT_RAW:
off_linktype = -1;
off_nl = 0;
return;
- case PCAP_ENCAP_ATM_CLIP:
+ case DLT_ATM_CLIP: /* Linux ATM defines this */
off_linktype = 6;
off_nl = 8;
return;
switch (linktype) {
- case PCAP_ENCAP_SLIP:
+ case DLT_EN10MB:
+ /*
+ * XXX - handle other LLC-encapsulated protocols here
+ * (IPX, OSI)?
+ */
+ switch (proto) {
+
+ case LLC_ISO_LSAP:
+ /*
+ * OSI protocols always use 802.2 encapsulation.
+ */
+ b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU);
+ gen_not(b0);
+ b1 = gen_cmp(off_linktype + 2, BPF_H, (long)
+ ((LLC_ISO_LSAP << 8) | LLC_ISO_LSAP));
+ gen_and(b0, b1);
+ return b1;
+
+ case ETHERTYPE_ATALK:
+ case ETHERTYPE_AARP:
+ /*
+ * EtherTalk (AppleTalk protocols on Ethernet link
+ * layer) may use 802.2 encapsulation.
+ */
+
+ /*
+ * Check for 802.2 encapsulation (EtherTalk phase 2?);
+ * we check for an Ethernet type field less than
+ * 1500, which means it's an 802.3 length field.
+ */
+ b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU);
+ gen_not(b0);
+
+ /*
+ * 802.2-encapsulated ETHERTYPE_ATALK packets are
+ * SNAP packets with an organization code of
+ * 0x080007 (Apple, for Appletalk) and a protocol
+ * type of ETHERTYPE_ATALK (Appletalk).
+ *
+ * 802.2-encapsulated ETHERTYPE_AARP packets are
+ * SNAP packets with an organization code of
+ * 0x000000 (encapsulated Ethernet) and a protocol
+ * type of ETHERTYPE_AARP (Appletalk ARP).
+ */
+ if (proto == ETHERTYPE_ATALK)
+ b1 = gen_snap(0x080007, ETHERTYPE_ATALK, 14);
+ else /* proto == ETHERTYPE_AARP */
+ b1 = gen_snap(0x000000, ETHERTYPE_AARP, 14);
+ gen_and(b0, b1);
+
+ /*
+ * Check for Ethernet encapsulation (Ethertalk
+ * phase 1?); we just check for the Ethernet
+ * protocol type.
+ */
+ b0 = gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);
+
+ gen_or(b0, b1);
+ return b1;
+ }
+ break;
+
+ case DLT_SLIP:
return gen_false();
- case PCAP_ENCAP_PPP:
- case PCAP_ENCAP_PPP_HDLC:
- if (proto == ETHERTYPE_IP)
+ case DLT_PPP:
+ case DLT_PPP_SERIAL:
+ /*
+ * We use Ethernet protocol types inside libpcap;
+ * map them to the corresponding PPP protocol types.
+ */
+ switch (proto) {
+
+ case ETHERTYPE_IP:
proto = PPP_IP; /* XXX was 0x21 */
+ break;
+
#ifdef INET6
- else if (proto == ETHERTYPE_IPV6)
+ case ETHERTYPE_IPV6:
proto = PPP_IPV6;
+ break;
#endif
+
+ case ETHERTYPE_DN:
+ proto = PPP_DECNET;
+ break;
+
+ case ETHERTYPE_ATALK:
+ proto = PPP_APPLE;
+ break;
+
+ case ETHERTYPE_NS:
+ proto = PPP_NS;
+ break;
+ }
break;
- case PCAP_ENCAP_PPP_BSDOS:
+ case DLT_PPP_BSDOS:
+ /*
+ * We use Ethernet protocol types inside libpcap;
+ * map them to the corresponding PPP protocol types.
+ */
switch (proto) {
case ETHERTYPE_IP:
}
break;
- case PCAP_ENCAP_NULL:
+ case DLT_NULL:
/* XXX */
if (proto == ETHERTYPE_IP)
return (gen_cmp(0, BPF_W, (bpf_int32)htonl(AF_INET)));
return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);
}
+/*
+ * Check for an LLC SNAP packet with a given organization code and
+ * protocol type; we check the entire contents of the 802.2 LLC and
+ * snap headers, checking for a DSAP of 0xAA, an SSAP of 0xAA, and
+ * a control field of 0x03 in the LLC header, and for the specified
+ * organization code and protocol type in the SNAP header.
+ */
+static struct block *
+gen_snap(orgcode, ptype, offset)
+ bpf_u_int32 orgcode;
+ bpf_u_int32 ptype;
+ u_int offset;
+{
+ u_char snapblock[8];
+
+ snapblock[0] = 0xAA; /* DSAP = SNAP */
+ snapblock[1] = 0xAA; /* SSAP = SNAP */
+ snapblock[2] = 0x03; /* control = UI */
+ snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */
+ snapblock[4] = (orgcode >> 8); /* middle 8 bits of organization code */
+ snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */
+ snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */
+ snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */
+ return gen_bcmp(offset, 8, snapblock);
+}
+
static struct block *
gen_hostop(addr, mask, dir, proto, src_off, dst_off)
bpf_u_int32 addr;
}
/*
- * Like gen_ehostop, but for PCAP_ENCAP_FDDI
+ * Like gen_ehostop, but for DLT_FDDI
*/
static struct block *
gen_fhostop(eaddr, dir)
}
/*
- * Like gen_ehostop, but for PCAP_ENCAP_TOKEN_RING
+ * Like gen_ehostop, but for DLT_IEEE802 (Token Ring)
*/
static struct block *
gen_thostop(eaddr, dir)
gen_or(b0, b1);
return b1;
+ case Q_ISO:
+ bpf_error("ISO host filtering not implemented");
+
default:
abort();
}
case Q_ATALK:
bpf_error("ATALK host filtering not implemented");
+ case Q_AARP:
+ bpf_error("AARP host filtering not implemented");
+
case Q_DECNET:
return gen_dnhostop(addr, dir, off_nl);
case Q_ATALK:
bpf_error("ATALK host filtering not implemented");
+ case Q_AARP:
+ bpf_error("AARP host filtering not implemented");
+
case Q_DECNET:
bpf_error("'decnet' modifier applied to ip6 host");
case Q_IP:
case Q_ARP:
case Q_RARP:
- if (linktype == PCAP_ENCAP_ETHERNET)
+ if (linktype == DLT_EN10MB)
b0 = gen_ehostop(eaddr, Q_OR);
- else if (linktype == PCAP_ENCAP_FDDI)
+ else if (linktype == DLT_FDDI)
b0 = gen_fhostop(eaddr, Q_OR);
- else if (linktype == PCAP_ENCAP_TOKEN_RING)
+ else if (linktype == DLT_IEEE802)
b0 = gen_thostop(eaddr, Q_OR);
else
bpf_error(
b1 = gen_linktype(ETHERTYPE_ATALK);
break;
+ case Q_AARP:
+ b1 = gen_linktype(ETHERTYPE_AARP);
+ break;
+
case Q_DECNET:
b1 = gen_linktype(ETHERTYPE_DN);
break;
#endif
break;
+ case Q_ISO:
+ b1 = gen_linktype(LLC_ISO_LSAP);
+ break;
+
+ case Q_ESIS:
+ b1 = gen_proto(ISO9542_ESIS, Q_ISO, Q_DEFAULT);
+ break;
+
+ case Q_ISIS:
+ b1 = gen_proto(ISO10589_ISIS, Q_ISO, Q_DEFAULT);
+ break;
+
default:
abort();
}
}
#endif
-struct block *
+static struct block *
gen_protochain(v, proto, dir)
int v;
int proto;
gen_and(b0, b1);
return b1;
+ case Q_ISO:
+ b0 = gen_linktype(LLC_ISO_LSAP);
+ b1 = gen_cmp(off_nl + 3, BPF_B, (long)v);
+ gen_and(b0, b1);
+ return b1;
+
case Q_ARP:
bpf_error("arp does not encapsulate another protocol");
/* NOTREACHED */
if (proto == Q_LINK) {
switch (linktype) {
- case PCAP_ENCAP_ETHERNET:
+ case DLT_EN10MB:
eaddr = pcap_ether_hostton(name);
if (eaddr == NULL)
bpf_error(
"unknown ether host '%s'", name);
return gen_ehostop(eaddr, dir);
- case PCAP_ENCAP_FDDI:
+ case DLT_FDDI:
eaddr = pcap_ether_hostton(name);
if (eaddr == NULL)
bpf_error(
"unknown FDDI host '%s'", name);
return gen_fhostop(eaddr, dir);
- case PCAP_ENCAP_TOKEN_RING:
+ case DLT_IEEE802:
eaddr = pcap_ether_hostton(name);
if (eaddr == NULL)
bpf_error(
struct qual q;
{
if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
- if (linktype == PCAP_ENCAP_ETHERNET)
+ if (linktype == DLT_EN10MB)
return gen_ehostop(eaddr, (int)q.dir);
- if (linktype == PCAP_ENCAP_FDDI)
+ if (linktype == DLT_FDDI)
return gen_fhostop(eaddr, (int)q.dir);
- if (linktype == PCAP_ENCAP_TOKEN_RING)
+ if (linktype == DLT_IEEE802)
return gen_thostop(eaddr, (int)q.dir);
}
bpf_error("ethernet address used in non-ether expression");
return gen_len(BPF_JGE, n);
}
+/*
+ * Actually, this is less than or equal.
+ */
struct block *
gen_less(n)
int n;
case Q_DEFAULT:
case Q_LINK:
- if (linktype == PCAP_ENCAP_ETHERNET)
+ if (linktype == DLT_EN10MB)
return gen_ehostop(ebroadcast, Q_DST);
- if (linktype == PCAP_ENCAP_FDDI)
+ if (linktype == DLT_FDDI)
return gen_fhostop(ebroadcast, Q_DST);
- if (linktype == PCAP_ENCAP_TOKEN_RING)
+ if (linktype == DLT_IEEE802)
return gen_thostop(ebroadcast, Q_DST);
bpf_error("not a broadcast link");
break;
case Q_DEFAULT:
case Q_LINK:
- if (linktype == PCAP_ENCAP_ETHERNET) {
+ if (linktype == DLT_EN10MB) {
/* ether[0] & 1 != 0 */
s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
s->s.k = 0;
return b0;
}
- if (linktype == PCAP_ENCAP_FDDI) {
+ 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);
}
/* TODO - check how token ring handles multicast */
- /* if (linktype == PCAP_ENCAP_TOKEN_RING) ... */
+ /* if (linktype == DLT_IEEE802) ... */
/* Link not known to support multicasts */
break;
dir);
return (b0);
}
+
+/*
+ * support IEEE 802.1Q VLAN trunk over ethernet
+ */
+struct block *
+gen_vlan(vlan_num)
+ int vlan_num;
+{
+ static u_int orig_linktype = -1, orig_nl = -1;
+ struct block *b0;
+
+ /*
+ * Change the offsets to point to the type and data fields within
+ * the VLAN packet. This is somewhat of a kludge.
+ */
+ if (orig_nl == (u_int)-1) {
+ orig_linktype = off_linktype; /* save original values */
+ orig_nl = off_nl;
+
+ switch (linktype) {
+
+ case DLT_EN10MB:
+ off_linktype = 16;
+ off_nl = 18;
+ break;
+
+ default:
+ bpf_error("no VLAN support for data link type %d",
+ linktype);
+ /*NOTREACHED*/
+ }
+ }
+
+ /* check for VLAN */
+ b0 = gen_cmp(orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q);
+
+ /* If a specific VLAN is requested, check VLAN id */
+ if (vlan_num >= 0) {
+ struct block *b1;
+
+ b1 = gen_cmp(orig_nl, BPF_H, (bpf_int32)vlan_num);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ return (b0);
+}