]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
Another change from Debian.
[libpcap] / gencode.c
index fd1db5aa8c2cabdc75851e2df091d1b7ea3cbb31..5548e6fd1f0c4dadfdff9b0778a0f6dde3e0daa6 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -21,7 +21,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.4 2007-11-04 22:29:35 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.19 2008-12-23 20:14:12 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -68,6 +68,7 @@ static const char rcsid[] _U_ =
 #include "nlpid.h"
 #include "llc.h"
 #include "gencode.h"
+#include "ieee80211.h"
 #include "atmuni31.h"
 #include "sunatmpos.h"
 #include "ppp.h"
@@ -146,7 +147,8 @@ static struct block *root;
  */
 enum e_offrel {
        OR_PACKET,      /* relative to the beginning of the packet */
-       OR_LINK,        /* relative to the link-layer header */
+       OR_LINK,        /* relative to the beginning of the link-layer header */
+       OR_MACPL,       /* relative to the end of the MAC-layer header */
        OR_NET,         /* relative to the network-layer header */
        OR_NET_NOSNAP,  /* relative to the network-layer header, with no SNAP header at the link layer */
        OR_TRAN_IPV4,   /* relative to the transport-layer header, with IPv4 network layer */
@@ -191,6 +193,7 @@ static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *);
 static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32,
     bpf_u_int32, bpf_u_int32, int, bpf_int32);
 static struct slist *gen_load_llrel(u_int, u_int);
+static struct slist *gen_load_macplrel(u_int, u_int);
 static struct slist *gen_load_a(enum e_offrel, u_int, u_int);
 static struct slist *gen_loadx_iphdrlen(void);
 static struct block *gen_uncond(int);
@@ -198,12 +201,16 @@ static inline struct block *gen_true(void);
 static inline struct block *gen_false(void);
 static struct block *gen_ether_linktype(int);
 static struct block *gen_linux_sll_linktype(int);
-static void insert_radiotap_load_llprefixlen(struct block *);
-static void insert_ppi_load_llprefixlen(struct block *);
-static void insert_load_llprefixlen(struct block *);
+static struct slist *gen_load_prism_llprefixlen(void);
+static struct slist *gen_load_avs_llprefixlen(void);
+static struct slist *gen_load_radiotap_llprefixlen(void);
+static struct slist *gen_load_ppi_llprefixlen(void);
+static void insert_compute_vloffsets(struct block *);
 static struct slist *gen_llprefixlen(void);
+static struct slist *gen_off_macpl(void);
+static int ethertype_to_ppptype(int);
 static struct block *gen_linktype(int);
-static struct block *gen_snap(bpf_u_int32, bpf_u_int32, u_int);
+static struct block *gen_snap(bpf_u_int32, bpf_u_int32);
 static struct block *gen_llc_linktype(int);
 static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);
 #ifdef INET6
@@ -248,6 +255,7 @@ static struct slist *xfer_to_x(struct arth *);
 static struct slist *xfer_to_a(struct arth *);
 static struct block *gen_mac_multicast(int);
 static struct block *gen_len(int, int);
+static struct block *gen_check_802_11_data_frame(void);
 
 static struct block *gen_ppi_dlt_check(void);
 static struct block *gen_msg_abbrev(int type);
@@ -491,18 +499,6 @@ 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
@@ -513,13 +509,30 @@ finish_parse(p)
         * statements of all blocks that use those lengths and that
         * have no predecessors that use them, so that we only compute
         * the lengths if we need them.  There might be even better
-        * approaches than that.  However, as we're currently only
-        * handling variable-length radiotap headers, and as all
-        * filtering expressions other than raw link[M:N] tests
-        * require the length of that header, doing more for that
-        * header length isn't really worth the effort.
+        * approaches than that.
+        *
+        * However, those strategies would be more complicated, and
+        * as we don't generate code to compute a length if the
+        * program has no tests that use the length, and as most
+        * tests will probably use those lengths, we would just
+        * postpone computing the lengths so that it's not done
+        * for tests that fail early, and it's not clear that's
+        * worth the effort.
+        */
+       insert_compute_vloffsets(p->head);
+       
+       /*
+        * For DLT_PPI captures, generate a check of the per-packet
+        * DLT value to make sure it's DLT_IEEE802_11.
         */
-       insert_load_llprefixlen(root);
+       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;
 }
 
 void
