summaryrefslogtreecommitdiff
path: root/gencode.c
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@FreeBSD.org>2009-03-21 20:43:56 +0000
committerRui Paulo <rpaulo@FreeBSD.org>2009-03-21 20:43:56 +0000
commitc6a6c5e28b1033c61a7bb7e108fa0592b22cc016 (patch)
tree1c663fff98874ff52b3f01d448e178f668ba0307 /gencode.c
parent3430dc7c1fc255ec21a9b5e9c189ec01d930c6bd (diff)
Notes
Diffstat (limited to 'gencode.c')
-rw-r--r--gencode.c2411
1 files changed, 1687 insertions, 724 deletions
diff --git a/gencode.c b/gencode.c
index d2cae2101c1c7..41057ba8cb12a 100644
--- a/gencode.c
+++ b/gencode.c
@@ -21,7 +21,7 @@
*/
#ifndef lint
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.53 2007/09/12 19:17:24 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.16 2008-09-22 20:16:01 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -68,10 +68,11 @@ static const char rcsid[] _U_ =
#include "nlpid.h"
#include "llc.h"
#include "gencode.h"
+#include "ieee80211.h"
#include "atmuni31.h"
#include "sunatmpos.h"
#include "ppp.h"
-#include "sll.h"
+#include "pcap/sll.h"
#include "arcnet.h"
#ifdef HAVE_NET_PFVAR_H
#include <sys/socket.h>
@@ -87,7 +88,7 @@ static const char rcsid[] _U_ =
#include <netdb.h> /* for "struct addrinfo" */
#endif /* WIN32 */
#endif /*INET6*/
-#include <pcap-namedb.h>
+#include <pcap/namedb.h>
#define ETHERMTU 1500
@@ -105,8 +106,8 @@ static const char rcsid[] _U_ =
static jmp_buf top_ctx;
static pcap_t *bpf_pcap;
-#ifdef WIN32
/* Hack for updating VLAN, MPLS, and PPPoE offsets. */
+#ifdef WIN32
static u_int orig_linktype = (u_int)-1, orig_nl = (u_int)-1, label_stack_depth = (u_int)-1;
#else
static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;
@@ -134,6 +135,7 @@ bpf_error(const char *fmt, ...)
static void init_linktype(pcap_t *);
+static void init_regs(void);
static int alloc_reg(void);
static void free_reg(int);
@@ -145,7 +147,8 @@ static struct block *root;
*/
enum e_offrel {
OR_PACKET, /* relative to the beginning of the packet */
- OR_LINK, /* relative to the link-layer header */
+ OR_LINK, /* relative to the beginning of the link-layer header */
+ OR_MACPL, /* relative to the end of the MAC-layer header */
OR_NET, /* relative to the network-layer header */
OR_NET_NOSNAP, /* relative to the network-layer header, with no SNAP header at the link layer */
OR_TRAN_IPV4, /* relative to the transport-layer header, with IPv4 network layer */
@@ -190,6 +193,7 @@ static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *);
static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32,
bpf_u_int32, bpf_u_int32, int, bpf_int32);
static struct slist *gen_load_llrel(u_int, u_int);
+static struct slist *gen_load_macplrel(u_int, u_int);
static struct slist *gen_load_a(enum e_offrel, u_int, u_int);
static struct slist *gen_loadx_iphdrlen(void);
static struct block *gen_uncond(int);
@@ -197,12 +201,16 @@ static inline struct block *gen_true(void);
static inline struct block *gen_false(void);
static struct block *gen_ether_linktype(int);
static struct block *gen_linux_sll_linktype(int);
-static void insert_radiotap_load_llprefixlen(struct block *);
-static void insert_ppi_load_llprefixlen(struct block *);
-static void insert_load_llprefixlen(struct block *);
+static struct slist *gen_load_prism_llprefixlen(void);
+static struct slist *gen_load_avs_llprefixlen(void);
+static struct slist *gen_load_radiotap_llprefixlen(void);
+static struct slist *gen_load_ppi_llprefixlen(void);
+static void insert_compute_vloffsets(struct block *);
static struct slist *gen_llprefixlen(void);
+static struct slist *gen_off_macpl(void);
+static int ethertype_to_ppptype(int);
static struct block *gen_linktype(int);
-static struct block *gen_snap(bpf_u_int32, bpf_u_int32, u_int);
+static struct block *gen_snap(bpf_u_int32, bpf_u_int32);
static struct block *gen_llc_linktype(int);
static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);
#ifdef INET6
@@ -247,6 +255,7 @@ static struct slist *xfer_to_x(struct arth *);
static struct slist *xfer_to_a(struct arth *);
static struct block *gen_mac_multicast(int);
static struct block *gen_len(int, int);
+static struct block *gen_check_802_11_data_frame(void);
static struct block *gen_ppi_dlt_check(void);
static struct block *gen_msg_abbrev(int type);
@@ -369,6 +378,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
n_errors = 0;
root = NULL;
bpf_pcap = p;
+ init_regs();
if (setjmp(top_ctx)) {
lex_cleanup();
freechunks();
@@ -484,24 +494,11 @@ merge(b0, b1)
*p = b1;
}
-
void
finish_parse(p)
struct block *p;
{
struct block *ppi_dlt_check;
-
- ppi_dlt_check = gen_ppi_dlt_check();
-
- if (ppi_dlt_check != NULL)
- {
- gen_and(ppi_dlt_check, p);
- }
-
- backpatch(p, gen_retblk(snaplen));
- p->sense = !p->sense;
- backpatch(p, gen_retblk(0));
- root = p->head;
/*
* Insert before the statements of the first (root) block any
@@ -512,14 +509,30 @@ finish_parse(p)
* statements of all blocks that use those lengths and that
* have no predecessors that use them, so that we only compute
* the lengths if we need them. There might be even better
- * approaches than that. However, as we're currently only
- * handling variable-length radiotap headers, and as all
- * filtering expressions other than raw link[M:N] tests
- * require the length of that header, doing more for that
- * header length isn't really worth the effort.
+ * approaches than that.
+ *
+ * However, those strategies would be more complicated, and
+ * as we don't generate code to compute a length if the
+ * program has no tests that use the length, and as most
+ * tests will probably use those lengths, we would just
+ * postpone computing the lengths so that it's not done
+ * for tests that fail early, and it's not clear that's
+ * worth the effort.
*/
+ insert_compute_vloffsets(p->head);
+
+ /*
+ * For DLT_PPI captures, generate a check of the per-packet
+ * DLT value to make sure it's DLT_IEEE802_11.
+ */
+ ppi_dlt_check = gen_ppi_dlt_check();
+ if (ppi_dlt_check != NULL)
+ gen_and(ppi_dlt_check, p);
- insert_load_llprefixlen(root);
+ backpatch(p, gen_retblk(snaplen));
+ p->sense = !p->sense;
+ backpatch(p, gen_retblk(0));
+ root = p->head;
}
void
@@ -682,13 +695,7 @@ gen_ncmp(offrel, offset, size, mask, jtype, reverse, v)
* Various code constructs need to know the layout of the data link
* layer. These variables give the necessary offsets from the beginning
* of the packet data.
- *
- * If the link layer has variable_length headers, the offsets are offsets
- * from the end of the link-link-layer header, and "reg_ll_size" is
- * the register number for a register containing the length of the
- * link-layer header. Otherwise, "reg_ll_size" is -1.
*/
-static int reg_ll_size;
/*
* This is the offset of the beginning of the link-layer header from
@@ -701,13 +708,49 @@ static int reg_ll_size;
static u_int off_ll;
/*
- * This is the offset of the beginning of the MAC-layer header.
+ * If there's a variable-length header preceding the link-layer header,
+ * "reg_off_ll" is the register number for a register containing the
+ * length of that header, and therefore the offset of the link-layer
+ * header from the beginning of the raw packet data. Otherwise,
+ * "reg_off_ll" is -1.
+ */
+static int reg_off_ll;
+
+/*
+ * This is the offset of the beginning of the MAC-layer header from
+ * the beginning of the link-layer header.
* It's usually 0, except for ATM LANE, where it's the offset, relative
* to the beginning of the raw packet data, of the Ethernet header.
*/
static u_int off_mac;
/*
+ * This is the offset of the beginning of the MAC-layer payload,
+ * from the beginning of the raw packet data.
+ *
+ * I.e., it's the sum of the length of the link-layer header (without,
+ * for example, any 802.2 LLC header, so it's the MAC-layer
+ * portion of that header), plus any prefix preceding the
+ * link-layer header.
+ */
+static u_int off_macpl;
+
+/*
+ * This is 1 if the offset of the beginning of the MAC-layer payload
+ * from the beginning of the link-layer header is variable-length.
+ */
+static int off_macpl_is_variable;
+
+/*
+ * If the link layer has variable_length headers, "reg_off_macpl"
+ * is the register number for a register containing the length of the
+ * link-layer header plus the length of any variable-length header
+ * preceding the link-layer header. Otherwise, "reg_off_macpl"
+ * is -1.
+ */
+static int reg_off_macpl;
+
+/*
* "off_linktype" is the offset to information in the link-layer header
* giving the packet type. This offset is relative to the beginning
* of the link-layer header (i.e., it doesn't include off_ll).
@@ -730,6 +773,13 @@ static u_int off_mac;
static u_int off_linktype;
/*
+ * TRUE if "pppoes" appeared in the filter; it causes link-layer type
+ * checks to check the PPP header, assumed to follow a LAN-style link-
+ * layer header and a PPPoE session header.
+ */
+static int is_pppoes = 0;
+
+/*
* TRUE if the link layer includes an ATM pseudo-header.
*/
static int is_atm = 0;
@@ -768,8 +818,8 @@ static u_int off_payload;
/*
* These are offsets to the beginning of the network-layer header.
- * They are relative to the beginning of the link-layer header (i.e.,
- * they don't include off_ll).
+ * They are relative to the beginning of the MAC-layer payload (i.e.,
+ * they don't include off_ll or off_macpl).
*
* If the link layer never uses 802.2 LLC:
*
@@ -816,6 +866,11 @@ init_linktype(p)
off_payload = -1;
/*
+ * And that we're not doing PPPoE.
+ */
+ is_pppoes = 0;
+
+ /*
* And assume we're not doing SS7.
*/
off_li = -1;
@@ -825,34 +880,40 @@ init_linktype(p)
off_sls = -1;
/*
- * Also assume it's not 802.11 with a fixed-length radio header.
+ * Also assume it's not 802.11.
*/
off_ll = 0;
+ off_macpl = 0;
+ off_macpl_is_variable = 0;
orig_linktype = -1;
orig_nl = -1;
label_stack_depth = 0;
- reg_ll_size = -1;
+ reg_off_ll = -1;
+ reg_off_macpl = -1;
switch (linktype) {
case DLT_ARCNET:
off_linktype = 2;
- off_nl = 6; /* XXX in reality, variable! */
- off_nl_nosnap = 6; /* no 802.2 LLC */
+ off_macpl = 6;
+ off_nl = 0; /* XXX in reality, variable! */
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_ARCNET_LINUX:
off_linktype = 4;
- off_nl = 8; /* XXX in reality, variable! */
- off_nl_nosnap = 8; /* no 802.2 LLC */
+ off_macpl = 8;
+ off_nl = 0; /* XXX in reality, variable! */
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_EN10MB:
off_linktype = 12;
- off_nl = 14; /* Ethernet II */
- off_nl_nosnap = 17; /* 802.3+802.2 */
+ off_macpl = 14; /* Ethernet header length */
+ off_nl = 0; /* Ethernet II */
+ off_nl_nosnap = 3; /* 802.3+802.2 */
return;
case DLT_SLIP:
@@ -861,29 +922,33 @@ init_linktype(p)
* header is hacked into our SLIP driver.
*/
off_linktype = -1;
- off_nl = 16;
- off_nl_nosnap = 16; /* no 802.2 LLC */
+ off_macpl = 16;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_SLIP_BSDOS:
/* XXX this may be the same as the DLT_PPP_BSDOS case */
off_linktype = -1;
/* XXX end */
- off_nl = 24;
- off_nl_nosnap = 24; /* no 802.2 LLC */
+ off_macpl = 24;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_NULL:
case DLT_LOOP:
off_linktype = 0;
- off_nl = 4;
- off_nl_nosnap = 4; /* no 802.2 LLC */
+ off_macpl = 4;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_ENC:
off_linktype = 0;
- off_nl = 12;
- off_nl_nosnap = 12; /* no 802.2 LLC */
+ off_macpl = 12;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_PPP:
@@ -891,8 +956,9 @@ init_linktype(p)
case DLT_C_HDLC: /* BSD/OS Cisco HDLC */
case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */
off_linktype = 2;
- off_nl = 4;
- off_nl_nosnap = 4; /* no 802.2 LLC */
+ off_macpl = 4;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_PPP_ETHER:
@@ -901,14 +967,16 @@ init_linktype(p)
* only covers session state.
*/
off_linktype = 6;
- off_nl = 8;
- off_nl_nosnap = 8; /* no 802.2 LLC */
+ off_macpl = 8;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_PPP_BSDOS:
off_linktype = 5;
- off_nl = 24;
- off_nl_nosnap = 24; /* no 802.2 LLC */
+ off_macpl = 24;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_FDDI:
@@ -924,12 +992,12 @@ init_linktype(p)
#ifdef PCAP_FDDIPAD
off_linktype += pcap_fddipad;
#endif
- off_nl = 21; /* FDDI+802.2+SNAP */
- off_nl_nosnap = 16; /* FDDI+802.2 */
+ off_macpl = 13; /* FDDI MAC header length */
#ifdef PCAP_FDDIPAD
- off_nl += pcap_fddipad;
- off_nl_nosnap += pcap_fddipad;
+ off_macpl += pcap_fddipad;
#endif
+ off_nl = 8; /* 802.2+SNAP */
+ off_nl_nosnap = 3; /* 802.2 */
return;
case DLT_IEEE802:
@@ -957,11 +1025,15 @@ init_linktype(p)
* 8 - figure out which byte that is).
*/
off_linktype = 14;
- off_nl = 22; /* Token Ring+802.2+SNAP */
- off_nl_nosnap = 17; /* Token Ring+802.2 */
+ off_macpl = 14; /* Token Ring MAC header length */
+ off_nl = 8; /* 802.2+SNAP */
+ off_nl_nosnap = 3; /* 802.2 */
return;
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
/*
* 802.11 doesn't really have a link-level type field.
* We set "off_linktype" to the offset of the LLC header.
@@ -970,90 +1042,37 @@ init_linktype(p)
* is being used and pick out the encapsulated Ethernet type.
* XXX - should we generate code to check for SNAP?
*
- * 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. If the
- * fromds and tods 802.11 header bits are both set,
- * it's actually supposed to be 30 bytes.
+ * We also handle variable-length radio headers here.
+ * The Prism header is in theory variable-length, but in
+ * practice it's always 144 bytes long. However, some
+ * drivers on Linux use ARPHRD_IEEE80211_PRISM, but
+ * sometimes or always supply an AVS header, so we
+ * have to check whether the radio header is a Prism
+ * header or an AVS header, so, in practice, it's
+ * variable-length.
*/
off_linktype = 24;
- off_nl = 32; /* 802.11+802.2+SNAP */
- off_nl_nosnap = 27; /* 802.11+802.2 */
- return;
-
- case DLT_PRISM_HEADER:
- /*
- * 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 144 bytes long.
- *
- * XXX - same variable-length header problem; at least
- * the Prism header is fixed-length.
- */
- off_ll = 144;
- off_linktype = 24;
- off_nl = 32; /* Prism+802.11+802.2+SNAP */
- off_nl_nosnap = 27; /* Prism+802.11+802.2 */
- return;
-
- 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, at least in its
- * current incarnation.
- *
- * XXX - same variable-length header problem, only
- * more so; this header is also variable-length,
- * with the length being the 32-bit big-endian
- * number at an offset of 4 from the beginning
- * of the radio header. We should handle that the
- * same way we handle the length at the beginning
- * of the radiotap header.
- *
- * XXX - in Linux, do any drivers that supply an AVS
- * header supply a link-layer type other than
- * ARPHRD_IEEE80211_PRISM? If so, we should map that
- * to DLT_IEEE802_11_RADIO_AVS; if not, or if there are
- * any drivers that supply an AVS header but supply
- * an ARPHRD value of ARPHRD_IEEE80211_PRISM, we'll
- * have to check the header in the generated code to
- * determine whether it's Prism or AVS.
- */
- off_ll = 64;
- off_linktype = 24;
- off_nl = 32; /* Radio+802.11+802.2+SNAP */
- off_nl_nosnap = 27; /* Radio+802.11+802.2 */
+ off_macpl = 0; /* link-layer header is variable-length */
+ off_macpl_is_variable = 1;
+ off_nl = 8; /* 802.2+SNAP */
+ off_nl_nosnap = 3; /* 802.2 */
return;
-
- /*
- * At the moment we treat PPI as normal Radiotap encoded
- * packets. The difference is in the function that generates
- * the code at the beginning to compute the header length.
- * Since this code generator of PPI supports bare 802.11
- * encapsulation only (i.e. the encapsulated DLT should be
- * DLT_IEEE802_11) we generate code to check for this too.
- */
case DLT_PPI:
- 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.
- *
- * The radiotap header is variable length, and we
- * generate code to compute its length and store it
- * in a register. These offsets are relative to the
- * beginning of the 802.11 header.
+ /*
+ * At the moment we treat PPI the same way that we treat
+ * normal Radiotap encoded packets. The difference is in
+ * the function that generates the code at the beginning
+ * to compute the header length. Since this code generator
+ * of PPI supports bare 802.11 encapsulation only (i.e.
+ * the encapsulated DLT should be DLT_IEEE802_11) we
+ * generate code to check for this too.
*/
off_linktype = 24;
- off_nl = 32; /* 802.11+802.2+SNAP */
- off_nl_nosnap = 27; /* 802.11+802.2 */
+ off_macpl = 0; /* link-layer header is variable-length */
+ off_macpl_is_variable = 1;
+ off_nl = 8; /* 802.2+SNAP */
+ off_nl_nosnap = 3; /* 802.2 */
return;
case DLT_ATM_RFC1483:
@@ -1070,6 +1089,7 @@ init_linktype(p)
* PPPo{A,E} and a PPP protocol of IP and....
*/
off_linktype = 0;
+ off_macpl = 0; /* packet begins with LLC header */
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
return;
@@ -1083,23 +1103,26 @@ init_linktype(p)
off_vpi = SUNATM_VPI_POS;
off_vci = SUNATM_VCI_POS;
off_proto = PROTO_POS;
- off_mac = -1; /* LLC-encapsulated, so no MAC-layer header */
+ off_mac = -1; /* assume LLC-encapsulated, so no MAC-layer header */
off_payload = SUNATM_PKT_BEGIN_POS;
off_linktype = off_payload;
- off_nl = off_payload+8; /* 802.2+SNAP */
- off_nl_nosnap = off_payload+3; /* 802.2 */
+ off_macpl = off_payload; /* if LLC-encapsulated */
+ off_nl = 8; /* 802.2+SNAP */
+ off_nl_nosnap = 3; /* 802.2 */
return;
case DLT_RAW:
off_linktype = -1;
+ off_macpl = 0;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_LINUX_SLL: /* fake header for Linux cooked socket */
off_linktype = 14;
- off_nl = 16;
- off_nl_nosnap = 16; /* no 802.2 LLC */
+ off_macpl = 16;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_LTALK:
@@ -1109,6 +1132,7 @@ init_linktype(p)
* "long" DDP packet following.
*/
off_linktype = -1;
+ off_macpl = 0;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
return;
@@ -1125,8 +1149,9 @@ init_linktype(p)
* 2625 says SNAP should be used.
*/
off_linktype = 16;
- off_nl = 24; /* IPFC+802.2+SNAP */
- off_nl_nosnap = 19; /* IPFC+802.2 */
+ off_macpl = 16;
+ off_nl = 8; /* 802.2+SNAP */
+ off_nl_nosnap = 3; /* 802.2 */
return;
case DLT_FRELAY:
@@ -1135,6 +1160,7 @@ init_linktype(p)
* frames (NLPID of 0x80).
*/
off_linktype = -1;
+ off_macpl = 0;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
return;
@@ -1146,14 +1172,16 @@ init_linktype(p)
*/
case DLT_MFR:
off_linktype = -1;
+ off_macpl = 0;
off_nl = 4;
off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */
return;
case DLT_APPLE_IP_OVER_IEEE1394:
off_linktype = 16;
- off_nl = 18;
- off_nl_nosnap = 18; /* no 802.2 LLC */
+ off_macpl = 18;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
case DLT_LINUX_IRDA:
@@ -1161,6 +1189,7 @@ init_linktype(p)
* Currently, only raw "link[N:M]" filtering is supported.
*/
off_linktype = -1;
+ off_macpl = -1;
off_nl = -1;
off_nl_nosnap = -1;
return;
@@ -1170,21 +1199,24 @@ init_linktype(p)
* Currently, only raw "link[N:M]" filtering is supported.
*/
off_linktype = -1;
+ off_macpl = -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? */
+ off_macpl = 44;
+ off_nl = 0; /* Ethernet II */
+ off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */
return;
#ifdef HAVE_NET_PFVAR_H
case DLT_PFLOG:
off_linktype = 0;
- off_nl = PFLOG_HDRLEN;
- off_nl_nosnap = PFLOG_HDRLEN; /* no 802.2 LLC */
+ off_macpl = PFLOG_HDRLEN;
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return;
#endif
@@ -1195,26 +1227,30 @@ init_linktype(p)
case DLT_JUNIPER_CHDLC:
case DLT_JUNIPER_FRELAY:
off_linktype = 4;
- off_nl = 4;
+ off_macpl = 4;
+ off_nl = 0;
off_nl_nosnap = -1; /* no 802.2 LLC */
return;
case DLT_JUNIPER_ATM1:
- off_linktype = 4; /* in reality variable between 4-8 */
- off_nl = 4;
- off_nl_nosnap = 14;
+ off_linktype = 4; /* in reality variable between 4-8 */
+ off_macpl = 4; /* in reality variable between 4-8 */
+ off_nl = 0;
+ off_nl_nosnap = 10;
return;
case DLT_JUNIPER_ATM2:
- off_linktype = 8; /* in reality variable between 8-12 */
- off_nl = 8;
- off_nl_nosnap = 18;
+ off_linktype = 8; /* in reality variable between 8-12 */
+ off_macpl = 8; /* in reality variable between 8-12 */
+ off_nl = 0;
+ off_nl_nosnap = 10;
return;
/* frames captured on a Juniper PPPoE service PIC
* contain raw ethernet frames */
case DLT_JUNIPER_PPPOE:
case DLT_JUNIPER_ETHER:
+ off_macpl = 14;
off_linktype = 16;
off_nl = 18; /* Ethernet II */
off_nl_nosnap = 21; /* 802.3+802.2 */
@@ -1222,36 +1258,56 @@ init_linktype(p)
case DLT_JUNIPER_PPPOE_ATM:
off_linktype = 4;
- off_nl = 6;
- off_nl_nosnap = -1; /* no 802.2 LLC */
+ off_macpl = 6;
+ off_nl = 0;
+ off_nl_nosnap = -1; /* no 802.2 LLC */
return;
case DLT_JUNIPER_GGSN:
off_linktype = 6;
- off_nl = 12;
- off_nl_nosnap = -1; /* no 802.2 LLC */
+ off_macpl = 12;
+ off_nl = 0;
+ off_nl_nosnap = -1; /* no 802.2 LLC */
return;
case DLT_JUNIPER_ES:
off_linktype = 6;
- off_nl = -1; /* not really a network layer but raw IP adresses */
+ off_macpl = -1; /* not really a network layer but raw IP addresses */
+ off_nl = -1; /* not really a network layer but raw IP addresses */
off_nl_nosnap = -1; /* no 802.2 LLC */
return;
case DLT_JUNIPER_MONITOR:
off_linktype = 12;
- off_nl = 12; /* raw IP/IP6 header */
+ off_macpl = 12;
+ off_nl = 0; /* raw IP/IP6 header */
off_nl_nosnap = -1; /* no 802.2 LLC */
return;
case DLT_JUNIPER_SERVICES:
off_linktype = 12;
+ off_macpl = -1; /* L3 proto location dep. on cookie type */
off_nl = -1; /* L3 proto location dep. on cookie type */
off_nl_nosnap = -1; /* no 802.2 LLC */
return;
case DLT_JUNIPER_VP:
off_linktype = 18;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_JUNIPER_ST:
+ off_linktype = 18;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_JUNIPER_ISM:
+ off_linktype = 8;
+ off_macpl = -1;
off_nl = -1;
off_nl_nosnap = -1;
return;
@@ -1263,6 +1319,7 @@ init_linktype(p)
off_dpc = 4;
off_sls = 7;
off_linktype = -1;
+ off_macpl = -1;
off_nl = -1;
off_nl_nosnap = -1;
return;
@@ -1274,6 +1331,19 @@ init_linktype(p)
off_dpc = 8;
off_sls = 11;
off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_ERF:
+ off_li = 22;
+ off_sio = 23;
+ off_opc = 24;
+ off_dpc = 24;
+ off_sls = 27;
+ off_linktype = -1;
+ off_macpl = -1;
off_nl = -1;
off_nl_nosnap = -1;
return;
@@ -1281,8 +1351,9 @@ init_linktype(p)
#ifdef DLT_PFSYNC
case DLT_PFSYNC:
off_linktype = -1;
- off_nl = 4;
- off_nl_nosnap = 4;
+ off_macpl = 4;
+ off_nl = 0;
+ off_nl_nosnap = 0;
return;
#endif
@@ -1291,6 +1362,7 @@ init_linktype(p)
* Currently, only raw "link[N:M]" filtering is supported.
*/
off_linktype = -1;
+ off_macpl = -1;
off_nl = -1;
off_nl_nosnap = -1;
return;
@@ -1300,6 +1372,7 @@ init_linktype(p)
* Currently, only raw "link[N:M]" filtering is supported.
*/
off_linktype = -1;
+ off_macpl = -1;
off_nl = -1;
off_nl_nosnap = -1;
return;
@@ -1309,6 +1382,118 @@ init_linktype(p)
* Currently, only raw "link[N:M]" filtering is supported.
*/
off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_USB_LINUX:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_CAN20B:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_IEEE802_15_4_LINUX:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_IEEE802_16_MAC_CPS_RADIO:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_IEEE802_15_4:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_SITA:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_RAIF1:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_IPMB:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_BLUETOOTH_HCI_H4_WITH_PHDR:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_AX25_KISS:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1; /* variable, min 15, max 71 steps of 7 */
+ off_macpl = -1;
+ off_nl = -1; /* variable, min 16, max 71 steps of 7 */
+ off_nl_nosnap = -1; /* no 802.2 LLC */
+ off_mac = 1; /* step over the kiss length byte */
+ return;
+
+ case DLT_IEEE802_15_4_NONASK_PHY:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
off_nl = -1;
off_nl_nosnap = -1;
return;
@@ -1362,6 +1547,45 @@ gen_load_llrel(offset, size)
return s;
}
+/*
+ * Load a value relative to the beginning of the MAC-layer payload.
+ */
+static struct slist *
+gen_load_macplrel(offset, size)
+ u_int offset, size;
+{
+ struct slist *s, *s2;
+
+ s = gen_off_macpl();
+
+ /*
+ * If s is non-null, the offset of the MAC-layer payload is
+ * variable, and s points to a list of instructions that
+ * arrange that the X register contains that offset.
+ *
+ * Otherwise, the offset of the MAC-layer payload is constant,
+ * and is in off_macpl.
+ */
+ if (s != NULL) {
+ /*
+ * The offset of the MAC-layer payload is in the X
+ * register. Do an indirect load, to use the X register
+ * as an offset.
+ */
+ s2 = new_stmt(BPF_LD|BPF_IND|size);
+ s2->s.k = offset;
+ sappend(s, s2);
+ } else {
+ /*
+ * The offset of the MAC-layer payload is constant,
+ * and is in off_macpl; load the value at that offset
+ * plus the specified offset.
+ */
+ s = new_stmt(BPF_LD|BPF_ABS|size);
+ s->s.k = off_macpl + offset;
+ }
+ return s;
+}
/*
* Load a value relative to the beginning of the specified header.
@@ -1384,12 +1608,16 @@ gen_load_a(offrel, offset, size)
s = gen_load_llrel(offset, size);
break;
+ case OR_MACPL:
+ s = gen_load_macplrel(offset, size);
+ break;
+
case OR_NET:
- s = gen_load_llrel(off_nl + offset, size);
+ s = gen_load_macplrel(off_nl + offset, size);
break;
case OR_NET_NOSNAP:
- s = gen_load_llrel(off_nl_nosnap + offset, size);
+ s = gen_load_macplrel(off_nl_nosnap + offset, size);
break;
case OR_TRAN_IPV4:
@@ -1402,21 +1630,22 @@ gen_load_a(offrel, offset, size)
s = gen_loadx_iphdrlen();
/*
- * Load the item at {offset of the link-layer header} +
- * {offset, relative to the start of the link-layer
- * header, of the IPv4 header} + {length of the IPv4 header} +
+ * Load the item at {offset of the MAC-layer payload} +
+ * {offset, relative to the start of the MAC-layer
+ * paylod, of the IPv4 header} + {length of the IPv4 header} +
* {specified offset}.
*
- * (If the link-layer is variable-length, it's included
- * in the value in the X register, and off_ll is 0.)
+ * (If the offset of the MAC-layer payload is variable,
+ * it's included in the value in the X register, and
+ * off_macpl is 0.)
*/
s2 = new_stmt(BPF_LD|BPF_IND|size);
- s2->s.k = off_ll + off_nl + offset;
+ s2->s.k = off_macpl + off_nl + offset;
sappend(s, s2);
break;
case OR_TRAN_IPV6:
- s = gen_load_llrel(off_nl + 40 + offset, size);
+ s = gen_load_macplrel(off_nl + 40 + offset, size);
break;
default:
@@ -1436,12 +1665,15 @@ gen_loadx_iphdrlen()
{
struct slist *s, *s2;
- s = gen_llprefixlen();
+ s = gen_off_macpl();
if (s != NULL) {
/*
* There's a variable-length prefix preceding the
- * link-layer header. "s" points to a list of statements
- * that put the length of that prefix into the X register.
+ * link-layer header, or the link-layer header is itself
+ * variable-length. "s" points to a list of statements
+ * that put the offset of the MAC-layer payload into
+ * the X register.
+ *
* The 4*([k]&0xf) addressing mode can't be used, as we
* don't have a constant offset, so we have to load the
* value in question into the A register and add to it
@@ -1459,22 +1691,24 @@ gen_loadx_iphdrlen()
/*
* The A register now contains the length of the
- * IP header. We need to add to it the length
- * of the prefix preceding the link-layer
- * header, which is still in the X register, and
- * move the result into the X register.
+ * IP header. We need to add to it the offset of
+ * the MAC-layer payload, which is still in the X
+ * register, and move the result into the X register.
*/
sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
sappend(s, new_stmt(BPF_MISC|BPF_TAX));
} else {
/*
* There is no variable-length header preceding the
- * link-layer header; add in off_ll, which, if there's
- * a fixed-length header preceding the link-layer header,
- * is the length of that header.
+ * link-layer header, and the link-layer header is
+ * fixed-length; load the length of the IPv4 header,
+ * which is at an offset of off_nl from the beginning
+ * of the MAC-layer payload, and thus at an offset
+ * of off_mac_pl + off_nl from the beginning of the
+ * raw packet data.
*/
s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
- s->s.k = off_ll + off_nl;
+ s->s.k = off_macpl + off_nl;
}
return s;
}
@@ -1548,7 +1782,7 @@ gen_ether_linktype(proto)
*/
b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
gen_not(b0);
- b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32)
+ b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)
((proto << 8) | proto));
gen_and(b0, b1);
return b1;
@@ -1586,17 +1820,15 @@ gen_ether_linktype(proto)
* This generates code to check both for the
* IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
*/
- b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
- (bpf_int32)LLCSAP_IPX);
- b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H,
- (bpf_int32)0xFFFF);
+ b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
+ b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)0xFFFF);
gen_or(b0, b1);
/*
* Now we add code to check for SNAP frames with
* ETHERTYPE_IPX, i.e. Ethernet_SNAP.
*/
- b0 = gen_snap(0x000000, ETHERTYPE_IPX, 14);
+ b0 = gen_snap(0x000000, ETHERTYPE_IPX);
gen_or(b0, b1);
/*
@@ -1651,9 +1883,9 @@ gen_ether_linktype(proto)
* type of ETHERTYPE_AARP (Appletalk ARP).
*/
if (proto == ETHERTYPE_ATALK)
- b1 = gen_snap(0x080007, ETHERTYPE_ATALK, 14);
+ b1 = gen_snap(0x080007, ETHERTYPE_ATALK);
else /* proto == ETHERTYPE_AARP */
- b1 = gen_snap(0x000000, ETHERTYPE_AARP, 14);
+ b1 = gen_snap(0x000000, ETHERTYPE_AARP);
gen_and(b0, b1);
/*
@@ -1730,7 +1962,7 @@ gen_linux_sll_linktype(proto)
* (i.e., other SAP values)?
*/
b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);
- b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32)
+ b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)
((proto << 8) | proto));
gen_and(b0, b1);
return b1;
@@ -1761,10 +1993,8 @@ gen_linux_sll_linktype(proto)
* then put a check for LINUX_SLL_P_802_2 frames
* before it.
*/
- b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
- (bpf_int32)LLCSAP_IPX);
- b1 = gen_snap(0x000000, ETHERTYPE_IPX,
- off_linktype + 2);
+ b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
+ b1 = gen_snap(0x000000, ETHERTYPE_IPX);
gen_or(b0, b1);
b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);
gen_and(b0, b1);
@@ -1812,11 +2042,9 @@ gen_linux_sll_linktype(proto)
* type of ETHERTYPE_AARP (Appletalk ARP).
*/
if (proto == ETHERTYPE_ATALK)
- b1 = gen_snap(0x080007, ETHERTYPE_ATALK,
- off_linktype + 2);
+ b1 = gen_snap(0x080007, ETHERTYPE_ATALK);
else /* proto == ETHERTYPE_AARP */
- b1 = gen_snap(0x000000, ETHERTYPE_AARP,
- off_linktype + 2);
+ b1 = gen_snap(0x000000, ETHERTYPE_AARP);
gen_and(b0, b1);
/*
@@ -1840,7 +2068,7 @@ gen_linux_sll_linktype(proto)
*/
b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
LINUX_SLL_P_802_2);
- b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
+ b1 = gen_cmp(OR_LINK, off_macpl, BPF_B,
(bpf_int32)proto);
gen_and(b0, b1);
return b1;
@@ -1860,18 +2088,169 @@ gen_linux_sll_linktype(proto)
}
}
-static void
-insert_radiotap_load_llprefixlen(b)
- struct block *b;
+static struct slist *
+gen_load_prism_llprefixlen()
{
struct slist *s1, *s2;
+ struct slist *sjeq_avs_cookie;
+ struct slist *sjcommon;
+
+ /*
+ * This code is not compatible with the optimizer, as
+ * we are generating jmp instructions within a normal
+ * slist of instructions
+ */
+ no_optimize = 1;
/*
- * Prepend to the statements in this block code to load the
- * length of the radiotap header into the register assigned
- * to hold that length, if one has been assigned.
+ * Generate code to load the length of the radio header into
+ * the register assigned to hold that length, if one has been
+ * assigned. (If one hasn't been assigned, no code we've
+ * generated uses that prefix, so we don't need to generate any
+ * code to load it.)
+ *
+ * Some Linux drivers use ARPHRD_IEEE80211_PRISM but sometimes
+ * or always use the AVS header rather than the Prism header.
+ * We load a 4-byte big-endian value at the beginning of the
+ * raw packet data, and see whether, when masked with 0xFFFFF000,
+ * it's equal to 0x80211000. If so, that indicates that it's
+ * an AVS header (the masked-out bits are the version number).
+ * Otherwise, it's a Prism header.
+ *
+ * XXX - the Prism header is also, in theory, variable-length,
+ * but no known software generates headers that aren't 144
+ * bytes long.
*/
- if (reg_ll_size != -1) {
+ if (reg_off_ll != -1) {
+ /*
+ * Load the cookie.
+ */
+ s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+ s1->s.k = 0;
+
+ /*
+ * AND it with 0xFFFFF000.
+ */
+ s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+ s2->s.k = 0xFFFFF000;
+ sappend(s1, s2);
+
+ /*
+ * Compare with 0x80211000.
+ */
+ sjeq_avs_cookie = new_stmt(JMP(BPF_JEQ));
+ sjeq_avs_cookie->s.k = 0x80211000;
+ sappend(s1, sjeq_avs_cookie);
+
+ /*
+ * If it's AVS:
+ *
+ * The 4 bytes at an offset of 4 from the beginning of
+ * the AVS header are the length of the AVS header.
+ * That field is big-endian.
+ */
+ s2 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+ s2->s.k = 4;
+ sappend(s1, s2);
+ sjeq_avs_cookie->s.jt = s2;
+
+ /*
+ * Now jump to the code to allocate a register
+ * into which to save the header length and
+ * store the length there. (The "jump always"
+ * instruction needs to have the k field set;
+ * it's added to the PC, so, as we're jumping
+ * over a single instruction, it should be 1.)
+ */
+ sjcommon = new_stmt(JMP(BPF_JA));
+ sjcommon->s.k = 1;
+ sappend(s1, sjcommon);
+
+ /*
+ * Now for the code that handles the Prism header.
+ * Just load the length of the Prism header (144)
+ * into the A register. Have the test for an AVS
+ * header branch here if we don't have an AVS header.
+ */
+ s2 = new_stmt(BPF_LD|BPF_W|BPF_IMM);
+ s2->s.k = 144;
+ sappend(s1, s2);
+ sjeq_avs_cookie->s.jf = s2;
+
+ /*
+ * Now allocate a register to hold that value and store
+ * it. The code for the AVS header will jump here after
+ * loading the length of the AVS header.
+ */
+ s2 = new_stmt(BPF_ST);
+ s2->s.k = reg_off_ll;
+ sappend(s1, s2);
+ sjcommon->s.jf = s2;
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
+static struct slist *
+gen_load_avs_llprefixlen()
+{
+ struct slist *s1, *s2;
+
+ /*
+ * Generate code to load the length of the AVS header into
+ * the register assigned to hold that length, if one has been
+ * assigned. (If one hasn't been assigned, no code we've
+ * generated uses that prefix, so we don't need to generate any
+ * code to load it.)
+ */
+ if (reg_off_ll != -1) {
+ /*
+ * The 4 bytes at an offset of 4 from the beginning of
+ * the AVS header are the length of the AVS header.
+ * That field is big-endian.
+ */
+ s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+ s1->s.k = 4;
+
+ /*
+ * Now allocate a register to hold that value and store
+ * it.
+ */
+ s2 = new_stmt(BPF_ST);
+ s2->s.k = reg_off_ll;
+ sappend(s1, s2);
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
+static struct slist *
+gen_load_radiotap_llprefixlen()
+{
+ struct slist *s1, *s2;
+
+ /*
+ * Generate code to load the length of the radiotap header into
+ * the register assigned to hold that length, if one has been
+ * assigned. (If one hasn't been assigned, no code we've
+ * generated uses that prefix, so we don't need to generate any
+ * code to load it.)
+ */
+ if (reg_off_ll != -1) {
/*
* The 2 bytes at offsets of 2 and 3 from the beginning
* of the radiotap header are the length of the radiotap
@@ -1906,7 +2285,7 @@ insert_radiotap_load_llprefixlen(b)
* it.
*/
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_ll_size;
+ s2->s.k = reg_off_ll;
sappend(s1, s2);
/*
@@ -1915,13 +2294,9 @@ insert_radiotap_load_llprefixlen(b)
s2 = new_stmt(BPF_MISC|BPF_TAX);
sappend(s1, s2);
- /*
- * Now append all the existing statements in this
- * block to these statements.
- */
- sappend(s1, b->stmts);
- b->stmts = s1;
- }
+ return (s1);
+ } else
+ return (NULL);
}
/*
@@ -1930,21 +2305,21 @@ insert_radiotap_load_llprefixlen(b)
* the code at the beginning to compute the header length.
* Since this code generator of PPI supports bare 802.11
* encapsulation only (i.e. the encapsulated DLT should be
- * DLT_IEEE802_11) we generate code to check for this too.
+ * DLT_IEEE802_11) we generate code to check for this too;
+ * that's done in finish_parse().
*/
-static void
-insert_ppi_load_llprefixlen(b)
- struct block *b;
+static struct slist *
+gen_load_ppi_llprefixlen()
{
struct slist *s1, *s2;
/*
- * Prepend to the statements in this block code to load the
- * length of the radiotap header into the register assigned
- * to hold that length, if one has been assigned.
+ * Generate code to load the length of the radiotap header
+ * into the register assigned to hold that length, if one has
+ * been assigned.
*/
- if (reg_ll_size != -1) {
- /*
+ if (reg_off_ll != -1) {
+ /*
* The 2 bytes at offsets of 2 and 3 from the beginning
* of the radiotap header are the length of the radiotap
* header; unfortunately, it's little-endian, so we have
@@ -1978,7 +2353,7 @@ insert_ppi_load_llprefixlen(b)
* it.
*/
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_ll_size;
+ s2->s.k = reg_off_ll;
sappend(s1, s2);
/*
@@ -1987,16 +2362,295 @@ insert_ppi_load_llprefixlen(b)
s2 = new_stmt(BPF_MISC|BPF_TAX);
sappend(s1, s2);
+ return (s1);
+ } else
+ return (NULL);
+}
+
+/*
+ * Load a value relative to the beginning of the link-layer header after the 802.11
+ * header, i.e. LLC_SNAP.
+ * The link-layer header doesn't necessarily begin at the beginning
+ * of the packet data; there might be a variable-length prefix containing
+ * radio information.
+ */
+static struct slist *
+gen_load_802_11_header_len(struct slist *s, struct slist *snext)
+{
+ struct slist *s2;
+ struct slist *sjset_data_frame_1;
+ struct slist *sjset_data_frame_2;
+ struct slist *sjset_qos;
+ struct slist *sjset_radiotap_flags;
+ struct slist *sjset_radiotap_tsft;
+ struct slist *sjset_tsft_datapad, *sjset_notsft_datapad;
+ struct slist *s_roundup;
+
+ if (reg_off_macpl == -1) {
/*
- * Now append all the existing statements in this
- * block to these statements.
+ * No register has been assigned to the offset of
+ * the MAC-layer payload, which means nobody needs
+ * it; don't bother computing it - just return
+ * what we already have.
*/
- sappend(s1, b->stmts);
- b->stmts = s1;
+ return (s);
+ }
+ /*
+ * This code is not compatible with the optimizer, as
+ * we are generating jmp instructions within a normal
+ * slist of instructions
+ */
+ no_optimize = 1;
+
+ /*
+ * If "s" is non-null, it has code to arrange that the X register
+ * contains the length of the prefix preceding the link-layer
+ * header.
+ *
+ * Otherwise, the length of the prefix preceding the link-layer
+ * header is "off_ll".
+ */
+ if (s == NULL) {
+ /*
+ * There is no variable-length header preceding the
+ * link-layer header.
+ *
+ * Load the length of the fixed-length prefix preceding
+ * the link-layer header (if any) into the X register,
+ * and store it in the reg_off_macpl register.
+ * That length is off_ll.
+ */
+ s = new_stmt(BPF_LDX|BPF_IMM);
+ s->s.k = off_ll;
}
+
+ /*
+ * The X register contains the offset of the beginning of the
+ * link-layer header; add 24, which is the minimum length
+ * of the MAC header for a data frame, to that, and store it
+ * in reg_off_macpl, and then load the Frame Control field,
+ * which is at the offset in the X register, with an indexed load.
+ */
+ s2 = new_stmt(BPF_MISC|BPF_TXA);
+ sappend(s, s2);
+ s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
+ s2->s.k = 24;
+ sappend(s, s2);
+ s2 = new_stmt(BPF_ST);
+ s2->s.k = reg_off_macpl;
+ sappend(s, s2);
+
+ s2 = new_stmt(BPF_LD|BPF_IND|BPF_B);
+ s2->s.k = 0;
+ sappend(s, s2);
+
+ /*
+ * Check the Frame Control field to see if this is a data frame;
+ * a data frame has the 0x08 bit (b3) in that field set and the
+ * 0x04 bit (b2) clear.
+ */
+ sjset_data_frame_1 = new_stmt(JMP(BPF_JSET));
+ sjset_data_frame_1->s.k = 0x08;
+ sappend(s, sjset_data_frame_1);
+
+ /*
+ * If b3 is set, test b2, otherwise go to the first statement of
+ * the rest of the program.
+ */
+ sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(JMP(BPF_JSET));
+ sjset_data_frame_2->s.k = 0x04;
+ sappend(s, sjset_data_frame_2);
+ sjset_data_frame_1->s.jf = snext;
+
+ /*
+ * If b2 is not set, this is a data frame; test the QoS bit.
+ * Otherwise, go to the first statement of the rest of the
+ * program.
+ */
+ sjset_data_frame_2->s.jt = snext;
+ sjset_data_frame_2->s.jf = sjset_qos = new_stmt(JMP(BPF_JSET));
+ sjset_qos->s.k = 0x80; /* QoS bit */
+ sappend(s, sjset_qos);
+
+ /*
+ * If it's set, add 2 to reg_off_macpl, to skip the QoS
+ * field.
+ * Otherwise, go to the first statement of the rest of the
+ * program.
+ */
+ sjset_qos->s.jt = s2 = new_stmt(BPF_LD|BPF_MEM);
+ s2->s.k = reg_off_macpl;
+ sappend(s, s2);
+ s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM);
+ s2->s.k = 2;
+ sappend(s, s2);
+ s2 = new_stmt(BPF_ST);
+ s2->s.k = reg_off_macpl;
+ sappend(s, s2);
+
+ /*
+ * If we have a radiotap header, look at it to see whether
+ * there's Atheros padding between the MAC-layer header
+ * and the payload.
+ *
+ * Note: all of the fields in the radiotap header are
+ * little-endian, so we byte-swap all of the values
+ * we test against, as they will be loaded as big-endian
+ * values.
+ */
+ if (linktype == DLT_IEEE802_11_RADIO) {
+ /*
+ * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set
+ * in the presence flag?
+ */
+ sjset_qos->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_W);
+ s2->s.k = 4;
+ sappend(s, s2);
+
+ sjset_radiotap_flags = new_stmt(JMP(BPF_JSET));
+ sjset_radiotap_flags->s.k = SWAPLONG(0x00000002);
+ sappend(s, sjset_radiotap_flags);
+
+ /*
+ * If not, skip all of this.
+ */
+ sjset_radiotap_flags->s.jf = snext;
+
+ /*
+ * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set?
+ */
+ sjset_radiotap_tsft = sjset_radiotap_flags->s.jt =
+ new_stmt(JMP(BPF_JSET));
+ sjset_radiotap_tsft->s.k = SWAPLONG(0x00000001);
+ sappend(s, sjset_radiotap_tsft);
+
+ /*
+ * If IEEE80211_RADIOTAP_TSFT is set, the flags field is
+ * at an offset of 16 from the beginning of the raw packet
+ * data (8 bytes for the radiotap header and 8 bytes for
+ * the TSFT field).
+ *
+ * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+ * is set.
+ */
+ sjset_radiotap_tsft->s.jt = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B);
+ s2->s.k = 16;
+ sappend(s, s2);
+
+ sjset_tsft_datapad = new_stmt(JMP(BPF_JSET));
+ sjset_tsft_datapad->s.k = 0x20;
+ sappend(s, sjset_tsft_datapad);
+
+ /*
+ * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is
+ * at an offset of 8 from the beginning of the raw packet
+ * data (8 bytes for the radiotap header).
+ *
+ * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+ * is set.
+ */
+ sjset_radiotap_tsft->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B);
+ s2->s.k = 8;
+ sappend(s, s2);
+
+ sjset_notsft_datapad = new_stmt(JMP(BPF_JSET));
+ sjset_notsft_datapad->s.k = 0x20;
+ sappend(s, sjset_notsft_datapad);
+
+ /*
+ * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is
+ * set, round the length of the 802.11 header to
+ * a multiple of 4. Do that by adding 3 and then
+ * dividing by and multiplying by 4, which we do by
+ * ANDing with ~3.
+ */
+ s_roundup = new_stmt(BPF_LD|BPF_MEM);
+ s_roundup->s.k = reg_off_macpl;
+ sappend(s, s_roundup);
+ s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM);
+ s2->s.k = 3;
+ sappend(s, s2);
+ s2 = new_stmt(BPF_ALU|BPF_AND|BPF_IMM);
+ s2->s.k = ~3;
+ sappend(s, s2);
+ s2 = new_stmt(BPF_ST);
+ s2->s.k = reg_off_macpl;
+ sappend(s, s2);
+
+ sjset_tsft_datapad->s.jt = s_roundup;
+ sjset_tsft_datapad->s.jf = snext;
+ sjset_notsft_datapad->s.jt = s_roundup;
+ sjset_notsft_datapad->s.jf = snext;
+ } else
+ sjset_qos->s.jf = snext;
+
+ return s;
}
-
+
+static void
+insert_compute_vloffsets(b)
+ struct block *b;
+{
+ struct slist *s;
+
+ /*
+ * For link-layer types that have a variable-length header
+ * preceding the link-layer header, generate code to load
+ * the offset of the link-layer header into the register
+ * assigned to that offset, if any.
+ */
+ switch (linktype) {
+
+ case DLT_PRISM_HEADER:
+ s = gen_load_prism_llprefixlen();
+ break;
+
+ case DLT_IEEE802_11_RADIO_AVS:
+ s = gen_load_avs_llprefixlen();
+ break;
+
+ case DLT_IEEE802_11_RADIO:
+ s = gen_load_radiotap_llprefixlen();
+ break;
+
+ case DLT_PPI:
+ s = gen_load_ppi_llprefixlen();
+ break;
+
+ default:
+ s = NULL;
+ break;
+ }
+
+ /*
+ * For link-layer types that have a variable-length link-layer
+ * header, generate code to load the offset of the MAC-layer
+ * payload into the register assigned to that offset, if any.
+ */
+ switch (linktype) {
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ s = gen_load_802_11_header_len(s, b->stmts);
+ break;
+ }
+
+ /*
+ * If we have any offset-loading code, append all the
+ * existing statements in the block to those statements,
+ * and make the resulting list the list of statements
+ * for the block.
+ */
+ if (s != NULL) {
+ sappend(s, b->stmts);
+ b->stmts = s;
+ }
+}
+
static struct block *
gen_ppi_dlt_check(void)
{
@@ -2023,42 +2677,61 @@ gen_ppi_dlt_check(void)
return b;
}
-static void
-insert_load_llprefixlen(b)
- struct block *b;
+static struct slist *
+gen_prism_llprefixlen(void)
{
- switch (linktype) {
+ struct slist *s;
+
+ if (reg_off_ll == -1) {
+ /*
+ * We haven't yet assigned a register for the length
+ * of the radio header; allocate one.
+ */
+ reg_off_ll = alloc_reg();
+ }
- /*
- * At the moment we treat PPI as normal Radiotap encoded
- * packets. The difference is in the function that generates
- * the code at the beginning to compute the header length.
- * Since this code generator of PPI supports bare 802.11
- * encapsulation only (i.e. the encapsulated DLT should be
- * DLT_IEEE802_11) we generate code to check for this too.
+ /*
+ * Load the register containing the radio length
+ * into the X register.
*/
- case DLT_PPI:
- insert_ppi_load_llprefixlen(b);
- break;
+ s = new_stmt(BPF_LDX|BPF_MEM);
+ s->s.k = reg_off_ll;
+ return s;
+}
- case DLT_IEEE802_11_RADIO:
- insert_radiotap_load_llprefixlen(b);
- break;
+static struct slist *
+gen_avs_llprefixlen(void)
+{
+ struct slist *s;
+
+ if (reg_off_ll == -1) {
+ /*
+ * We haven't yet assigned a register for the length
+ * of the AVS header; allocate one.
+ */
+ reg_off_ll = alloc_reg();
}
-}
+ /*
+ * Load the register containing the AVS length
+ * into the X register.
+ */
+ s = new_stmt(BPF_LDX|BPF_MEM);
+ s->s.k = reg_off_ll;
+ return s;
+}
static struct slist *
gen_radiotap_llprefixlen(void)
{
struct slist *s;
- if (reg_ll_size == -1) {
+ if (reg_off_ll == -1) {
/*
* We haven't yet assigned a register for the length
* of the radiotap header; allocate one.
*/
- reg_ll_size = alloc_reg();
+ reg_off_ll = alloc_reg();
}
/*
@@ -2066,7 +2739,7 @@ gen_radiotap_llprefixlen(void)
* into the X register.
*/
s = new_stmt(BPF_LDX|BPF_MEM);
- s->s.k = reg_ll_size;
+ s->s.k = reg_off_ll;
return s;
}
@@ -2083,25 +2756,23 @@ gen_ppi_llprefixlen(void)
{
struct slist *s;
- if (reg_ll_size == -1) {
+ if (reg_off_ll == -1) {
/*
* We haven't yet assigned a register for the length
* of the radiotap header; allocate one.
*/
- reg_ll_size = alloc_reg();
+ reg_off_ll = alloc_reg();
}
/*
- * Load the register containing the radiotap length
+ * Load the register containing the PPI length
* into the X register.
*/
s = new_stmt(BPF_LDX|BPF_MEM);
- s->s.k = reg_ll_size;
+ s->s.k = reg_off_ll;
return s;
}
-
-
/*
* Generate code to compute the link-layer header length, if necessary,
* putting it into the X register, and to return either a pointer to a
@@ -2113,19 +2784,110 @@ gen_llprefixlen(void)
{
switch (linktype) {
- case DLT_PPI:
- return gen_ppi_llprefixlen();
+ case DLT_PRISM_HEADER:
+ return gen_prism_llprefixlen();
+
+ case DLT_IEEE802_11_RADIO_AVS:
+ return gen_avs_llprefixlen();
-
case DLT_IEEE802_11_RADIO:
return gen_radiotap_llprefixlen();
+ case DLT_PPI:
+ return gen_ppi_llprefixlen();
+
default:
return NULL;
}
}
/*
+ * Generate code to load the register containing the offset of the
+ * MAC-layer payload into the X register; if no register for that offset
+ * has been allocated, allocate it first.
+ */
+static struct slist *
+gen_off_macpl(void)
+{
+ struct slist *s;
+
+ if (off_macpl_is_variable) {
+ if (reg_off_macpl == -1) {
+ /*
+ * We haven't yet assigned a register for the offset
+ * of the MAC-layer payload; allocate one.
+ */
+ reg_off_macpl = alloc_reg();
+ }
+
+ /*
+ * Load the register containing the offset of the MAC-layer
+ * payload into the X register.
+ */
+ s = new_stmt(BPF_LDX|BPF_MEM);
+ s->s.k = reg_off_macpl;
+ return s;
+ } else {
+ /*
+ * That offset isn't variable, so we don't need to
+ * generate any code.
+ */
+ return NULL;
+ }
+}
+
+/*
+ * Map an Ethernet type to the equivalent PPP type.
+ */
+static int
+ethertype_to_ppptype(proto)
+ int proto;
+{
+ switch (proto) {
+
+ case ETHERTYPE_IP:
+ proto = PPP_IP;
+ break;
+
+#ifdef INET6
+ 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;
+
+ case LLCSAP_ISONS:
+ proto = PPP_OSI;
+ break;
+
+ case LLCSAP_8021D:
+ /*
+ * I'm assuming the "Bridging PDU"s that go
+ * over PPP are Spanning Tree Protocol
+ * Bridging PDUs.
+ */
+ proto = PPP_BRPDU;
+ break;
+
+ case LLCSAP_IPX:
+ proto = PPP_IPX;
+ break;
+ }
+ return (proto);
+}
+
+/*
* Generate code to match a particular packet type by matching the
* link-layer type field or fields in the 802.2 LLC header.
*
@@ -2143,12 +2905,12 @@ gen_linktype(proto)
switch (proto) {
case ETHERTYPE_IP:
case PPP_IP:
- /* FIXME add other L3 proto IDs */
+ /* FIXME add other L3 proto IDs */
return gen_mpls_linktype(Q_IP);
case ETHERTYPE_IPV6:
case PPP_IPV6:
- /* FIXME add other L3 proto IDs */
+ /* FIXME add other L3 proto IDs */
return gen_mpls_linktype(Q_IPV6);
default:
@@ -2157,6 +2919,25 @@ gen_linktype(proto)
}
}
+ /*
+ * Are we testing PPPoE packets?
+ */
+ if (is_pppoes) {
+ /*
+ * The PPPoE session header is part of the
+ * MAC-layer payload, so all references
+ * should be relative to the beginning of
+ * that payload.
+ */
+
+ /*
+ * We use Ethernet protocol types inside libpcap;
+ * map them to the corresponding PPP protocol types.
+ */
+ proto = ethertype_to_ppptype(proto);
+ return gen_cmp(OR_MACPL, off_linktype, BPF_H, (bpf_int32)proto);
+ }
+
switch (linktype) {
case DLT_EN10MB:
@@ -2179,13 +2960,41 @@ gen_linktype(proto)
}
break;
- case DLT_PPI:
- case DLT_FDDI:
- case DLT_IEEE802:
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
+ case DLT_PPI:
+ /*
+ * Check that we have a data frame.
+ */
+ b0 = gen_check_802_11_data_frame();
+
+ /*
+ * Now check for the specified link-layer type.
+ */
+ b1 = gen_llc_linktype(proto);
+ gen_and(b0, b1);
+ return b1;
+ /*NOTREACHED*/
+ break;
+
+ case DLT_FDDI:
+ /*
+ * XXX - check for asynchronous frames, as per RFC 1103.
+ */
+ return gen_llc_linktype(proto);
+ /*NOTREACHED*/
+ break;
+
+ case DLT_IEEE802:
+ /*
+ * XXX - check for LLC PDUs, as per IEEE 802.5.
+ */
+ return gen_llc_linktype(proto);
+ /*NOTREACHED*/
+ break;
+
case DLT_ATM_RFC1483:
case DLT_ATM_CLIP:
case DLT_IP_OVER_FC:
@@ -2270,47 +3079,9 @@ gen_linktype(proto)
* We use Ethernet protocol types inside libpcap;
* map them to the corresponding PPP protocol types.
*/
- switch (proto) {
-
- case ETHERTYPE_IP:
- proto = PPP_IP;
- break;
-
-#ifdef INET6
- 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;
-
- case LLCSAP_ISONS:
- proto = PPP_OSI;
- break;
-
- case LLCSAP_8021D:
- /*
- * I'm assuming the "Bridging PDU"s that go
- * over PPP are Spanning Tree Protocol
- * Bridging PDUs.
- */
- proto = PPP_BRPDU;
- break;
-
- case LLCSAP_IPX:
- proto = PPP_IPX;
- break;
- }
+ proto = ethertype_to_ppptype(proto);
+ return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
+ /*NOTREACHED*/
break;
case DLT_PPP_BSDOS:
@@ -2321,6 +3092,10 @@ gen_linktype(proto)
switch (proto) {
case ETHERTYPE_IP:
+ /*
+ * Also check for Van Jacobson-compressed IP.
+ * XXX - do this for other forms of PPP?
+ */
b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_IP);
b1 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_VJC);
gen_or(b0, b1);
@@ -2328,42 +3103,12 @@ gen_linktype(proto)
gen_or(b1, b0);
return b0;
-#ifdef INET6
- case ETHERTYPE_IPV6:
- proto = PPP_IPV6;
- /* more to go? */
- break;
-#endif
-
- case ETHERTYPE_DN:
- proto = PPP_DECNET;
- break;
-
- case ETHERTYPE_ATALK:
- proto = PPP_APPLE;
- break;
-
- case ETHERTYPE_NS:
- proto = PPP_NS;
- break;
-
- case LLCSAP_ISONS:
- proto = PPP_OSI;
- break;
-
- case LLCSAP_8021D:
- /*
- * I'm assuming the "Bridging PDU"s that go
- * over PPP are Spanning Tree Protocol
- * Bridging PDUs.
- */
- proto = PPP_BRPDU;
- break;
-
- case LLCSAP_IPX:
- proto = PPP_IPX;
- break;
+ default:
+ proto = ethertype_to_ppptype(proto);
+ return gen_cmp(OR_LINK, off_linktype, BPF_H,
+ (bpf_int32)proto);
}
+ /*NOTREACHED*/
break;
case DLT_NULL:
@@ -2552,6 +3297,9 @@ gen_linktype(proto)
/*NOTREACHED*/
break;
+ case DLT_MFR:
+ bpf_error("Multi-link Frame Relay link-layer type filtering not implemented");
+
case DLT_JUNIPER_MFR:
case DLT_JUNIPER_MLFR:
case DLT_JUNIPER_MLPPP:
@@ -2568,6 +3316,8 @@ gen_linktype(proto)
case DLT_JUNIPER_FRELAY:
case DLT_JUNIPER_CHDLC:
case DLT_JUNIPER_VP:
+ case DLT_JUNIPER_ST:
+ case DLT_JUNIPER_ISM:
/* just lets verify the magic number for now -
* on ATM we may have up to 6 different encapsulations on the wire
* and need a lot of heuristics to figure out that the payload
@@ -2583,8 +3333,51 @@ gen_linktype(proto)
case DLT_DOCSIS:
bpf_error("DOCSIS link-layer type filtering not implemented");
+ case DLT_MTP2:
+ case DLT_MTP2_WITH_PHDR:
+ bpf_error("MTP2 link-layer type filtering not implemented");
+
+ case DLT_ERF:
+ bpf_error("ERF link-layer type filtering not implemented");
+
+#ifdef DLT_PFSYNC
+ case DLT_PFSYNC:
+ bpf_error("PFSYNC link-layer type filtering not implemented");
+#endif
+
case DLT_LINUX_LAPD:
bpf_error("LAPD link-layer type filtering not implemented");
+
+ case DLT_USB:
+ case DLT_USB_LINUX:
+ bpf_error("USB link-layer type filtering not implemented");
+
+ case DLT_BLUETOOTH_HCI_H4:
+ case DLT_BLUETOOTH_HCI_H4_WITH_PHDR:
+ bpf_error("Bluetooth link-layer type filtering not implemented");
+
+ case DLT_CAN20B:
+ bpf_error("CAN20B link-layer type filtering not implemented");
+
+ case DLT_IEEE802_15_4:
+ case DLT_IEEE802_15_4_LINUX:
+ case DLT_IEEE802_15_4_NONASK_PHY:
+ bpf_error("IEEE 802.15.4 link-layer type filtering not implemented");
+
+ case DLT_IEEE802_16_MAC_CPS_RADIO:
+ bpf_error("IEEE 802.16 link-layer type filtering not implemented");
+
+ case DLT_SITA:
+ bpf_error("SITA link-layer type filtering not implemented");
+
+ case DLT_RAIF1:
+ bpf_error("RAIF1 link-layer type filtering not implemented");
+
+ case DLT_IPMB:
+ bpf_error("IPMB link-layer type filtering not implemented");
+
+ case DLT_AX25_KISS:
+ bpf_error("AX.25 link-layer type filtering not implemented");
}
/*
@@ -2602,12 +3395,7 @@ gen_linktype(proto)
/*
* Any type not handled above should always have an Ethernet
- * type at an offset of "off_linktype". (PPP is partially
- * handled above - the protocol type is mapped from the
- * Ethernet and LLC types we use internally to the corresponding
- * PPP type - but the PPP type is always specified by a value
- * at "off_linktype", so we don't have to do the code generation
- * above.)
+ * type at an offset of "off_linktype".
*/
return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
}
@@ -2620,10 +3408,9 @@ gen_linktype(proto)
* code and protocol type in the SNAP header.
*/
static struct block *
-gen_snap(orgcode, ptype, offset)
+gen_snap(orgcode, ptype)
bpf_u_int32 orgcode;
bpf_u_int32 ptype;
- u_int offset;
{
u_char snapblock[8];
@@ -2635,7 +3422,7 @@ gen_snap(orgcode, ptype, offset)
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(OR_LINK, offset, 8, snapblock);
+ return gen_bcmp(OR_MACPL, 0, 8, snapblock);
}
/*
@@ -2668,7 +3455,7 @@ gen_llc_linktype(proto)
* DSAP, as we do for other types <= ETHERMTU
* (i.e., other SAP values)?
*/
- return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_u_int32)
+ return gen_cmp(OR_MACPL, 0, BPF_H, (bpf_u_int32)
((proto << 8) | proto));
case LLCSAP_IPX:
@@ -2676,7 +3463,7 @@ gen_llc_linktype(proto)
* XXX - are there ever SNAP frames for IPX on
* non-Ethernet 802.x networks?
*/
- return gen_cmp(OR_LINK, off_linktype, BPF_B,
+ return gen_cmp(OR_MACPL, 0, BPF_B,
(bpf_int32)LLCSAP_IPX);
case ETHERTYPE_ATALK:
@@ -2689,7 +3476,7 @@ gen_llc_linktype(proto)
* XXX - check for an organization code of
* encapsulated Ethernet as well?
*/
- return gen_snap(0x080007, ETHERTYPE_ATALK, off_linktype);
+ return gen_snap(0x080007, ETHERTYPE_ATALK);
default:
/*
@@ -2701,8 +3488,7 @@ gen_llc_linktype(proto)
* This is an LLC SAP value, so check
* the DSAP.
*/
- return gen_cmp(OR_LINK, off_linktype, BPF_B,
- (bpf_int32)proto);
+ return gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)proto);
} else {
/*
* This is an Ethernet type; we assume that it's
@@ -2717,15 +3503,13 @@ gen_llc_linktype(proto)
* organization code of 0x000000 (encapsulated
* Ethernet), we'd do
*
- * return gen_snap(0x000000, proto,
- * off_linktype);
+ * return gen_snap(0x000000, proto);
*
* here; for now, we don't, as per the above.
* I don't know whether it's worth the extra CPU
* time to do the right check or not.
*/
- return gen_cmp(OR_LINK, off_linktype+6, BPF_H,
- (bpf_int32)proto);
+ return gen_cmp(OR_MACPL, 6, BPF_H, (bpf_int32)proto);
}
}
}
@@ -2934,7 +3718,8 @@ gen_thostop(eaddr, dir)
}
/*
- * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN)
+ * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and
+ * various 802.11 + radio headers.
*/
static struct block *
gen_wlanhostop(eaddr, dir)
@@ -2944,6 +3729,16 @@ gen_wlanhostop(eaddr, dir)
register struct block *b0, *b1, *b2;
register struct slist *s;
+#ifdef ENABLE_WLAN_FILTERING_PATCH
+ /*
+ * TODO GV 20070613
+ * We need to disable the optimizer because the optimizer is buggy
+ * and wipes out some LD instructions generated by the below
+ * code to validate the Frame Control bits
+ */
+ no_optimize = 1;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
+
switch (dir) {
case Q_SRC:
/*
@@ -3041,7 +3836,7 @@ gen_wlanhostop(eaddr, dir)
* Now check for a data frame.
* I.e, check "link[0] & 0x08".
*/
- gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINK, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x08;
b1->stmts = s;
@@ -3210,6 +4005,55 @@ gen_wlanhostop(eaddr, dir)
gen_and(b1, b0);
return b0;
+ /*
+ * XXX - add RA, TA, and BSSID keywords?
+ */
+ case Q_ADDR1:
+ return (gen_bcmp(OR_LINK, 4, 6, eaddr));
+
+ case Q_ADDR2:
+ /*
+ * Not present in CTS or ACK control frames.
+ */
+ b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+ IEEE80211_FC0_TYPE_MASK);
+ gen_not(b0);
+ b1 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+ IEEE80211_FC0_SUBTYPE_MASK);
+ gen_not(b1);
+ b2 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+ IEEE80211_FC0_SUBTYPE_MASK);
+ gen_not(b2);
+ gen_and(b1, b2);
+ gen_or(b0, b2);
+ b1 = gen_bcmp(OR_LINK, 10, 6, eaddr);
+ gen_and(b2, b1);
+ return b1;
+
+ case Q_ADDR3:
+ /*
+ * Not present in control frames.
+ */
+ b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+ IEEE80211_FC0_TYPE_MASK);
+ gen_not(b0);
+ b1 = gen_bcmp(OR_LINK, 16, 6, eaddr);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_ADDR4:
+ /*
+ * Present only if the direction mask has both "From DS"
+ * and "To DS" set. Neither control frames nor management
+ * frames should have both of those set, so we don't
+ * check the frame type.
+ */
+ b0 = gen_mcmp(OR_LINK, 1, BPF_B,
+ IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK);
+ b1 = gen_bcmp(OR_LINK, 24, 6, eaddr);
+ gen_and(b0, b1);
+ return b1;
+
case Q_AND:
b0 = gen_wlanhostop(eaddr, Q_SRC);
b1 = gen_wlanhostop(eaddr, Q_DST);
@@ -3652,48 +4496,48 @@ gen_gateway(eaddr, alist, proto, dir)
case Q_IP:
case Q_ARP:
case Q_RARP:
- switch (linktype) {
- case DLT_EN10MB:
- b0 = gen_ehostop(eaddr, Q_OR);
- break;
- case DLT_FDDI:
- b0 = gen_fhostop(eaddr, Q_OR);
- break;
+ switch (linktype) {
+ case DLT_EN10MB:
+ b0 = gen_ehostop(eaddr, Q_OR);
+ break;
+ case DLT_FDDI:
+ b0 = gen_fhostop(eaddr, Q_OR);
+ break;
case DLT_IEEE802:
- b0 = gen_thostop(eaddr, Q_OR);
- break;
+ b0 = gen_thostop(eaddr, Q_OR);
+ break;
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
- case DLT_PPI:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
- b0 = gen_wlanhostop(eaddr, Q_OR);
- break;
- case DLT_SUNATM:
- if (is_lane) {
- /*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
- */
- b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
- 0xFF00);
- gen_not(b1);
+ case DLT_PPI:
+ b0 = gen_wlanhostop(eaddr, Q_OR);
+ break;
+ case DLT_SUNATM:
+ if (is_lane) {
+ /*
+ * Check that the packet doesn't begin with an
+ * LE Control marker. (We've already generated
+ * a test for LANE.)
+ */
+ b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
+ BPF_H, 0xFF00);
+ gen_not(b1);
- /*
- * Now check the MAC address.
- */
- b0 = gen_ehostop(eaddr, Q_OR);
- gen_and(b1, b0);
- }
- break;
+ /*
+ * Now check the MAC address.
+ */
+ b0 = gen_ehostop(eaddr, Q_OR);
+ gen_and(b1, b0);
+ }
+ break;
case DLT_IP_OVER_FC:
- b0 = gen_ipfchostop(eaddr, Q_OR);
- break;
- default:
- bpf_error(
+ b0 = gen_ipfchostop(eaddr, Q_OR);
+ break;
+ default:
+ bpf_error(
"'gateway' supported only on ethernet/FDDI/token ring/802.11/Fibre Channel");
- }
+ }
b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR, Q_HOST);
while (*alist) {
tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR,
@@ -4458,7 +5302,8 @@ gen_protochain(v, proto, dir)
}
/*
- * We don't handle variable-length radiotap here headers yet.
+ * We don't handle variable-length prefixes before the link-layer
+ * header, or variable-length link-layer headers, here yet.
* We might want to add BPF instructions to do the protochain
* work, to simplify that and, on platforms that have a BPF
* interpreter with the new instructions, let the filtering
@@ -4467,11 +5312,15 @@ gen_protochain(v, proto, dir)
* branches, and backward branch support is unlikely to appear
* in kernel BPF engines.)
*/
- if (linktype == DLT_IEEE802_11_RADIO)
- bpf_error("'protochain' not supported with radiotap headers");
+ switch (linktype) {
- if (linktype == DLT_PPI)
- bpf_error("'protochain' not supported with PPI headers");
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ bpf_error("'protochain' not supported with 802.11");
+ }
no_optimize = 1; /*this code is not compatible with optimzer yet */
@@ -4490,11 +5339,11 @@ gen_protochain(v, proto, dir)
/* A = ip->ip_p */
s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
- s[i]->s.k = off_ll + off_nl + 9;
+ s[i]->s.k = off_macpl + off_nl + 9;
i++;
/* X = ip->ip_hl << 2 */
s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
- s[i]->s.k = off_ll + off_nl;
+ s[i]->s.k = off_macpl + off_nl;
i++;
break;
#ifdef INET6
@@ -4503,7 +5352,7 @@ gen_protochain(v, proto, dir)
/* A = ip6->ip_nxt */
s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
- s[i]->s.k = off_ll + off_nl + 6;
+ s[i]->s.k = off_macpl + off_nl + 6;
i++;
/* X = sizeof(struct ip6_hdr) */
s[i] = new_stmt(BPF_LDX|BPF_IMM);
@@ -4583,7 +5432,7 @@ gen_protochain(v, proto, dir)
i++;
/* A = P[X + packet head] */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_ll + off_nl;
+ s[i]->s.k = off_macpl + off_nl;
i++;
/* MEM[reg2] = A */
s[i] = new_stmt(BPF_ST);
@@ -4601,7 +5450,7 @@ gen_protochain(v, proto, dir)
i++;
/* A = P[X + packet head]; */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_ll + off_nl;
+ s[i]->s.k = off_macpl + off_nl;
i++;
/* A += 1 */
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
@@ -4660,7 +5509,7 @@ gen_protochain(v, proto, dir)
i++;
/* A = P[X + packet head]; */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_ll + off_nl;
+ s[i]->s.k = off_macpl + off_nl;
i++;
/* MEM[reg2] = A */
s[i] = new_stmt(BPF_ST);
@@ -4678,7 +5527,7 @@ gen_protochain(v, proto, dir)
i++;
/* A = P[X + packet head] */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_ll + off_nl;
+ s[i]->s.k = off_macpl + off_nl;
i++;
/* A += 2 */
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
@@ -4732,6 +5581,31 @@ gen_protochain(v, proto, dir)
#endif
}
+static struct block *
+gen_check_802_11_data_frame()
+{
+ struct slist *s;
+ struct block *b0, *b1;
+
+ /*
+ * A data frame has the 0x08 bit (b3) in the frame control field set
+ * and the 0x04 bit (b2) clear.
+ */
+ s = gen_load_a(OR_LINK, 0, BPF_B);
+ b0 = new_block(JMP(BPF_JSET));
+ b0->s.k = 0x08;
+ b0->stmts = s;
+
+ s = gen_load_a(OR_LINK, 0, BPF_B);
+ b1 = new_block(JMP(BPF_JSET));
+ b1->s.k = 0x04;
+ b1->stmts = s;
+ gen_not(b1);
+
+ gen_and(b1, b0);
+
+ return b0;
+}
/*
* Generate code that checks whether the packet is a packet for protocol
@@ -5019,9 +5893,9 @@ gen_scode(name, q)
return b;
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
case DLT_PPI:
eaddr = pcap_ether_hostton(name);
if (eaddr == NULL)
@@ -5250,7 +6124,6 @@ gen_scode(name, q)
else
bpf_error("unknown protocol: %s", name);
-
case Q_UNDEF:
syntax();
/* NOTREACHED */
@@ -5487,44 +6360,44 @@ gen_ecode(eaddr, q)
struct block *b, *tmp;
if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
- switch (linktype) {
- case DLT_EN10MB:
- return gen_ehostop(eaddr, (int)q.dir);
- case DLT_FDDI:
- return gen_fhostop(eaddr, (int)q.dir);
- case DLT_IEEE802:
- return gen_thostop(eaddr, (int)q.dir);
- case DLT_IEEE802_11:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
- case DLT_PPI:
- return gen_wlanhostop(eaddr, (int)q.dir);
- case DLT_SUNATM:
- if (is_lane) {
- /*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
- */
- tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
- 0xFF00);
- gen_not(tmp);
-
- /*
- * Now check the MAC address.
- */
- b = gen_ehostop(eaddr, (int)q.dir);
- gen_and(tmp, b);
- return b;
- }
- break;
- case DLT_IP_OVER_FC:
- return gen_ipfchostop(eaddr, (int)q.dir);
- default:
- bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
- break;
- }
+ switch (linktype) {
+ case DLT_EN10MB:
+ return gen_ehostop(eaddr, (int)q.dir);
+ case DLT_FDDI:
+ return gen_fhostop(eaddr, (int)q.dir);
+ case DLT_IEEE802:
+ return gen_thostop(eaddr, (int)q.dir);
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ return gen_wlanhostop(eaddr, (int)q.dir);
+ case DLT_SUNATM:
+ if (is_lane) {
+ /*
+ * Check that the packet doesn't begin with an
+ * LE Control marker. (We've already generated
+ * a test for LANE.)
+ */
+ tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
+ 0xFF00);
+ gen_not(tmp);
+
+ /*
+ * Now check the MAC address.
+ */
+ b = gen_ehostop(eaddr, (int)q.dir);
+ gen_and(tmp, b);
+ return b;
+ }
+ break;
+ case DLT_IP_OVER_FC:
+ return gen_ipfchostop(eaddr, (int)q.dir);
+ default:
+ bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+ break;
+ }
}
bpf_error("ethernet address used in non-ether expression");
/* NOTREACHED */
@@ -5691,14 +6564,14 @@ gen_load(proto, inst, size)
* XXX - are there any cases where we want
* off_nl_nosnap?
*/
- s = gen_llprefixlen();
+ s = gen_off_macpl();
/*
* If "s" is non-null, it has code to arrange that the
- * X register contains the length of the prefix preceding
- * the link-layer header. Add to it the offset computed
- * into the register specified by "index", and move that
- * into the X register. Otherwise, just load into the X
+ * X register contains the offset of the MAC-layer
+ * payload. Add to it the offset computed into the
+ * register specified by "index", and move that into
+ * the X register. Otherwise, just load into the X
* register the offset computed into the register specifed
* by "index".
*/
@@ -5712,13 +6585,17 @@ gen_load(proto, inst, size)
/*
* Load the item at the sum of the offset we've put in the
* X register, the offset of the start of the network
- * layer header, and the offset of the start of the link
- * layer header (which is 0 if the radio header is
- * variable-length; that header length is what we put
- * into the X register and then added to the index).
+ * layer header from the beginning of the MAC-layer
+ * payload, and the purported offset of the start of the
+ * MAC-layer payload (which might be 0 if there's a
+ * variable-length prefix before the link-layer header
+ * or the link-layer header itself is variable-length;
+ * the variable-length offset of the start of the
+ * MAC-layer payload is what we put into the X register
+ * and then added to the index).
*/
tmp = new_stmt(BPF_LD|BPF_IND|size);
- tmp->s.k = off_ll + off_nl;
+ tmp->s.k = off_macpl + off_nl;
sappend(s, tmp);
sappend(inst->s, s);
@@ -5759,22 +6636,24 @@ gen_load(proto, inst, size)
/*
* The X register now contains the sum of the length
* of any variable-length header preceding the link-layer
- * header and the length of the network-layer header.
+ * header, any variable-length link-layer header, and the
+ * length of the network-layer header.
+ *
* Load into the A register the offset relative to
* the beginning of the transport layer header,
* add the X register to that, move that to the
* X register, and load with an offset from the
* X register equal to the offset of the network
* layer header relative to the beginning of
- * the link-layer header plus the length of any
- * fixed-length header preceding the link-layer
- * header.
+ * the MAC-layer payload plus the fixed-length
+ * portion of the offset of the MAC-layer payload
+ * from the beginning of the raw packet data.
*/
sappend(s, xfer_to_a(inst));
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_ll + off_nl;
+ tmp->s.k = off_macpl + off_nl;
sappend(inst->s, s);
/*
@@ -5941,6 +6820,16 @@ static int regused[BPF_MEMWORDS];
static int curreg;
/*
+ * Initialize the table of used registers and the current register.
+ */
+static void
+init_regs()
+{
+ curreg = 0;
+ memset(regused, 0, sizeof regused);
+}
+
+/*
* Return the next free register.
*/
static int
@@ -6071,46 +6960,46 @@ gen_broadcast(proto)
case Q_DEFAULT:
case Q_LINK:
- switch (linktype) {
- case DLT_ARCNET:
- case DLT_ARCNET_LINUX:
- return gen_ahostop(abroadcast, Q_DST);
- case DLT_EN10MB:
- return gen_ehostop(ebroadcast, Q_DST);
- case DLT_FDDI:
- return gen_fhostop(ebroadcast, Q_DST);
- case DLT_IEEE802:
- return gen_thostop(ebroadcast, Q_DST);
- case DLT_IEEE802_11:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- case DLT_PPI:
- case DLT_PRISM_HEADER:
- return gen_wlanhostop(ebroadcast, Q_DST);
- case DLT_IP_OVER_FC:
- return gen_ipfchostop(ebroadcast, Q_DST);
- case DLT_SUNATM:
- if (is_lane) {
- /*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
- */
- b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
- 0xFF00);
- gen_not(b1);
+ switch (linktype) {
+ case DLT_ARCNET:
+ case DLT_ARCNET_LINUX:
+ return gen_ahostop(abroadcast, Q_DST);
+ case DLT_EN10MB:
+ return gen_ehostop(ebroadcast, Q_DST);
+ case DLT_FDDI:
+ return gen_fhostop(ebroadcast, Q_DST);
+ case DLT_IEEE802:
+ return gen_thostop(ebroadcast, Q_DST);
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ return gen_wlanhostop(ebroadcast, Q_DST);
+ case DLT_IP_OVER_FC:
+ return gen_ipfchostop(ebroadcast, Q_DST);
+ case DLT_SUNATM:
+ if (is_lane) {
+ /*
+ * Check that the packet doesn't begin with an
+ * LE Control marker. (We've already generated
+ * a test for LANE.)
+ */
+ b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
+ BPF_H, 0xFF00);
+ gen_not(b1);
- /*
- * Now check the MAC address.
- */
- b0 = gen_ehostop(ebroadcast, Q_DST);
- gen_and(b1, b0);
- return b0;
- }
- break;
- default:
- bpf_error("not a broadcast link");
- }
+ /*
+ * Now check the MAC address.
+ */
+ b0 = gen_ehostop(ebroadcast, Q_DST);
+ gen_and(b1, b0);
+ return b0;
+ }
+ break;
+ default:
+ bpf_error("not a broadcast link");
+ }
break;
case Q_IP:
@@ -6158,167 +7047,167 @@ gen_multicast(proto)
case Q_DEFAULT:
case Q_LINK:
- switch (linktype) {
- case DLT_ARCNET:
- case DLT_ARCNET_LINUX:
- /* all ARCnet multicasts use the same address */
- return gen_ahostop(abroadcast, Q_DST);
- case DLT_EN10MB:
- /* ether[0] & 1 != 0 */
- return gen_mac_multicast(0);
- case DLT_FDDI:
- /*
- * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
- *
- * XXX - was that referring to bit-order issues?
- */
- /* fddi[1] & 1 != 0 */
- return gen_mac_multicast(1);
- case DLT_IEEE802:
- /* tr[2] & 1 != 0 */
- return gen_mac_multicast(2);
- case DLT_IEEE802_11:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_PPI:
- case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
- /*
- * Oh, yuk.
- *
- * For control frames, there is no DA.
- *
- * For management frames, DA is at an
- * offset of 4 from the beginning of
- * the packet.
- *
- * For data frames, DA is at an offset
- * of 4 from the beginning of the packet
- * if To DS is clear and at an offset of
- * 16 from the beginning of the packet
- * if To DS is set.
- */
-
- /*
- * Generate the tests to be done for data frames.
- *
- * First, check for To DS set, i.e. "link[1] & 0x01".
- */
- s = gen_load_a(OR_LINK, 1, BPF_B);
- b1 = new_block(JMP(BPF_JSET));
- b1->s.k = 0x01; /* To DS */
- b1->stmts = s;
-
- /*
- * If To DS is set, the DA is at 16.
- */
- b0 = gen_mac_multicast(16);
- gen_and(b1, b0);
-
- /*
- * Now, check for To DS not set, i.e. check
- * "!(link[1] & 0x01)".
- */
- s = gen_load_a(OR_LINK, 1, BPF_B);
- b2 = new_block(JMP(BPF_JSET));
- b2->s.k = 0x01; /* To DS */
- b2->stmts = s;
- gen_not(b2);
-
- /*
- * If To DS is not set, the DA is at 4.
- */
- b1 = gen_mac_multicast(4);
- gen_and(b2, b1);
-
- /*
- * Now OR together the last two checks. That gives
- * the complete set of checks for data frames.
- */
- gen_or(b1, b0);
-
- /*
- * Now check for a data frame.
- * I.e, check "link[0] & 0x08".
- */
- s = gen_load_a(OR_LINK, 0, BPF_B);
- b1 = new_block(JMP(BPF_JSET));
- b1->s.k = 0x08;
- b1->stmts = s;
-
- /*
- * AND that with the checks done for data frames.
- */
- gen_and(b1, b0);
-
- /*
- * If the high-order bit of the type value is 0, this
- * is a management frame.
- * I.e, check "!(link[0] & 0x08)".
- */
- s = gen_load_a(OR_LINK, 0, BPF_B);
- b2 = new_block(JMP(BPF_JSET));
- b2->s.k = 0x08;
- b2->stmts = s;
- gen_not(b2);
-
- /*
- * For management frames, the DA is at 4.
- */
- b1 = gen_mac_multicast(4);
- gen_and(b2, b1);
-
- /*
- * OR that with the checks done for data frames.
- * That gives the checks done for management and
- * data frames.
- */
- gen_or(b1, b0);
-
- /*
- * If the low-order bit of the type value is 1,
- * this is either a control frame or a frame
- * with a reserved type, and thus not a
- * frame with an SA.
- *
- * I.e., check "!(link[0] & 0x04)".
- */
- s = gen_load_a(OR_LINK, 0, BPF_B);
- b1 = new_block(JMP(BPF_JSET));
- b1->s.k = 0x04;
- b1->stmts = s;
- gen_not(b1);
-
- /*
- * AND that with the checks for data and management
- * frames.
- */
- gen_and(b1, b0);
- return b0;
- case DLT_IP_OVER_FC:
- b0 = gen_mac_multicast(2);
- return b0;
- case DLT_SUNATM:
- if (is_lane) {
+ switch (linktype) {
+ case DLT_ARCNET:
+ case DLT_ARCNET_LINUX:
+ /* all ARCnet multicasts use the same address */
+ return gen_ahostop(abroadcast, Q_DST);
+ case DLT_EN10MB:
+ /* ether[0] & 1 != 0 */
+ return gen_mac_multicast(0);
+ case DLT_FDDI:
/*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
+ * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
+ *
+ * XXX - was that referring to bit-order issues?
*/
- b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
- 0xFF00);
+ /* fddi[1] & 1 != 0 */
+ return gen_mac_multicast(1);
+ case DLT_IEEE802:
+ /* tr[2] & 1 != 0 */
+ return gen_mac_multicast(2);
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ /*
+ * Oh, yuk.
+ *
+ * For control frames, there is no DA.
+ *
+ * For management frames, DA is at an
+ * offset of 4 from the beginning of
+ * the packet.
+ *
+ * For data frames, DA is at an offset
+ * of 4 from the beginning of the packet
+ * if To DS is clear and at an offset of
+ * 16 from the beginning of the packet
+ * if To DS is set.
+ */
+
+ /*
+ * Generate the tests to be done for data frames.
+ *
+ * First, check for To DS set, i.e. "link[1] & 0x01".
+ */
+ s = gen_load_a(OR_LINK, 1, BPF_B);
+ b1 = new_block(JMP(BPF_JSET));
+ b1->s.k = 0x01; /* To DS */
+ b1->stmts = s;
+
+ /*
+ * If To DS is set, the DA is at 16.
+ */
+ b0 = gen_mac_multicast(16);
+ gen_and(b1, b0);
+
+ /*
+ * Now, check for To DS not set, i.e. check
+ * "!(link[1] & 0x01)".
+ */
+ s = gen_load_a(OR_LINK, 1, BPF_B);
+ b2 = new_block(JMP(BPF_JSET));
+ b2->s.k = 0x01; /* To DS */
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * If To DS is not set, the DA is at 4.
+ */
+ b1 = gen_mac_multicast(4);
+ gen_and(b2, b1);
+
+ /*
+ * Now OR together the last two checks. That gives
+ * the complete set of checks for data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * Now check for a data frame.
+ * I.e, check "link[0] & 0x08".
+ */
+ s = gen_load_a(OR_LINK, 0, BPF_B);
+ b1 = new_block(JMP(BPF_JSET));
+ b1->s.k = 0x08;
+ b1->stmts = s;
+
+ /*
+ * AND that with the checks done for data frames.
+ */
+ gen_and(b1, b0);
+
+ /*
+ * If the high-order bit of the type value is 0, this
+ * is a management frame.
+ * I.e, check "!(link[0] & 0x08)".
+ */
+ s = gen_load_a(OR_LINK, 0, BPF_B);
+ b2 = new_block(JMP(BPF_JSET));
+ b2->s.k = 0x08;
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * For management frames, the DA is at 4.
+ */
+ b1 = gen_mac_multicast(4);
+ gen_and(b2, b1);
+
+ /*
+ * OR that with the checks done for data frames.
+ * That gives the checks done for management and
+ * data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * If the low-order bit of the type value is 1,
+ * this is either a control frame or a frame
+ * with a reserved type, and thus not a
+ * frame with an SA.
+ *
+ * I.e., check "!(link[0] & 0x04)".
+ */
+ s = gen_load_a(OR_LINK, 0, BPF_B);
+ b1 = new_block(JMP(BPF_JSET));
+ b1->s.k = 0x04;
+ b1->stmts = s;
gen_not(b1);
- /* ether[off_mac] & 1 != 0 */
- b0 = gen_mac_multicast(off_mac);
+ /*
+ * AND that with the checks for data and management
+ * frames.
+ */
gen_and(b1, b0);
return b0;
- }
- break;
- default:
- break;
- }
- /* Link not known to support multicasts */
- break;
+ case DLT_IP_OVER_FC:
+ b0 = gen_mac_multicast(2);
+ return b0;
+ case DLT_SUNATM:
+ if (is_lane) {
+ /*
+ * Check that the packet doesn't begin with an
+ * LE Control marker. (We've already generated
+ * a test for LANE.)
+ */
+ b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
+ BPF_H, 0xFF00);
+ gen_not(b1);
+
+ /* ether[off_mac] & 1 != 0 */
+ b0 = gen_mac_multicast(off_mac);
+ gen_and(b1, b0);
+ return b0;
+ }
+ break;
+ default:
+ break;
+ }
+ /* Link not known to support multicasts */
+ break;
case Q_IP:
b0 = gen_linktype(ETHERTYPE_IP);
@@ -6415,6 +7304,8 @@ gen_inbound(dir)
case DLT_JUNIPER_FRELAY:
case DLT_JUNIPER_CHDLC:
case DLT_JUNIPER_VP:
+ case DLT_JUNIPER_ST:
+ case DLT_JUNIPER_ISM:
/* juniper flags (including direction) are stored
* the byte after the 3-byte magic number */
if (dir) {
@@ -6424,7 +7315,7 @@ gen_inbound(dir)
/* match incoming packets */
b0 = gen_mcmp(OR_LINK, 3, BPF_B, 1, 0x01);
}
- break;
+ break;
default:
bpf_error("inbound/outbound not supported on linktype %d",
@@ -6443,13 +7334,12 @@ 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);
+ if (linktype != DLT_PFLOG) {
+ bpf_error("ifname supported only on PF linktype");
/* NOTREACHED */
}
+ len = sizeof(((struct pfloghdr *)0)->ifname);
+ off = offsetof(struct pfloghdr, ifname);
if (strlen(ifname) >= len) {
bpf_error("ifname interface names can only be %d characters",
len-1);
@@ -6466,14 +7356,16 @@ gen_pf_ruleset(char *ruleset)
struct block *b0;
if (linktype != DLT_PFLOG) {
- bpf_error("ruleset not supported on linktype 0x%x", linktype);
+ bpf_error("ruleset supported only on PF 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(OR_LINK, offsetof(struct pfloghdr, ruleset),
strlen(ruleset), (const u_char *)ruleset);
return (b0);
@@ -6485,14 +7377,13 @@ gen_pf_rnr(int rnr)
{
struct block *b0;
- if (linktype == DLT_PFLOG) {
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, rulenr), BPF_W,
- (bpf_int32)rnr);
- } else {
- bpf_error("rnr not supported on linktype 0x%x", linktype);
+ if (linktype != DLT_PFLOG) {
+ bpf_error("rnr supported only on PF linktype");
/* NOTREACHED */
}
+ b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, rulenr), BPF_W,
+ (bpf_int32)rnr);
return (b0);
}
@@ -6503,7 +7394,7 @@ gen_pf_srnr(int srnr)
struct block *b0;
if (linktype != DLT_PFLOG) {
- bpf_error("srnr not supported on linktype 0x%x", linktype);
+ bpf_error("srnr supported only on PF linktype");
/* NOTREACHED */
}
@@ -6518,14 +7409,13 @@ gen_pf_reason(int reason)
{
struct block *b0;
- if (linktype == DLT_PFLOG) {
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, reason), BPF_B,
- (bpf_int32)reason);
- } else {
- bpf_error("reason not supported on linktype 0x%x", linktype);
+ if (linktype != DLT_PFLOG) {
+ bpf_error("reason supported only on PF linktype");
/* NOTREACHED */
}
+ b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, reason), BPF_B,
+ (bpf_int32)reason);
return (b0);
}
@@ -6535,14 +7425,13 @@ gen_pf_action(int action)
{
struct block *b0;
- if (linktype == DLT_PFLOG) {
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, action), BPF_B,
- (bpf_int32)action);
- } else {
- bpf_error("action not supported on linktype 0x%x", linktype);
+ if (linktype != DLT_PFLOG) {
+ bpf_error("action supported only on PF linktype");
/* NOTREACHED */
}
+ b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, action), BPF_B,
+ (bpf_int32)action);
return (b0);
}
#else /* !HAVE_NET_PFVAR_H */
@@ -6595,14 +7484,75 @@ gen_pf_action(int action)
}
#endif /* HAVE_NET_PFVAR_H */
+/* IEEE 802.11 wireless header */
+struct block *
+gen_p80211_type(int type, int mask)
+{
+ struct block *b0;
+
+ switch (linktype) {
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ b0 = gen_mcmp(OR_LINK, 0, BPF_B, (bpf_int32)type,
+ (bpf_int32)mask);
+ break;
+
+ default:
+ bpf_error("802.11 link-layer types supported only on 802.11");
+ /* NOTREACHED */
+ }
+
+ return (b0);
+}
+
+struct block *
+gen_p80211_fcdir(int fcdir)
+{
+ struct block *b0;
+
+ switch (linktype) {
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ break;
+
+ default:
+ bpf_error("frame direction supported only with 802.11 headers");
+ /* NOTREACHED */
+ }
+
+ b0 = gen_mcmp(OR_LINK, 1, BPF_B, (bpf_int32)fcdir,
+ (bpf_u_int32)IEEE80211_FC1_DIR_MASK);
+
+ return (b0);
+}
+
struct block *
gen_acode(eaddr, q)
register const u_char *eaddr;
struct qual q;
{
- if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
- if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX)
- return gen_ahostop(eaddr, (int)q.dir);
+ switch (linktype) {
+
+ case DLT_ARCNET:
+ case DLT_ARCNET_LINUX:
+ if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) &&
+ q.proto == Q_LINK)
+ return (gen_ahostop(eaddr, (int)q.dir));
+ else {
+ bpf_error("ARCnet address used in non-arc expression");
+ /* NOTREACHED */
+ }
+ break;
+
+ default:
+ bpf_error("aid supported only on ARCnet");
+ /* NOTREACHED */
}
bpf_error("ARCnet address used in non-arc expression");
/* NOTREACHED */
@@ -6655,10 +7605,11 @@ gen_vlan(vlan_num)
bpf_error("no VLAN match after MPLS");
/*
- * Change the offsets to point to the type and data fields within
- * the VLAN packet. Just increment the offsets, so that we
- * can support a hierarchy, e.g. "vlan 300 && vlan 200" to
- * capture VLAN 200 encapsulated within VLAN 100.
+ * Check for a VLAN packet, and then change the offsets to point
+ * to the type and data fields within the VLAN packet. Just
+ * increment the offsets, so that we can support a hierarchy, e.g.
+ * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within
+ * VLAN 100.
*
* XXX - this is a bit of a kludge. If we were to split the
* compiler into a parser that parses an expression and
@@ -6684,15 +7635,29 @@ gen_vlan(vlan_num)
* be done assuming a VLAN, even though the "or" could be viewed
* as meaning "or, if this isn't a VLAN packet...".
*/
- orig_linktype = off_linktype; /* save original values */
orig_nl = off_nl;
switch (linktype) {
case DLT_EN10MB:
+ /* check for VLAN */
+ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+ (bpf_int32)ETHERTYPE_8021Q);
+
+ /* If a specific VLAN is requested, check VLAN id */
+ if (vlan_num >= 0) {
+ b1 = gen_mcmp(OR_MACPL, 0, BPF_H,
+ (bpf_int32)vlan_num, 0x0fff);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ off_macpl += 4;
off_linktype += 4;
+#if 0
off_nl_nosnap += 4;
off_nl += 4;
+#endif
break;
default:
@@ -6701,17 +7666,6 @@ gen_vlan(vlan_num)
/*NOTREACHED*/
}
- /* check for VLAN */
- b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q);
-
- /* If a specific VLAN is requested, check VLAN id */
- if (vlan_num >= 0) {
- b1 = gen_mcmp(OR_LINK, orig_nl, BPF_H, (bpf_int32)vlan_num,
- 0x0fff);
- gen_and(b0, b1);
- b0 = b1;
- }
-
return (b0);
}
@@ -6737,7 +7691,7 @@ gen_mpls(label_num)
if (label_stack_depth > 0) {
/* just match the bottom-of-stack bit clear */
- b0 = gen_mcmp(OR_LINK, orig_nl-2, BPF_B, 0, 0x01);
+ b0 = gen_mcmp(OR_MACPL, orig_nl-2, BPF_B, 0, 0x01);
} else {
/*
* Indicate that we're checking MPLS-encapsulated headers,
@@ -6772,7 +7726,7 @@ gen_mpls(label_num)
/* If a specific MPLS label is requested, check it */
if (label_num >= 0) {
label_num = label_num << 12; /* label is shifted 12 bits on the wire */
- b1 = gen_mcmp(OR_LINK, orig_nl, BPF_W, (bpf_int32)label_num,
+ b1 = gen_mcmp(OR_MACPL, orig_nl, BPF_W, (bpf_int32)label_num,
0xfffff000); /* only compare the first 20 bits */
gen_and(b0, b1);
b0 = b1;
@@ -6806,7 +7760,8 @@ gen_pppoes()
/*
* Change the offsets to point to the type and data fields within
- * the PPP packet.
+ * the PPP packet, and note that this is PPPoE rather than
+ * raw PPP.
*
* XXX - this is a bit of a kludge. If we were to split the
* compiler into a parser that parses an expression and
@@ -6834,24 +7789,28 @@ gen_pppoes()
*/
orig_linktype = off_linktype; /* save original values */
orig_nl = off_nl;
+ is_pppoes = 1;
/*
* The "network-layer" protocol is PPPoE, which has a 6-byte
- * PPPoE header, followed by PPP payload, so we set the
- * offsets to the network layer offset plus 6 bytes for
- * the PPPoE header plus the values appropriate for PPP when
- * encapsulated in Ethernet (which means there's no HDLC
- * encapsulation).
+ * PPPoE header, followed by a PPP packet.
+ *
+ * There is no HDLC encapsulation for the PPP packet (it's
+ * encapsulated in PPPoES instead), so the link-layer type
+ * starts at the first byte of the PPP packet. For PPPoE,
+ * that offset is relative to the beginning of the total
+ * link-layer payload, including any 802.2 LLC header, so
+ * it's 6 bytes past off_nl.
*/
- off_linktype = orig_nl + 6;
- off_nl = orig_nl + 6 + 2;
- off_nl_nosnap = orig_nl + 6 + 2;
+ off_linktype = off_nl + 6;
/*
- * Set the link-layer type to PPP, as all subsequent tests will
- * be on the encapsulated PPP header.
+ * The network-layer offsets are relative to the beginning
+ * of the MAC-layer payload; that's past the 6-byte
+ * PPPoE header and the 2-byte PPP header.
*/
- linktype = DLT_PPP;
+ off_nl = 6+2;
+ off_nl_nosnap = 6+2;
return b0;
}
@@ -6997,8 +7956,9 @@ gen_atmtype_abbrev(type)
is_lane = 1;
off_mac = off_payload + 2; /* MAC header */
off_linktype = off_mac + 12;
- off_nl = off_mac + 14; /* Ethernet II */
- off_nl_nosnap = off_mac + 17; /* 802.3+802.2 */
+ off_macpl = off_mac + 14; /* Ethernet */
+ off_nl = 0; /* Ethernet II */
+ off_nl_nosnap = 3; /* 802.3+802.2 */
break;
case A_LLC:
@@ -7031,6 +7991,7 @@ gen_mtp2type_abbrev(type)
case M_FISU:
if ( (linktype != DLT_MTP2) &&
+ (linktype != DLT_ERF) &&
(linktype != DLT_MTP2_WITH_PHDR) )
bpf_error("'fisu' supported only on MTP2");
/* gen_ncmp(offrel, offset, size, mask, jtype, reverse, value) */
@@ -7039,6 +8000,7 @@ gen_mtp2type_abbrev(type)
case M_LSSU:
if ( (linktype != DLT_MTP2) &&
+ (linktype != DLT_ERF) &&
(linktype != DLT_MTP2_WITH_PHDR) )
bpf_error("'lssu' supported only on MTP2");
b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 1, 2);
@@ -7048,6 +8010,7 @@ gen_mtp2type_abbrev(type)
case M_MSU:
if ( (linktype != DLT_MTP2) &&
+ (linktype != DLT_ERF) &&
(linktype != DLT_MTP2_WITH_PHDR) )
bpf_error("'msu' supported only on MTP2");
b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 2);