Merge branch 'vendor/LIBPCAP' and updated build for new version.
[dragonfly.git] / contrib / libpcap / gencode.c
index eb260b9..bd38224 100644 (file)
@@ -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 <netproto/802_11/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>
@@ -88,9 +89,8 @@ static const char rcsid[] _U_ =
 #include <netdb.h>     /* for "struct addrinfo" */
 #endif /* WIN32 */
 #endif /*INET6*/
-#include <pcap-namedb.h>
+#include <pcap/namedb.h>
 
-#include <netproto/802_11/ieee80211.h>
 #include <netproto/802_11/ieee80211_radiotap.h>
 
 #define ETHERMTU       1500
@@ -109,8 +109,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;
@@ -138,6 +138,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);
 
@@ -149,7 +150,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 */
@@ -194,6 +196,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);
@@ -201,12 +204,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
@@ -251,6 +258,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);
@@ -373,6 +381,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();
@@ -488,24 +497,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
@@ -516,14 +512,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
@@ -686,13 +698,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
@@ -705,12 +711,48 @@ 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
@@ -733,6 +775,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.
  */
@@ -772,8 +821,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:
  *
@@ -819,6 +868,11 @@ init_linktype(p)
        off_proto = -1;
        off_payload = -1;
 
+       /*
+        * And that we're not doing PPPoE.
+        */
+       is_pppoes = 0;
+
        /*
         * And assume we're not doing SS7.
         */
@@ -829,34 +883,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:
@@ -865,29 +925,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:
@@ -895,8 +959,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:
@@ -905,14 +970,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:
@@ -928,12 +995,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:
@@ -961,11 +1028,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.
@@ -974,90 +1045,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.
-                */
-               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.
+                * 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_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:
@@ -1074,6 +1092,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;
@@ -1087,23 +1106,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:
@@ -1113,6 +1135,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;
@@ -1129,8 +1152,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:
@@ -1139,6 +1163,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;
@@ -1150,14 +1175,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:
@@ -1165,6 +1192,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;
@@ -1174,21 +1202,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
 
@@ -1199,26 +1230,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 */
@@ -1226,36 +1261,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;
@@ -1267,6 +1322,7 @@ init_linktype(p)
                off_dpc = 4;
                off_sls = 7;
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1278,6 +1334,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;
@@ -1285,8 +1354,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
 
@@ -1295,6 +1365,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;
@@ -1304,6 +1375,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;
@@ -1313,6 +1385,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;
@@ -1366,6 +1550,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.
@@ -1388,12 +1611,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:
@@ -1406,21 +1633,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:
@@ -1440,12 +1668,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
@@ -1463,22 +1694,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;
 }
@@ -1552,7 +1785,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;
@@ -1590,17 +1823,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);
 
                /*
@@ -1655,9 +1886,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);
 
                /*
@@ -1734,7 +1965,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;
@@ -1765,10 +1996,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);
@@ -1816,11 +2045,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);
 
                /*
@@ -1844,7 +2071,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;
@@ -1864,18 +2091,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;
+
+       /*
+        * 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_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;
 
        /*
-        * 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 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_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
@@ -1910,7 +2288,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);
 
                /*
@@ -1919,13 +2297,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);
 }
 
 /* 
@@ -1934,21 +2308,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
@@ -1982,7 +2356,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);
 
                /*
@@ -1991,16 +2365,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) {
+               /*
+                * 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.
+                */
+               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);
+
                /*
-                * Now append all the existing statements in this
-                * block to these statements.
+                * 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.
                 */
-               sappend(s1, b->stmts);
-               b->stmts = s1;
+               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)
 {
@@ -2027,42 +2680,61 @@ gen_ppi_dlt_check(void)
        return b;
 }
 
