* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
-static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.186 2003-02-14 07:48:25 guy Exp $ (LBL)";
+static const char rcsid[] _U_ =
+ "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.209 2004-08-27 07:37:10 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
#include "ppp.h"
#include "sll.h"
#include "arcnet.h"
+#include "pf.h"
+#ifndef offsetof
+#define offsetof(s, e) ((size_t)&((s *)0)->e)
+#endif
#ifdef INET6
#ifndef WIN32
#include <netdb.h> /* for "struct addrinfo" */
static jmp_buf top_ctx;
static pcap_t *bpf_pcap;
-/* Hack for updating VLAN offsets. */
-static u_int orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
+/* Hack for updating VLAN, MPLS offsets. */
+static u_int orig_linktype = -1U, orig_nl = -1U, orig_nl_nosnap = -1U;
/* XXX */
#ifdef PCAP_FDDIPAD
u_int n;
{
struct chunk *cp;
- int k, size;
+ int k;
+ size_t size;
#ifndef __NetBSD__
/* XXX Round up to nearest long. */
bpf_error("out of memory");
size = CHUNK0SIZE << k;
cp->m = (void *)malloc(size);
+ if (cp->m == NULL)
+ bpf_error("out of memory");
memset((char *)cp->m, 0, size);
cp->n_left = size;
if (n > size)
off_nl_nosnap = 4; /* no 802.2 LLC */
return;
+ case DLT_ENC:
+ off_linktype = 0;
+ off_nl = 12;
+ off_nl_nosnap = 12; /* no 802.2 LLC */
+ return;
+
case DLT_PPP:
+ case DLT_PPP_WITHDIRECTION:
case DLT_C_HDLC: /* BSD/OS Cisco HDLC */
case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */
off_linktype = 2;
*
* XXX - the header is actually variable-length. We
* assume a 24-byte link-layer header, as appears in
- * data frames in networks with no bridges.
+ * data frames in networks with no bridges. If the
+ * fromds and tods 802.11 header bits are both set,
+ * it's actually supposed to be 30 bytes.
*/
off_linktype = 24;
off_nl = 32; /* 802.11+802.2+SNAP */
off_nl_nosnap = 144+27; /* Prism+802.11+802.2 */
return;
- case DLT_IEEE802_11_RADIO:
+ case DLT_IEEE802_11_RADIO_AVS:
/*
* Same as 802.11, but with an additional header before
* the 802.11 header, containing a bunch of additional
* information including radio-level information.
*
- * The header is 64 bytes long.
+ * The header is 64 bytes long, at least in its
+ * current incarnation.
*
* XXX - same variable-length header problem, only
* more so; this header is also variable-length,
off_nl_nosnap = 64+27; /* Radio+802.11+802.2 */
return;
+ case DLT_IEEE802_11_RADIO:
+ /*
+ * Same as 802.11, but with an additional header before
+ * the 802.11 header, containing a bunch of additional
+ * information including radio-level information.
+ *
+ * XXX - same variable-length header problem, only
+ * even *more* so; this header is also variable-length,
+ * with the length being the 16-bit number at an offset
+ * of 2 from the beginning of the radio header, and it's
+ * device-dependent (different devices might supply
+ * different amounts of information), so we can't even
+ * assume a fixed length for the current version of the
+ * header.
+ *
+ * Therefore, currently, only raw "link[N:M]" filtering is
+ * supported.
+ */
+ off_linktype = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
case DLT_ATM_RFC1483:
case DLT_ATM_CLIP: /* Linux ATM defines this */
/*
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
return;
+
+ case DLT_APPLE_IP_OVER_IEEE1394:
+ off_linktype = 16;
+ off_nl = 18;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
+ return;
+
+ case DLT_LINUX_IRDA:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_DOCSIS:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_SYMANTEC_FIREWALL:
+ off_linktype = 6;
+ off_nl = 44; /* Ethernet II */
+ off_nl_nosnap = 44; /* XXX - what does it do with 802.3 packets? */
+ return;
+
+ case DLT_PFLOG:
+ off_linktype = 0;
+ /* XXX read from header? */
+ off_nl = PFLOG_HDRLEN;
+ off_nl_nosnap = PFLOG_HDRLEN;
+ return;
+
+#ifdef DLT_PFSYNC
+ case DLT_PFSYNC:
+ off_linktype = -1;
+ off_nl = 4;
+ off_nl_nosnap = 4;
+ return;
+#endif
}
bpf_error("unknown data link type %d", linktype);
/* NOTREACHED */
case DLT_EN10MB:
return gen_ether_linktype(proto);
+ /*NOTREACHED*/
break;
case DLT_C_HDLC:
default:
return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);
+ /*NOTREACHED*/
break;
}
break;
case DLT_ATM_CLIP:
case DLT_IP_OVER_FC:
return gen_llc(proto);
+ /*NOTREACHED*/
break;
case DLT_SUNATM:
(bpf_int32)proto);
}
}
+ /*NOTREACHED*/
break;
case DLT_SLIP:
default:
return gen_false(); /* always false */
}
+ /*NOTREACHED*/
break;
case DLT_PPP:
+ case DLT_PPP_WITHDIRECTION:
case DLT_PPP_SERIAL:
case DLT_PPP_ETHER:
/*
case DLT_NULL:
case DLT_LOOP:
+ case DLT_ENC:
/*
* For DLT_NULL, the link-layer header is a 32-bit
- * word containing an AF_ value in *host* byte order.
+ * word containing an AF_ value in *host* byte order,
+ * and for DLT_ENC, the link-layer header begins
+ * with a 32-bit work containing an AF_ value in
+ * host byte order.
*
* In addition, if we're reading a saved capture file,
* the host byte order in the capture may not be the
return gen_false();
}
- if (linktype == DLT_NULL) {
+ if (linktype == DLT_NULL || linktype == DLT_ENC) {
/*
* The AF_ value is in host byte order, but
* the BPF interpreter will convert it to
}
return (gen_cmp(0, BPF_W, (bpf_int32)proto));
+ case DLT_PFLOG:
+ /*
+ * af field is host byte order in contrast to the rest of
+ * the packet.
+ */
+ if (proto == ETHERTYPE_IP)
+ return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B,
+ (bpf_int32)AF_INET));
+#ifdef INET6
+ else if (proto == ETHERTYPE_IPV6)
+ return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B,
+ (bpf_int32)AF_INET6));
+#endif /* INET6 */
+ else
+ return gen_false();
+ /*NOTREACHED*/
+ break;
+
case DLT_ARCNET:
case DLT_ARCNET_LINUX:
/*
return (gen_cmp(off_linktype, BPF_B,
(bpf_int32)ARCTYPE_ATALK));
}
+ /*NOTREACHED*/
break;
case DLT_LTALK:
default:
return gen_false();
}
+ /*NOTREACHED*/
break;
case DLT_FRELAY:
default:
return gen_false();
}
+ /*NOTREACHED*/
break;
+
+ case DLT_LINUX_IRDA:
+ bpf_error("IrDA link-layer type filtering not implemented");
+
+ case DLT_DOCSIS:
+ bpf_error("DOCSIS link-layer type filtering not implemented");
}
/*
*
* Therefore, if "off_linktype" is -1, there's an error.
*/
- if (off_linktype == -1)
+ if (off_linktype == (u_int)-1)
abort();
/*
case Q_DEFAULT:
b0 = gen_host(addr, mask, Q_IP, dir);
- if (off_linktype != -1) {
+ if (off_linktype != (u_int)-1) {
b1 = gen_host(addr, mask, Q_ARP, dir);
gen_or(b0, b1);
b0 = gen_host(addr, mask, Q_RARP, dir);
break;
case Q_ISIS_CSNP:
- b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
- b1 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+ b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
gen_or(b0, b1);
break;
* XXX - what about SNAP-encapsulated frames?
*/
return gen_cmp(2, BPF_H, (0x03<<8) | v);
+ /*NOTREACHED*/
break;
case DLT_C_HDLC:
if (alist == NULL || *alist == NULL)
bpf_error("unknown host '%s'", name);
tproto = proto;
- if (off_linktype == -1 && tproto == Q_DEFAULT)
+ if (off_linktype == (u_int)-1 && tproto == Q_DEFAULT)
tproto = Q_IP;
b = gen_host(**alist++, 0xffffffff, tproto, dir);
while (*alist) {
bpf_error("Mask syntax for networks only");
/* NOTREACHED */
}
+ /* NOTREACHED */
}
struct block *
return gen_thostop(ebroadcast, Q_DST);
if (linktype == DLT_IEEE802_11)
return gen_wlanhostop(ebroadcast, Q_DST);
+ if (linktype == DLT_IP_OVER_FC)
+ return gen_ipfchostop(ebroadcast, Q_DST);
if (linktype == DLT_SUNATM && is_lane) {
/*
* Check that the packet doesn't begin with an
gen_and(b0, b2);
return b2;
}
- bpf_error("only ether/ip broadcast filters supported");
+ bpf_error("only link-layer/IP broadcast filters supported");
+ /* NOTREACHED */
}
/*
return b0;
}
+ if (linktype == DLT_IP_OVER_FC) {
+ b0 = gen_mac_multicast(2);
+ return b0;
+ }
+
if (linktype == DLT_SUNATM && is_lane) {
/*
* Check that the packet doesn't begin with an
return b1;
#endif /* INET6 */
}
- bpf_error("only IP multicast filters supported on ethernet/FDDI");
+ bpf_error("link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel");
+ /* NOTREACHED */
}
/*
}
break;
+ case DLT_PFLOG:
+ b0 = gen_cmp(offsetof(struct pfloghdr, dir), BPF_B,
+ (bpf_int32)((dir == 0) ? PF_IN : PF_OUT));
+ break;
+
+ case DLT_PPP_WITHDIRECTION:
+ if (dir) {
+ /* match outgoing packets */
+ b0 = gen_cmp(0, BPF_B, PPP_WITHDIRECTION_OUT);
+ } else {
+ /* match incoming packets */
+ b0 = gen_cmp(0, BPF_B, PPP_WITHDIRECTION_IN);
+ }
+ break;
+
default:
- bpf_error("inbound/outbound not supported on linktype %d\n",
+ bpf_error("inbound/outbound not supported on linktype %d",
linktype);
b0 = NULL;
/* NOTREACHED */
return (b0);
}
+/* PF firewall log matched interface */
+struct block *
+gen_pf_ifname(const char *ifname)
+{
+ struct block *b0;
+ u_int len, off;
+
+ if (linktype == DLT_PFLOG) {
+ len = sizeof(((struct pfloghdr *)0)->ifname);
+ off = offsetof(struct pfloghdr, ifname);
+ } else {
+ bpf_error("ifname not supported on linktype 0x%x", linktype);
+ /* NOTREACHED */
+ }
+ if (strlen(ifname) >= len) {
+ bpf_error("ifname interface names can only be %d characters",
+ len-1);
+ /* NOTREACHED */
+ }
+ b0 = gen_bcmp(off, strlen(ifname), (const u_char *)ifname);
+ return (b0);
+}
+
+/* PF firewall log matched interface */
+struct block *
+gen_pf_ruleset(char *ruleset)
+{
+ struct block *b0;
+
+ if (linktype != DLT_PFLOG) {
+ bpf_error("ruleset not supported on linktype 0x%x", linktype);
+ /* NOTREACHED */
+ }
+ if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) {
+ bpf_error("ruleset names can only be %ld characters",
+ (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1));
+ /* NOTREACHED */
+ }
+ b0 = gen_bcmp(offsetof(struct pfloghdr, ruleset),
+ strlen(ruleset), (const u_char *)ruleset);
+ return (b0);
+}
+
+/* PF firewall log rule number */
+struct block *
+gen_pf_rnr(int rnr)
+{
+ struct block *b0;
+
+ if (linktype == DLT_PFLOG) {
+ b0 = gen_cmp(offsetof(struct pfloghdr, rulenr), BPF_W,
+ (bpf_int32)rnr);
+ } else {
+ bpf_error("rnr not supported on linktype 0x%x", linktype);
+ /* NOTREACHED */
+ }
+
+ return (b0);
+}
+
+/* PF firewall log sub-rule number */
+struct block *
+gen_pf_srnr(int srnr)
+{
+ struct block *b0;
+
+ if (linktype != DLT_PFLOG) {
+ bpf_error("srnr not supported on linktype 0x%x", linktype);
+ /* NOTREACHED */
+ }
+
+ b0 = gen_cmp(offsetof(struct pfloghdr, subrulenr), BPF_W,
+ (bpf_int32)srnr);
+ return (b0);
+}
+
+/* PF firewall log reason code */
+struct block *
+gen_pf_reason(int reason)
+{
+ struct block *b0;
+
+ if (linktype == DLT_PFLOG) {
+ b0 = gen_cmp(offsetof(struct pfloghdr, reason), BPF_B,
+ (bpf_int32)reason);
+ } else {
+ bpf_error("reason not supported on linktype 0x%x", linktype);
+ /* NOTREACHED */
+ }
+
+ return (b0);
+}
+
+/* PF firewall log action */
+struct block *
+gen_pf_action(int action)
+{
+ struct block *b0;
+
+ if (linktype == DLT_PFLOG) {
+ b0 = gen_cmp(offsetof(struct pfloghdr, action), BPF_B,
+ (bpf_int32)action);
+ } else {
+ bpf_error("action not supported on linktype 0x%x", linktype);
+ /* NOTREACHED */
+ }
+
+ return (b0);
+}
+
struct block *
gen_acode(eaddr, q)
register const u_char *eaddr;
if (vlan_num >= 0) {
struct block *b1;
- b1 = gen_cmp(orig_nl, BPF_H, (bpf_int32)vlan_num);
+ b1 = gen_mcmp(orig_nl, BPF_H, (bpf_int32)vlan_num, 0x0fff);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ return (b0);
+}
+
+/*
+ * support for MPLS
+ */
+struct block *
+gen_mpls(label_num)
+ int label_num;
+{
+ struct block *b0;
+
+ /*
+ * Change the offsets to point to the type and data fields within
+ * the MPLS packet. This is somewhat of a kludge.
+ */
+ if (orig_nl == (u_int)-1) {
+ orig_linktype = off_linktype; /* save original values */
+ orig_nl = off_nl;
+ orig_nl_nosnap = off_nl_nosnap;
+
+ switch (linktype) {
+
+ case DLT_EN10MB:
+ off_linktype = 16;
+ off_nl_nosnap = 18;
+ off_nl = 18;
+
+ b0 = gen_cmp(orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_MPLS);
+ break;
+
+ case DLT_PPP:
+ off_linktype = 6;
+ off_nl_nosnap = 8;
+ off_nl = 8;
+
+ b0 = gen_cmp(orig_linktype, BPF_H, (bpf_int32)PPP_MPLS_UCAST);
+ break;
+
+ case DLT_C_HDLC:
+ off_linktype = 6;
+ off_nl_nosnap = 8;
+ off_nl = 8;
+
+ b0 = gen_cmp(orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_MPLS);
+ break;
+
+ /* FIXME add other DLT_s ...
+ * for Frame-Relay/and ATM this may get messy due to SNAP headers
+ * leave it for now */
+
+ default:
+ bpf_error("no MPLS support for data link type %d",
+ linktype);
+ /*NOTREACHED*/
+ }
+ } else {
+ bpf_error("'mpls' can't be combined with 'vlan' or another 'mpls'");
+ /*NOTREACHED*/
+ }
+
+ /* If a specific MPLS label is requested, check it */
+ if (label_num >= 0) {
+ struct block *b1;
+
+ label_num = label_num << 12; /* label is shifted 12 bits on the wire */
+ b1 = gen_mcmp(orig_nl, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */
gen_and(b0, b1);
b0 = b1;
}
case A_VPI:
if (!is_atm)
bpf_error("'vpi' supported only on raw ATM");
- if (off_vpi == -1)
+ if (off_vpi == (u_int)-1)
abort();
b0 = gen_ncmp(BPF_B, off_vpi, 0xffffffff, (u_int)jtype,
(u_int)jvalue, reverse);
case A_VCI:
if (!is_atm)
bpf_error("'vci' supported only on raw ATM");
- if (off_vci == -1)
+ if (off_vci == (u_int)-1)
abort();
b0 = gen_ncmp(BPF_H, off_vci, 0xffffffff, (u_int)jtype,
(u_int)jvalue, reverse);
break;
case A_PROTOTYPE:
- if (off_proto == -1)
+ if (off_proto == (u_int)-1)
abort(); /* XXX - this isn't on FreeBSD */
b0 = gen_ncmp(BPF_B, off_proto, 0x0f, (u_int)jtype,
(u_int)jvalue, reverse);
break;
case A_MSGTYPE:
- if (off_payload == -1)
+ if (off_payload == (u_int)-1)
abort();
b0 = gen_ncmp(BPF_B, off_payload + MSG_TYPE_POS, 0xffffffff,
(u_int)jtype, (u_int)jvalue, reverse);
case A_CALLREFTYPE:
if (!is_atm)
bpf_error("'callref' supported only on raw ATM");
- if (off_proto == -1)
+ if (off_proto == (u_int)-1)
abort();
b0 = gen_ncmp(BPF_B, off_proto, 0xffffffff, (u_int)jtype,
(u_int)jvalue, reverse);