@@ -682,13 +695,7 @@ gen_ncmp(offrel, offset, size, mask, jtype, reverse, v)
  * Various code constructs need to know the layout of the data link
  * layer.  These variables give the necessary offsets from the beginning
  * of the packet data.
- *
- * If the link layer has variable_length headers, the offsets are offsets
- * from the end of the link-link-layer header, and "reg_ll_size" is
- * the register number for a register containing the length of the
- * link-layer header.  Otherwise, "reg_ll_size" is -1.
  */
-static int reg_ll_size;
 
 /*
  * This is the offset of the beginning of the link-layer header from
@@ -701,12 +708,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
@@ -729,6 +772,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.
  */
@@ -768,8 +818,8 @@ static u_int off_payload;
 
 /*
  * These are offsets to the beginning of the network-layer header.
- * They are relative to the beginning of the link-layer header (i.e.,
- * they don't include off_ll).
+ * They are relative to the beginning of the MAC-layer payload (i.e.,
+ * they don't include off_ll or off_macpl).
  *
  * If the link layer never uses 802.2 LLC:
  *
@@ -815,6 +865,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.
         */
@@ -825,34 +880,40 @@ init_linktype(p)
        off_sls = -1;
 
        /*
-        * Also assume it's not 802.11 with a fixed-length radio header.
+        * Also assume it's not 802.11.
         */
        off_ll = 0;
+       off_macpl = 0;
+       off_macpl_is_variable = 0;
 
        orig_linktype = -1;
        orig_nl = -1;
         label_stack_depth = 0;
 
-       reg_ll_size = -1;
+       reg_off_ll = -1;
+       reg_off_macpl = -1;
 
        switch (linktype) {
 
        case DLT_ARCNET:
                off_linktype = 2;
-               off_nl = 6;             /* XXX in reality, variable! */
-               off_nl_nosnap = 6;      /* no 802.2 LLC */
+               off_macpl = 6;
+               off_nl = 0;             /* XXX in reality, variable! */
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_ARCNET_LINUX:
                off_linktype = 4;
-               off_nl = 8;             /* XXX in reality, variable! */
-               off_nl_nosnap = 8;      /* no 802.2 LLC */
+               off_macpl = 8;
+               off_nl = 0;             /* XXX in reality, variable! */
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_EN10MB:
                off_linktype = 12;
-               off_nl = 14;            /* Ethernet II */
-               off_nl_nosnap = 17;     /* 802.3+802.2 */
+               off_macpl = 14;         /* Ethernet header length */
+               off_nl = 0;             /* Ethernet II */
+               off_nl_nosnap = 3;      /* 802.3+802.2 */
                return;
 
        case DLT_SLIP:
@@ -861,29 +922,33 @@ init_linktype(p)
                 * header is hacked into our SLIP driver.
                 */
                off_linktype = -1;
-               off_nl = 16;
-               off_nl_nosnap = 16;     /* no 802.2 LLC */
+               off_macpl = 16;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_SLIP_BSDOS:
                /* XXX this may be the same as the DLT_PPP_BSDOS case */
                off_linktype = -1;
                /* XXX end */
-               off_nl = 24;
-               off_nl_nosnap = 24;     /* no 802.2 LLC */
+               off_macpl = 24;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_NULL:
        case DLT_LOOP:
                off_linktype = 0;
-               off_nl = 4;
-               off_nl_nosnap = 4;      /* no 802.2 LLC */
+               off_macpl = 4;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_ENC:
                off_linktype = 0;
-               off_nl = 12;
-               off_nl_nosnap = 12;     /* no 802.2 LLC */
+               off_macpl = 12;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_PPP:
@@ -891,8 +956,9 @@ init_linktype(p)
        case DLT_C_HDLC:                /* BSD/OS Cisco HDLC */
        case DLT_PPP_SERIAL:            /* NetBSD sync/async serial PPP */
                off_linktype = 2;
-               off_nl = 4;
-               off_nl_nosnap = 4;      /* no 802.2 LLC */
+               off_macpl = 4;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_PPP_ETHER:
@@ -901,14 +967,16 @@ init_linktype(p)
                 * only covers session state.
                 */
                off_linktype = 6;
-               off_nl = 8;
-               off_nl_nosnap = 8;      /* no 802.2 LLC */
+               off_macpl = 8;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_PPP_BSDOS:
                off_linktype = 5;
-               off_nl = 24;
-               off_nl_nosnap = 24;     /* no 802.2 LLC */
+               off_macpl = 24;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_FDDI:
@@ -924,12 +992,12 @@ init_linktype(p)
 #ifdef PCAP_FDDIPAD
                off_linktype += pcap_fddipad;
 #endif
-               off_nl = 21;            /* FDDI+802.2+SNAP */
-               off_nl_nosnap = 16;     /* FDDI+802.2 */
+               off_macpl = 13;         /* FDDI MAC header length */
 #ifdef PCAP_FDDIPAD
-               off_nl += pcap_fddipad;
-               off_nl_nosnap += pcap_fddipad;
+               off_macpl += pcap_fddipad;
 #endif
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_IEEE802:
@@ -957,11 +1025,15 @@ init_linktype(p)
                 * 8 - figure out which byte that is).
                 */
                off_linktype = 14;