-static void
-insert_load_llprefixlen(b)
-       struct block *b;
+static struct slist *
+gen_prism_llprefixlen(void)
+{
+       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();
+       }
+
+       /*
+        * Load the register containing the radio length
+        * into the X register.
+        */
+       s = new_stmt(BPF_LDX|BPF_MEM);
+       s->s.k = reg_off_ll;
+       return s;
+}
+
+static struct slist *
+gen_avs_llprefixlen(void)
 {
-       switch (linktype) {
-
-       /* 
-        * 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:
-               insert_ppi_load_llprefixlen(b);
-               break;
+       struct slist *s;
 
-       case DLT_IEEE802_11_RADIO:
-               insert_radiotap_load_llprefixlen(b);
-               break;
+       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();
        }
 
        /*
@@ -2070,7 +2742,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;
 }
 
@@ -2087,25 +2759,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
@@ -2117,18 +2787,109 @@ 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.
@@ -2147,12 +2908,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:
@@ -2161,6 +2922,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:
@@ -2183,13 +2963,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:
@@ -2274,47 +3082,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:
@@ -2325,6 +3095,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);
@@ -2332,42 +3106,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:
@@ -2556,6 +3300,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:
@@ -2572,6 +3319,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
@@ -2587,8 +3336,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");
        }
 
        /*
@@ -2606,12 +3398,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);
 }
@@ -2624,10 +3411,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];
 
@@ -2639,7 +3425,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);
 }
 
 /*
@@ -2672,7 +3458,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:
@@ -2680,7 +3466,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:
@@ -2693,7 +3479,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:
                /*
@@ -2705,8 +3491,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
@@ -2721,15 +3506,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);
                }
        }
 }
@@ -2938,7 +3721,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)
@@ -2948,6 +3732,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:
                /*
@@ -3045,7 +3839,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;
@@ -3214,6 +4008,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);
@@ -3656,48 +4499,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,
@@ -4462,7 +5305,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
@@ -4471,11 +5315,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 */
 
@@ -4494,11 +5342,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
@@ -4507,7 +5355,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);
@@ -4587,7 +5435,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);
@@ -4605,7 +5453,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);
@@ -4664,7 +5512,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);
@@ -4682,7 +5530,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);
@@ -4736,6 +5584,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
@@ -5023,9 +5896,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)
@@ -5254,7 +6127,6 @@ gen_scode(name, q)
                else
                        bpf_error("unknown protocol: %s", name);
 
-
        case Q_UNDEF:
                syntax();
                /* NOTREACHED */
@@ -5491,44 +6363,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 */
@@ -5695,14 +6567,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".
                 */
@@ -5716,13 +6588,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);
 
@@ -5763,22 +6639,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);
 
                /*
@@ -5944,6 +6822,16 @@ gen_arth(code, a0, a1)
 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.
  */
@@ -6075,46 +6963,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:
@@ -6162,167 +7050,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);
@@ -6419,6 +7307,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) {
@@ -6428,7 +7318,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",
@@ -6447,13 +7337,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);
@@ -6470,14 +7359,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);
@@ -6489,14 +7380,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);
 }
 
@@ -6507,7 +7397,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 */
        }
 
@@ -6522,14 +7412,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);
 }
 
@@ -6539,14 +7428,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 */
@@ -6605,12 +7493,45 @@ gen_p80211_type(int type, int mask)
 {
        struct block *b0;
 
-       if (linktype != DLT_IEEE802_11 && linktype != DLT_IEEE802_11_RADIO) {
-               bpf_error("action not supported on linktype 0x%x\n", linktype);
+       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, offsetof(struct ieee80211_frame, i_fc[0]),
-                     BPF_B, (bpf_int32)type, (bpf_int32)mask);
+
+       b0 = gen_mcmp(OR_LINK, 1, BPF_B, (bpf_int32)fcdir,
+               (bpf_u_int32)IEEE80211_FC1_DIR_MASK);
+
        return (b0);
 }
 
@@ -6619,9 +7540,22 @@ 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 */
@@ -6674,10 +7608,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
@@ -6703,15 +7638,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:
@@ -6720,17 +7669,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);
 }
 
@@ -6756,7 +7694,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,
@@ -6791,7 +7729,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;
@@ -6825,7 +7763,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
@@ -6853,24 +7792,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;
 }
@@ -7016,8 +7959,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:
@@ -7050,6 +7994,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) */
@@ -7058,6 +8003,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);
@@ -7067,6 +8013,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);