-               off_nl = 22;            /* Token Ring+802.2+SNAP */
-               off_nl_nosnap = 17;     /* Token Ring+802.2 */
+               off_macpl = 14;         /* Token Ring MAC header length */
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
                /*
                 * 802.11 doesn't really have a link-level type field.
                 * We set "off_linktype" to the offset of the LLC header.
@@ -970,90 +1042,37 @@ init_linktype(p)
                 * is being used and pick out the encapsulated Ethernet type.
                 * XXX - should we generate code to check for SNAP?
                 *
-                * XXX - the header is actually variable-length.  We
-                * assume a 24-byte link-layer header, as appears in
-                * data frames in networks with no bridges.  If the
-                * fromds and tods 802.11 header bits are both set,
-                * it's actually supposed to be 30 bytes.
-                */
-               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:
@@ -1070,6 +1089,7 @@ init_linktype(p)
                 * PPPo{A,E} and a PPP protocol of IP and....
                 */
                off_linktype = 0;
+               off_macpl = 0;          /* packet begins with LLC header */
                off_nl = 8;             /* 802.2+SNAP */
                off_nl_nosnap = 3;      /* 802.2 */
                return;
@@ -1083,23 +1103,26 @@ init_linktype(p)
                off_vpi = SUNATM_VPI_POS;
                off_vci = SUNATM_VCI_POS;
                off_proto = PROTO_POS;
-               off_mac = -1;   /* LLC-encapsulated, so no MAC-layer header */
+               off_mac = -1;   /* assume LLC-encapsulated, so no MAC-layer header */
                off_payload = SUNATM_PKT_BEGIN_POS;
                off_linktype = off_payload;
-               off_nl = off_payload+8;         /* 802.2+SNAP */
-               off_nl_nosnap = off_payload+3;  /* 802.2 */
+               off_macpl = off_payload;        /* if LLC-encapsulated */
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_RAW:
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 0;
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_LINUX_SLL:     /* fake header for Linux cooked socket */
                off_linktype = 14;
-               off_nl = 16;
-               off_nl_nosnap = 16;     /* no 802.2 LLC */
+               off_macpl = 16;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_LTALK:
@@ -1109,6 +1132,7 @@ init_linktype(p)
                 * "long" DDP packet following.
                 */
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 0;
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
@@ -1125,8 +1149,9 @@ init_linktype(p)
                 * 2625 says SNAP should be used.
                 */
                off_linktype = 16;
-               off_nl = 24;            /* IPFC+802.2+SNAP */
-               off_nl_nosnap = 19;     /* IPFC+802.2 */
+               off_macpl = 16;
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_FRELAY:
@@ -1135,6 +1160,7 @@ init_linktype(p)
                 * frames (NLPID of 0x80).
                 */
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 0;
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
@@ -1146,14 +1172,16 @@ init_linktype(p)
                  */
        case DLT_MFR:
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 4;
                off_nl_nosnap = 0;      /* XXX - for now -> no 802.2 LLC */
                return;
 
        case DLT_APPLE_IP_OVER_IEEE1394:
                off_linktype = 16;
-               off_nl = 18;
-               off_nl_nosnap = 18;     /* no 802.2 LLC */
+               off_macpl = 18;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_LINUX_IRDA:
@@ -1161,6 +1189,7 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1170,21 +1199,24 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
 
        case DLT_SYMANTEC_FIREWALL:
                off_linktype = 6;
-               off_nl = 44;            /* Ethernet II */
-               off_nl_nosnap = 44;     /* XXX - what does it do with 802.3 packets? */
+               off_macpl = 44;
+               off_nl = 0;             /* Ethernet II */
+               off_nl_nosnap = 0;      /* XXX - what does it do with 802.3 packets? */
                return;
 
 #ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                off_linktype = 0;
-               off_nl = PFLOG_HDRLEN;
-               off_nl_nosnap = PFLOG_HDRLEN;   /* no 802.2 LLC */
+               off_macpl = PFLOG_HDRLEN;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 #endif
 
@@ -1195,26 +1227,30 @@ init_linktype(p)
         case DLT_JUNIPER_CHDLC:
         case DLT_JUNIPER_FRELAY:
                 off_linktype = 4;
-               off_nl = 4;
+               off_macpl = 4;
+               off_nl = 0;
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                 return;
 
        case DLT_JUNIPER_ATM1:
-               off_linktype = 4; /* in reality variable between 4-8 */
-               off_nl = 4;
-               off_nl_nosnap = 14;
+               off_linktype = 4;       /* in reality variable between 4-8 */
+               off_macpl = 4;  /* in reality variable between 4-8 */
+               off_nl = 0;
+               off_nl_nosnap = 10;
                return;
 
        case DLT_JUNIPER_ATM2:
-               off_linktype = 8; /* in reality variable between 8-12 */
-               off_nl = 8;
-               off_nl_nosnap = 18;
+               off_linktype = 8;       /* in reality variable between 8-12 */
+               off_macpl = 8;  /* in reality variable between 8-12 */
+               off_nl = 0;
+               off_nl_nosnap = 10;
                return;
 
                /* frames captured on a Juniper PPPoE service PIC
                 * contain raw ethernet frames */
        case DLT_JUNIPER_PPPOE:
         case DLT_JUNIPER_ETHER:
+               off_macpl = 14;
                off_linktype = 16;
                off_nl = 18;            /* Ethernet II */
                off_nl_nosnap = 21;     /* 802.3+802.2 */
@@ -1222,48 +1258,56 @@ init_linktype(p)
 
        case DLT_JUNIPER_PPPOE_ATM:
                off_linktype = 4;
-               off_nl = 6;
-               off_nl_nosnap = -1;      /* no 802.2 LLC */
+               off_macpl = 6;
+               off_nl = 0;
+               off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_GGSN:
                off_linktype = 6;
-               off_nl = 12;
-               off_nl_nosnap = -1;      /* no 802.2 LLC */
+               off_macpl = 12;
+               off_nl = 0;
+               off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_ES:
                off_linktype = 6;
-               off_nl = -1;            /* not really a network layer but raw IP adresses */
+               off_macpl = -1;         /* not really a network layer but raw IP addresses */
+               off_nl = -1;            /* not really a network layer but raw IP addresses */
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_MONITOR:
                off_linktype = 12;
-               off_nl = 12;            /* raw IP/IP6 header */
+               off_macpl = 12;
+               off_nl = 0;             /* raw IP/IP6 header */
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_SERVICES:
                off_linktype = 12;
+               off_macpl = -1;         /* L3 proto location dep. on cookie type */
                off_nl = -1;            /* L3 proto location dep. on cookie type */
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_VP:
                off_linktype = 18;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
 
        case DLT_JUNIPER_ST:
                off_linktype = 18;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
 
        case DLT_JUNIPER_ISM:
                off_linktype = 8;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1275,6 +1319,7 @@ init_linktype(p)
                off_dpc = 4;
                off_sls = 7;
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1286,6 +1331,7 @@ init_linktype(p)
                off_dpc = 8;
                off_sls = 11;
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1297,6 +1343,7 @@ init_linktype(p)
                off_dpc = 24;
                off_sls = 27;
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1304,8 +1351,9 @@ init_linktype(p)
 #ifdef DLT_PFSYNC
        case DLT_PFSYNC:
                off_linktype = -1;
-               off_nl = 4;
-               off_nl_nosnap = 4;
+               off_macpl = 4;
+               off_nl = 0;
+               off_nl_nosnap = 0;
                return;
 #endif
 
@@ -1314,6 +1362,7 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1323,6 +1372,7 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1332,6 +1382,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;
@@ -1341,6 +1392,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;
@@ -1350,6 +1402,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;
@@ -1359,6 +1412,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;
@@ -1368,6 +1422,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;
@@ -1377,6 +1432,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;
@@ -1386,6 +1442,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;
@@ -1395,6 +1452,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;
@@ -1404,6 +1462,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;
@@ -1413,6 +1472,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;
@@ -1422,10 +1482,41 @@ init_linktype(p)
                 * 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;
+
+       case DLT_MPLS:
+               /*
+                * 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_MMAPPED:
+               /*
+                * Currently, only raw "link[N:M]" filtering is supported.
+                */
+               off_linktype = -1;
+               off_macpl = -1;
+               off_nl = -1;
+               off_nl_nosnap = -1;
+               return;
        }
        bpf_error("unknown data link type %d", linktype);
        /* NOTREACHED */
@@ -1476,6 +1567,46 @@ 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.
  */
@@ -1497,12 +1628,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:
@@ -1515,21 +1650,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:
@@ -1549,12 +1685,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
@@ -1572,22 +1711,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;
 }
@@ -1661,7 +1802,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;
@@ -1699,17 +1840,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, off_linktype + 2);
+               b0 = gen_snap(0x000000, ETHERTYPE_IPX);
                gen_or(b0, b1);
 
                /*
@@ -1764,11 +1903,9 @@ gen_ether_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);
 
                /*
@@ -1845,7 +1982,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;
@@ -1876,10 +2013,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);
@@ -1927,11 +2062,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);
 
                /*
@@ -1955,7 +2088,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;
@@ -1975,18 +2108,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;
 
        /*
-        * 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.
+        * This code is not compatible with the optimizer, as
+        * we are generating jmp instructions within a normal
+        * slist of instructions
         */
-       if (reg_ll_size != -1) {
+       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;
+
+       /*
+        * Generate code to load the length of the radiotap header into
+        * the register assigned to hold that length, if one has been
+        * assigned.  (If one hasn't been assigned, no code we've
+        * generated uses that prefix, so we don't need to generate any
+        * code to load it.)
+        */
+       if (reg_off_ll != -1) {
                /*
                 * The 2 bytes at offsets of 2 and 3 from the beginning
                 * of the radiotap header are the length of the radiotap
@@ -2021,7 +2305,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);
 
                /*
@@ -2030,13 +2314,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);
 }
 
 /* 
@@ -2045,21 +2325,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
@@ -2093,7 +2373,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);
 
                /*
@@ -2102,16 +2382,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);
+
                /*
-                * Now append all the existing statements in this
-                * block to these statements.
+                * If not, skip all of this.
                 */
-               sappend(s1, b->stmts);
-               b->stmts = s1;
+               sjset_radiotap_flags->s.jf = snext;
+
+               /*
+                * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set?
+                */
+               sjset_radiotap_tsft = sjset_radiotap_flags->s.jt =
+                   new_stmt(JMP(BPF_JSET));
+               sjset_radiotap_tsft->s.k = SWAPLONG(0x00000001);
+               sappend(s, sjset_radiotap_tsft);
+
+               /*
+                * If IEEE80211_RADIOTAP_TSFT is set, the flags field is
+                * at an offset of 16 from the beginning of the raw packet
+                * data (8 bytes for the radiotap header and 8 bytes for
+                * the TSFT field).
+                *
+                * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+                * is set.
+                */
+               sjset_radiotap_tsft->s.jt = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B);
+               s2->s.k = 16;
+               sappend(s, s2);
+
+               sjset_tsft_datapad = new_stmt(JMP(BPF_JSET));
+               sjset_tsft_datapad->s.k = 0x20;
+               sappend(s, sjset_tsft_datapad);
+
+               /*
+                * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is
+                * at an offset of 8 from the beginning of the raw packet
+                * data (8 bytes for the radiotap header).
+                *
+                * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+                * is set.
+                */
+               sjset_radiotap_tsft->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B);
+               s2->s.k = 8;
+               sappend(s, s2);
+
+               sjset_notsft_datapad = new_stmt(JMP(BPF_JSET));
+               sjset_notsft_datapad->s.k = 0x20;
+               sappend(s, sjset_notsft_datapad);
+
+               /*
+                * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is
+                * set, round the length of the 802.11 header to
+                * a multiple of 4.  Do that by adding 3 and then
+                * dividing by and multiplying by 4, which we do by
+                * ANDing with ~3.
+                */
+               s_roundup = new_stmt(BPF_LD|BPF_MEM);
+               s_roundup->s.k = reg_off_macpl;
+               sappend(s, s_roundup);
+               s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM);
+               s2->s.k = 3;
+               sappend(s, s2);
+               s2 = new_stmt(BPF_ALU|BPF_AND|BPF_IMM);
+               s2->s.k = ~3;
+               sappend(s, s2);
+               s2 = new_stmt(BPF_ST);
+               s2->s.k = reg_off_macpl;
+               sappend(s, s2);
+
+               sjset_tsft_datapad->s.jt = s_roundup;
+               sjset_tsft_datapad->s.jf = snext;
+               sjset_notsft_datapad->s.jt = s_roundup;
+               sjset_notsft_datapad->s.jf = snext;
+       } else
+               sjset_qos->s.jf = snext;
+
+       return s;
+}
+
+static void
+insert_compute_vloffsets(b)
+       struct block *b;
+{
+       struct slist *s;
+
+       /*
+        * For link-layer types that have a variable-length header
+        * preceding the link-layer header, generate code to load
+        * the offset of the link-layer header into the register
+        * assigned to that offset, if any.
+        */
+       switch (linktype) {
+
+       case DLT_PRISM_HEADER:
+               s = gen_load_prism_llprefixlen();
+               break;
+
+       case DLT_IEEE802_11_RADIO_AVS:
+               s = gen_load_avs_llprefixlen();
+               break;
+
+       case DLT_IEEE802_11_RADIO:
+               s = gen_load_radiotap_llprefixlen();
+               break;
+
+       case DLT_PPI:
+               s = gen_load_ppi_llprefixlen();
+               break;
+
+       default:
+               s = NULL;
+               break;
+       }
 
+       /*
+        * For link-layer types that have a variable-length link-layer
+        * header, generate code to load the offset of the MAC-layer
+        * payload into the register assigned to that offset, if any.
+        */
+       switch (linktype) {
+
+       case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
+       case DLT_PPI:
+               s = gen_load_802_11_header_len(s, b->stmts);
+               break;
+       }
+
+       /*
+        * If we have any offset-loading code, append all the
+        * existing statements in the block to those statements,
+        * and make the resulting list the list of statements
+        * for the block.
+        */
+       if (s != NULL) {
+               sappend(s, b->stmts);
+               b->stmts = s;
        }
 }
-       
+
 static struct block *
 gen_ppi_dlt_check(void)
 {
@@ -2138,42 +2697,61 @@ gen_ppi_dlt_check(void)
        return b;
 }
 
-static void
-insert_load_llprefixlen(b)
-       struct block *b;
+static struct slist *
+gen_prism_llprefixlen(void)
 {
-       switch (linktype) {
+       struct slist *s;
 
-       /* 
-        * 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.
+       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.
         */
-       case DLT_PPI:
-               insert_ppi_load_llprefixlen(b);
-               break;
+       s = new_stmt(BPF_LDX|BPF_MEM);
+       s->s.k = reg_off_ll;
+       return s;
+}
 
-       case DLT_IEEE802_11_RADIO:
-               insert_radiotap_load_llprefixlen(b);
-               break;
+static struct slist *
+gen_avs_llprefixlen(void)
+{
+       struct slist *s;
+
+       if (reg_off_ll == -1) {
+               /*
+                * We haven't yet assigned a register for the length
+                * of the AVS header; allocate one.
+                */
+               reg_off_ll = alloc_reg();
        }
-}
 
+       /*
+        * Load the register containing the AVS length
+        * into the X register.
+        */
+       s = new_stmt(BPF_LDX|BPF_MEM);
+       s->s.k = reg_off_ll;
+       return s;
+}
 
 static struct slist *
 gen_radiotap_llprefixlen(void)
 {
        struct slist *s;
 
-       if (reg_ll_size == -1) {
+       if (reg_off_ll == -1) {
                /*
                 * We haven't yet assigned a register for the length
                 * of the radiotap header; allocate one.
                 */
-               reg_ll_size = alloc_reg();
+               reg_off_ll = alloc_reg();
        }
 
        /*
@@ -2181,7 +2759,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;
 }
 
@@ -2198,25 +2776,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
@@ -2228,16 +2804,107 @@ 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 DLT_IEEE802_11_RADIO:
-               return gen_radiotap_llprefixlen();
+       case LLCSAP_ISONS:
+               proto = PPP_OSI;
+               break;
 
-       default:
-               return NULL;
+       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);
 }
 
 /*
@@ -2272,6 +2939,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:
@@ -2294,13 +2980,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:
@@ -2385,47 +3099,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:
@@ -2436,6 +3112,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);
@@ -2443,42 +3123,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:
@@ -2667,6 +3317,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:
@@ -2700,9 +3353,50 @@ 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:
+       case DLT_USB_LINUX_MMAPPED:
+               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");
        }
@@ -2722,12 +3416,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);
 }
@@ -2740,10 +3429,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];
 
@@ -2755,7 +3443,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);
 }
 
 /*
@@ -2788,7 +3476,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:
@@ -2796,7 +3484,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:
@@ -2809,7 +3497,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:
                /*
@@ -2821,8 +3509,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
@@ -2837,15 +3524,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);
                }
        }
 }
@@ -3054,7 +3739,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)
@@ -3064,6 +3750,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:
                /*
@@ -3161,7 +3857,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;
@@ -3330,6 +4026,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);
@@ -3783,10 +4528,10 @@ gen_gateway(eaddr, alist, proto, dir)
                        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:
+               case DLT_PPI:
                        b0 = gen_wlanhostop(eaddr, Q_OR);
                        break;
                case DLT_SUNATM:
@@ -4578,7 +5323,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
@@ -4587,11 +5333,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 */
 
@@ -4610,11 +5360,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
@@ -4623,7 +5373,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);
@@ -4703,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++;
                /* MEM[reg2] = A */
                s[i] = new_stmt(BPF_ST);
@@ -4721,7 +5471,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);
@@ -4780,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++;
        /* MEM[reg2] = A */
        s[i] = new_stmt(BPF_ST);
@@ -4798,7 +5548,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);
@@ -4852,6 +5602,32 @@ 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
  * <proto> and whether the type field in that protocol's header has
@@ -5138,9 +5914,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)
@@ -5369,7 +6145,6 @@ gen_scode(name, q)
                else
                        bpf_error("unknown protocol: %s", name);
 
-
        case Q_UNDEF:
                syntax();
                /* NOTREACHED */
@@ -5614,9 +6389,9 @@ gen_ecode(eaddr, q)
                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_PRISM_HEADER:
                case DLT_PPI:
                        return gen_wlanhostop(eaddr, (int)q.dir);
                case DLT_SUNATM:
@@ -5810,14 +6585,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".
                 */
@@ -5831,13 +6606,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);
 
@@ -5878,22 +6657,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);
 
                /*
@@ -6211,10 +6992,10 @@ gen_broadcast(proto)
                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:
-               case DLT_PRISM_HEADER:
                        return gen_wlanhostop(ebroadcast, Q_DST);
                case DLT_IP_OVER_FC:
                        return gen_ipfchostop(ebroadcast, Q_DST);
@@ -6307,10 +7088,10 @@ gen_multicast(proto)
                        /* 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_PPI:
                case DLT_IEEE802_11_RADIO:
-               case DLT_PRISM_HEADER:
+               case DLT_PPI:
                        /*
                         * Oh, yuk.
                         *
@@ -6744,6 +7525,31 @@ gen_p80211_type(int type, int mask)
                bpf_error("802.11 link-layer types supported only on 802.11");
                /* NOTREACHED */
        }
+
+       return (b0);
+}
+
+struct block *
+gen_p80211_fcdir(int fcdir)
+{
+       struct block *b0;
+
+       switch (linktype) {
+
+       case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
+               break;
+
+       default:
+               bpf_error("frame direction supported only with 802.11 headers");
+               /* NOTREACHED */
+       }
+
+       b0 = gen_mcmp(OR_LINK, 1, BPF_B, (bpf_int32)fcdir,
+               (bpf_u_int32)IEEE80211_FC1_DIR_MASK);
+
        return (b0);
 }
 
@@ -6820,10 +7626,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
@@ -6849,15 +7656,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:
@@ -6866,17 +7687,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);
 }
 
@@ -6902,7 +7712,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,
@@ -6937,7 +7747,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;
@@ -6971,7 +7781,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
@@ -6999,24 +7810,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;
 }
@@ -7162,8 +7977,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: