]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
Propagate from the main branch:
[libpcap] / gencode.c
index 1eafbafb36d6a5cee4983bf471b7a13520403d31..81da02ef76d26ac90b0ba96c1c30fe6b0ed8e389 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.221.2.24 2005-06-20 21:52:53 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.41 2006-09-13 07:02:15 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -100,8 +100,8 @@ static const char rcsid[] _U_ =
 static jmp_buf top_ctx;
 static pcap_t *bpf_pcap;
 
-/* Hack for updating VLAN, MPLS offsets. */
-static u_int   orig_linktype = -1U, orig_nl = -1U;
+/* Hack for updating VLAN, MPLS, and PPPoE offsets. */
+static u_int   orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;
 
 /* XXX */
 #ifdef PCAP_FDDIPAD
@@ -205,9 +205,10 @@ static struct block *gen_thostop(const u_char *, int);
 static struct block *gen_wlanhostop(const u_char *, int);
 static struct block *gen_ipfchostop(const u_char *, int);
 static struct block *gen_dnhostop(bpf_u_int32, int);
-static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int);
+static struct block *gen_mpls_linktype(int);
+static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int, int);
 #ifdef INET6
-static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int);
+static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int, int);
 #endif
 #ifndef INET6
 static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int);
@@ -667,20 +668,26 @@ gen_ncmp(offrel, offset, size, mask, jtype, reverse, v)
 static int reg_ll_size;
 
 /*
- * This is the offset of the beginning of the link-layer header.
+ * This is the offset of the beginning of the link-layer header from
+ * the beginning of the raw packet data.
+ *
  * It's usually 0, except for 802.11 with a fixed-length radio header.
+ * (For 802.11 with a variable-length radio header, we have to generate
+ * code to compute that offset; off_ll is 0 in that case.)
  */
 static u_int off_ll;
 
 /*
  * This is the offset of the beginning of the MAC-layer header.
- * It's usually 0, except for ATM LANE.
+ * 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;
 
 /*
  * "off_linktype" is the offset to information in the link-layer header
- * giving the packet type.
+ * giving the packet type.  This offset is relative to the beginning
+ * of the link-layer header (i.e., it doesn't include off_ll).
  *
  * For Ethernet, it's the offset of the Ethernet type field.
  *
@@ -733,6 +740,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).
  *
  * If the link layer never uses 802.2 LLC:
  *
@@ -778,6 +787,9 @@ init_linktype(p)
        off_proto = -1;
        off_payload = -1;
 
+       /*
+        * And assume we're not doing SS7.
+        */
        off_sio = -1;
        off_opc = -1;
        off_dpc = -1;
@@ -790,6 +802,7 @@ init_linktype(p)
 
        orig_linktype = -1;
        orig_nl = -1;
+        label_stack_depth = 0;
 
        reg_ll_size = -1;
 
@@ -951,9 +964,9 @@ init_linktype(p)
                 * the Prism header is fixed-length.
                 */
                off_ll = 144;
-               off_linktype = 144+24;
-               off_nl = 144+32;        /* Prism+802.11+802.2+SNAP */
-               off_nl_nosnap = 144+27; /* Prism+802.11+802.2 */
+               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:
@@ -969,12 +982,23 @@ init_linktype(p)
                 * 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.
+                * 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 = 64+24;
-               off_nl = 64+32;         /* Radio+802.11+802.2+SNAP */
-               off_nl_nosnap = 64+27;  /* Radio+802.11+802.2 */
+               off_linktype = 24;
+               off_nl = 32;            /* Radio+802.11+802.2+SNAP */
+               off_nl_nosnap = 27;     /* Radio+802.11+802.2 */
                return;
 
        case DLT_IEEE802_11_RADIO:
@@ -1076,6 +1100,17 @@ init_linktype(p)
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
+                /*
+                 * the only BPF-interesting FRF.16 frames are non-control frames;
+                 * Frame Relay has a variable length link-layer
+                 * so lets start with offset 4 for now and increments later on (FIXME);
+                 */
+       case DLT_MFR:
+               off_linktype = -1;
+               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;
@@ -1113,8 +1148,12 @@ init_linktype(p)
                off_nl_nosnap = PFLOG_HDRLEN;   /* no 802.2 LLC */
                return;
 
+        case DLT_JUNIPER_MFR:
         case DLT_JUNIPER_MLFR:
         case DLT_JUNIPER_MLPPP:
+        case DLT_JUNIPER_PPP:
+        case DLT_JUNIPER_CHDLC:
+        case DLT_JUNIPER_FRELAY:
                 off_linktype = 4;
                off_nl = 4;
                off_nl_nosnap = -1;     /* no 802.2 LLC */
@@ -1135,6 +1174,7 @@ init_linktype(p)
                /* frames captured on a Juniper PPPoE service PIC
                 * contain raw ethernet frames */
        case DLT_JUNIPER_PPPOE:
+        case DLT_JUNIPER_ETHER:
                off_linktype = 16;
                off_nl = 18;            /* Ethernet II */
                off_nl_nosnap = 21;     /* 802.3+802.2 */
@@ -1219,6 +1259,9 @@ gen_load_llrel(offset, size)
         * 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) {
                s2 = new_stmt(BPF_LD|BPF_IND|size);
@@ -1226,7 +1269,7 @@ gen_load_llrel(offset, size)
                sappend(s, s2);
        } else {
                s = new_stmt(BPF_LD|BPF_ABS|size);
-               s->s.k = offset;
+               s->s.k = offset + off_ll;
        }
        return s;
 }
@@ -1244,11 +1287,12 @@ gen_load_a(offrel, offset, size)
        switch (offrel) {
 
        case OR_PACKET:
-               s = gen_load_llrel(offset, size);
+                s = new_stmt(BPF_LD|BPF_ABS|size);
+                s->s.k = offset;
                break;
 
        case OR_LINK:
-               s = gen_load_llrel(off_ll + offset, size);
+               s = gen_load_llrel(offset, size);
                break;
 
        case OR_NET:
@@ -1851,6 +1895,25 @@ gen_linktype(proto)
 {
        struct block *b0, *b1, *b2;
 
+       /* are we checking MPLS-encapsulated packets? */
+       if (label_stack_depth > 0) {
+               switch (proto) {
+               case ETHERTYPE_IP:
+               case PPP_IP:
+               /* FIXME add other L3 proto IDs */
+                       return gen_mpls_linktype(Q_IP); 
+
+               case ETHERTYPE_IPV6:
+               case PPP_IPV6:
+               /* FIXME add other L3 proto IDs */
+                       return gen_mpls_linktype(Q_IPV6); 
+
+               default:
+                       bpf_error("unsupported protocol over mpls");
+                       /* NOTREACHED */
+               }
+       }
+
        switch (linktype) {
 
        case DLT_EN10MB:
@@ -2240,6 +2303,7 @@ gen_linktype(proto)
                /*NOTREACHED*/
                break;
 
+        case DLT_JUNIPER_MFR:
         case DLT_JUNIPER_MLFR:
         case DLT_JUNIPER_MLPPP:
        case DLT_JUNIPER_ATM1:
@@ -2250,6 +2314,10 @@ gen_linktype(proto)
         case DLT_JUNIPER_ES:
         case DLT_JUNIPER_MONITOR:
         case DLT_JUNIPER_SERVICES:
+        case DLT_JUNIPER_ETHER:
+        case DLT_JUNIPER_PPP:
+        case DLT_JUNIPER_FRELAY:
+        case DLT_JUNIPER_CHDLC:
                /* just lets verify the magic number for now -
                 * on ATM we may have up to 6 different encapsulations on the wire
                 * and need a lot of heuristics to figure out that the payload
@@ -3034,24 +3102,69 @@ gen_dnhostop(addr, dir)
        return b1;
 }
 
+/*
+ * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets;
+ * test the bottom-of-stack bit, and then check the version number
+ * field in the IP header.
+ */
 static struct block *
-gen_host(addr, mask, proto, dir)
+gen_mpls_linktype(proto)
+       int proto;
+{
+       struct block *b0, *b1;
+
+        switch (proto) {
+
+        case Q_IP:
+                /* match the bottom-of-stack bit */
+                b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01);
+                /* match the IPv4 version number */
+                b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x40, 0xf0);
+                gen_and(b0, b1);
+                return b1;
+       case Q_IPV6:
+                /* match the bottom-of-stack bit */
+                b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01);
+                /* match the IPv4 version number */
+                b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x60, 0xf0);
+                gen_and(b0, b1);
+                return b1;
+       default:
+                abort();
+        }
+}
+
+static struct block *
+gen_host(addr, mask, proto, dir, type)
        bpf_u_int32 addr;
        bpf_u_int32 mask;
        int proto;
        int dir;
+       int type;
 {
        struct block *b0, *b1;
+       const char *typestr;
+
+       if (type == Q_NET)
+               typestr = "net";
+       else
+               typestr = "host";
 
        switch (proto) {
 
        case Q_DEFAULT:
-               b0 = gen_host(addr, mask, Q_IP, dir);
-               if (off_linktype != (u_int)-1) {
-                   b1 = gen_host(addr, mask, Q_ARP, dir);
-                   gen_or(b0, b1);
-                   b0 = gen_host(addr, mask, Q_RARP, dir);
-                   gen_or(b1, b0);
+               b0 = gen_host(addr, mask, Q_IP, dir, type);
+               /*
+                * Only check for non-IPv4 addresses if we're not
+                * checking MPLS-encapsulated packets.
+                */
+               if (label_stack_depth == 0) {
+                       b1 = gen_host(addr, mask, Q_ARP, dir, type);
+                       gen_or(b0, b1);
+                       b0 = gen_host(addr, mask, Q_RARP, dir, type);
+                       gen_or(b1, b0);
                }
                return b0;
 
@@ -3065,28 +3178,28 @@ gen_host(addr, mask, proto, dir)
                return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, 14, 24);
 
        case Q_TCP:
-               bpf_error("'tcp' modifier applied to host");
+               bpf_error("'tcp' modifier applied to %s", typestr);
 
        case Q_SCTP:
-               bpf_error("'sctp' modifier applied to host");
+               bpf_error("'sctp' modifier applied to %s", typestr);
 
        case Q_UDP:
-               bpf_error("'udp' modifier applied to host");
+               bpf_error("'udp' modifier applied to %s", typestr);
 
        case Q_ICMP:
-               bpf_error("'icmp' modifier applied to host");
+               bpf_error("'icmp' modifier applied to %s", typestr);
 
        case Q_IGMP:
-               bpf_error("'igmp' modifier applied to host");
+               bpf_error("'igmp' modifier applied to %s", typestr);
 
        case Q_IGRP:
-               bpf_error("'igrp' modifier applied to host");
+               bpf_error("'igrp' modifier applied to %s", typestr);
 
        case Q_PIM:
-               bpf_error("'pim' modifier applied to host");
+               bpf_error("'pim' modifier applied to %s", typestr);
 
        case Q_VRRP:
-               bpf_error("'vrrp' modifier applied to host");
+               bpf_error("'vrrp' modifier applied to %s", typestr);
 
        case Q_ATALK:
                bpf_error("ATALK host filtering not implemented");
@@ -3114,38 +3227,38 @@ gen_host(addr, mask, proto, dir)
                bpf_error("'ip6' modifier applied to ip host");
 
        case Q_ICMPV6:
-               bpf_error("'icmp6' modifier applied to host");
+               bpf_error("'icmp6' modifier applied to %s", typestr);
 #endif /* INET6 */
 
        case Q_AH:
-               bpf_error("'ah' modifier applied to host");
+               bpf_error("'ah' modifier applied to %s", typestr);
 
        case Q_ESP:
-               bpf_error("'esp' modifier applied to host");
+               bpf_error("'esp' modifier applied to %s", typestr);
 
        case Q_ISO:
                bpf_error("ISO host filtering not implemented");
 
        case Q_ESIS:
-               bpf_error("'esis' modifier applied to host");
+               bpf_error("'esis' modifier applied to %s", typestr);
 
        case Q_ISIS:
-               bpf_error("'isis' modifier applied to host");
+               bpf_error("'isis' modifier applied to %s", typestr);
 
        case Q_CLNP:
-               bpf_error("'clnp' modifier applied to host");
+               bpf_error("'clnp' modifier applied to %s", typestr);
 
        case Q_STP:
-               bpf_error("'stp' modifier applied to host");
+               bpf_error("'stp' modifier applied to %s", typestr);
 
        case Q_IPX:
                bpf_error("IPX host filtering not implemented");
 
        case Q_NETBEUI:
-               bpf_error("'netbeui' modifier applied to host");
+               bpf_error("'netbeui' modifier applied to %s", typestr);
 
        case Q_RADIO:
-               bpf_error("'radio' modifier applied to host");
+               bpf_error("'radio' modifier applied to %s", typestr);
 
        default:
                abort();
@@ -3155,49 +3268,57 @@ gen_host(addr, mask, proto, dir)
 
 #ifdef INET6
 static struct block *
-gen_host6(addr, mask, proto, dir)
+gen_host6(addr, mask, proto, dir, type)
        struct in6_addr *addr;
        struct in6_addr *mask;
        int proto;
        int dir;
+       int type;
 {
+       const char *typestr;
+
+       if (type == Q_NET)
+               typestr = "net";
+       else
+               typestr = "host";
+
        switch (proto) {
 
        case Q_DEFAULT:
-               return gen_host6(addr, mask, Q_IPV6, dir);
+               return gen_host6(addr, mask, Q_IPV6, dir, type);
 
        case Q_IP:
-               bpf_error("'ip' modifier applied to ip6 host");
+               bpf_error("'ip' modifier applied to ip6 %s", typestr);
 
        case Q_RARP:
-               bpf_error("'rarp' modifier applied to ip6 host");
+               bpf_error("'rarp' modifier applied to ip6 %s", typestr);
 
        case Q_ARP:
-               bpf_error("'arp' modifier applied to ip6 host");
+               bpf_error("'arp' modifier applied to ip6 %s", typestr);
 
        case Q_SCTP:
-               bpf_error("'sctp' modifier applied to host");
+               bpf_error("'sctp' modifier applied to %s", typestr);
 
        case Q_TCP:
-               bpf_error("'tcp' modifier applied to host");
+               bpf_error("'tcp' modifier applied to %s", typestr);
 
        case Q_UDP:
-               bpf_error("'udp' modifier applied to host");
+               bpf_error("'udp' modifier applied to %s", typestr);
 
        case Q_ICMP:
-               bpf_error("'icmp' modifier applied to host");
+               bpf_error("'icmp' modifier applied to %s", typestr);
 
        case Q_IGMP:
-               bpf_error("'igmp' modifier applied to host");
+               bpf_error("'igmp' modifier applied to %s", typestr);
 
        case Q_IGRP:
-               bpf_error("'igrp' modifier applied to host");
+               bpf_error("'igrp' modifier applied to %s", typestr);
 
        case Q_PIM:
-               bpf_error("'pim' modifier applied to host");
+               bpf_error("'pim' modifier applied to %s", typestr);
 
        case Q_VRRP:
-               bpf_error("'vrrp' modifier applied to host");
+               bpf_error("'vrrp' modifier applied to %s", typestr);
 
        case Q_ATALK:
                bpf_error("ATALK host filtering not implemented");
@@ -3206,7 +3327,7 @@ gen_host6(addr, mask, proto, dir)
                bpf_error("AARP host filtering not implemented");
 
        case Q_DECNET:
-               bpf_error("'decnet' modifier applied to ip6 host");
+               bpf_error("'decnet' modifier applied to ip6 %s", typestr);
 
        case Q_SCA:
                bpf_error("SCA host filtering not implemented");
@@ -3224,37 +3345,37 @@ gen_host6(addr, mask, proto, dir)
                return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6, 8, 24);
 
        case Q_ICMPV6:
-               bpf_error("'icmp6' modifier applied to host");
+               bpf_error("'icmp6' modifier applied to %s", typestr);
 
        case Q_AH:
-               bpf_error("'ah' modifier applied to host");
+               bpf_error("'ah' modifier applied to %s", typestr);
 
        case Q_ESP:
-               bpf_error("'esp' modifier applied to host");
+               bpf_error("'esp' modifier applied to %s", typestr);
 
        case Q_ISO:
                bpf_error("ISO host filtering not implemented");
 
        case Q_ESIS:
-               bpf_error("'esis' modifier applied to host");
+               bpf_error("'esis' modifier applied to %s", typestr);
 
        case Q_ISIS:
-               bpf_error("'isis' modifier applied to host");
+               bpf_error("'isis' modifier applied to %s", typestr);
 
        case Q_CLNP:
-               bpf_error("'clnp' modifier applied to host");
+               bpf_error("'clnp' modifier applied to %s", typestr);
 
        case Q_STP:
-               bpf_error("'stp' modifier applied to host");
+               bpf_error("'stp' modifier applied to %s", typestr);
 
        case Q_IPX:
                bpf_error("IPX host filtering not implemented");
 
        case Q_NETBEUI:
-               bpf_error("'netbeui' modifier applied to host");
+               bpf_error("'netbeui' modifier applied to %s", typestr);
 
        case Q_RADIO:
-               bpf_error("'radio' modifier applied to host");
+               bpf_error("'radio' modifier applied to %s", typestr);
 
        default:
                abort();
@@ -3281,18 +3402,24 @@ gen_gateway(eaddr, alist, proto, dir)
        case Q_IP:
        case Q_ARP:
        case Q_RARP:
-               if (linktype == DLT_EN10MB)
-                       b0 = gen_ehostop(eaddr, Q_OR);
-               else if (linktype == DLT_FDDI)
-                       b0 = gen_fhostop(eaddr, Q_OR);
-               else if (linktype == DLT_IEEE802)
-                       b0 = gen_thostop(eaddr, Q_OR);
-               else if (linktype == DLT_IEEE802_11 ||
-                   linktype == DLT_IEEE802_11_RADIO_AVS ||
-                   linktype == DLT_IEEE802_11_RADIO ||
-                   linktype == DLT_PRISM_HEADER)
-                       b0 = gen_wlanhostop(eaddr, Q_OR);
-               else if (linktype == DLT_SUNATM && is_lane) {
+                switch (linktype) {
+                case DLT_EN10MB:
+                    b0 = gen_ehostop(eaddr, Q_OR);
+                    break;
+                case DLT_FDDI:
+                    b0 = gen_fhostop(eaddr, Q_OR);
+                    break;
+               case DLT_IEEE802:
+                    b0 = gen_thostop(eaddr, Q_OR);
+                    break;
+               case DLT_IEEE802_11:
+               case DLT_IEEE802_11_RADIO_AVS:
+               case DLT_IEEE802_11_RADIO:
+               case DLT_PRISM_HEADER:
+                    b0 = gen_wlanhostop(eaddr, Q_OR);
+                    break;
+                case DLT_SUNATM:
+                    if (is_lane) {
                        /*
                         * Check that the packet doesn't begin with an
                         * LE Control marker.  (We've already generated
@@ -3307,15 +3434,19 @@ gen_gateway(eaddr, alist, proto, dir)
                         */
                        b0 = gen_ehostop(eaddr, Q_OR);
                        gen_and(b1, b0);
-               } else if (linktype == DLT_IP_OVER_FC)
-                       b0 = gen_ipfchostop(eaddr, Q_OR);
-               else
-                       bpf_error(
+                    }
+                    break;
+               case DLT_IP_OVER_FC:
+                    b0 = gen_ipfchostop(eaddr, Q_OR);
+                    break;
+                default:
+                    bpf_error(
                            "'gateway' supported only on ethernet/FDDI/token ring/802.11/Fibre Channel");
-
-               b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR);
+                }
+               b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR, Q_HOST);
                while (*alist) {
-                       tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR);
+                       tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR,
+                           Q_HOST);
                        gen_or(b1, tmp);
                        b1 = tmp;
                }
@@ -4393,6 +4524,7 @@ gen_proto(v, proto, dir)
                 *
                 * So we always check for ETHERTYPE_IP.
                 */
+
                b0 = gen_linktype(ETHERTYPE_IP);
 #ifndef CHASE_CHAIN
                b1 = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)v);
@@ -4598,7 +4730,7 @@ gen_scode(name, q)
                        addr <<= 8;
                        mask <<= 8;
                }
-               return gen_host(addr, mask, proto, dir);
+               return gen_host(addr, mask, proto, dir, q.addr);
 
        case Q_DEFAULT:
        case Q_HOST:
@@ -4683,7 +4815,7 @@ gen_scode(name, q)
                         * I don't think DECNET hosts can be multihomed, so
                         * there is no need to build up a list of addresses
                         */
-                       return (gen_host(dn_addr, 0, proto, dir));
+                       return (gen_host(dn_addr, 0, proto, dir, q.addr));
                } else {
 #ifndef INET6
                        alist = pcap_nametoaddr(name);
@@ -4692,10 +4824,10 @@ gen_scode(name, q)
                        tproto = proto;
                        if (off_linktype == (u_int)-1 && tproto == Q_DEFAULT)
                                tproto = Q_IP;
-                       b = gen_host(**alist++, 0xffffffff, tproto, dir);
+                       b = gen_host(**alist++, 0xffffffff, tproto, dir, q.addr);
                        while (*alist) {
                                tmp = gen_host(**alist++, 0xffffffff,
-                                              tproto, dir);
+                                              tproto, dir, q.addr);
                                gen_or(b, tmp);
                                b = tmp;
                        }
@@ -4720,7 +4852,7 @@ gen_scode(name, q)
                                        sin = (struct sockaddr_in *)
                                                res->ai_addr;
                                        tmp = gen_host(ntohl(sin->sin_addr.s_addr),
-                                               0xffffffff, tproto, dir);
+                                               0xffffffff, tproto, dir, q.addr);
                                        break;
                                case AF_INET6:
                                        if (tproto6 == Q_IP)
@@ -4729,7 +4861,7 @@ gen_scode(name, q)
                                        sin6 = (struct sockaddr_in6 *)
                                                res->ai_addr;
                                        tmp = gen_host6(&sin6->sin6_addr,
-                                               &mask128, tproto6, dir);
+                                               &mask128, tproto6, dir, q.addr);
                                        break;
                                default:
                                        continue;
@@ -4902,7 +5034,14 @@ gen_mcode(s1, s2, masklen, q)
                /* Convert mask len to mask */
                if (masklen > 32)
                        bpf_error("mask length must be <= 32");
-               m = 0xffffffff << (32 - masklen);
+               if (masklen == 0) {
+                       /*
+                        * X << 32 is not guaranteed by C to be 0; it's
+                        * undefined.
+                        */
+                       m = 0;
+               } else
+                       m = 0xffffffff << (32 - masklen);
                if ((n & ~m) != 0)
                        bpf_error("non-network bits set in \"%s/%d\"",
                            s1, masklen);
@@ -4911,7 +5050,7 @@ gen_mcode(s1, s2, masklen, q)
        switch (q.addr) {
 
        case Q_NET:
-               return gen_host(n, m, q.proto, q.dir);
+               return gen_host(n, m, q.proto, q.dir, q.addr);
 
        default:
                bpf_error("Mask syntax for networks only");
@@ -4944,7 +5083,7 @@ gen_ncode(s, v, q)
        case Q_HOST:
        case Q_NET:
                if (proto == Q_DECNET)
-                       return gen_host(v, 0, proto, dir);
+                       return gen_host(v, 0, proto, dir, q.addr);
                else if (proto == Q_LINK) {
                        bpf_error("illegal link layer address");
                } else {
@@ -4960,7 +5099,7 @@ gen_ncode(s, v, q)
                                v <<= 32 - vlen;
                                mask <<= 32 - vlen;
                        }
-                       return gen_host(v, mask, proto, dir);
+                       return gen_host(v, mask, proto, dir, q.addr);
                }
 
        case Q_PORT:
@@ -5078,7 +5217,7 @@ gen_mcode6(s1, s2, masklen, q)
                /* FALLTHROUGH */
 
        case Q_NET:
-               b = gen_host6(addr, &mask, q.proto, q.dir);
+               b = gen_host6(addr, &mask, q.proto, q.dir, q.addr);
                freeaddrinfo(res);
                return b;
 
@@ -5097,18 +5236,20 @@ gen_ecode(eaddr, q)
        struct block *b, *tmp;
 
        if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
-               if (linktype == DLT_EN10MB)
-                       return gen_ehostop(eaddr, (int)q.dir);
-               if (linktype == DLT_FDDI)
-                       return gen_fhostop(eaddr, (int)q.dir);
-               if (linktype == DLT_IEEE802)
-                       return gen_thostop(eaddr, (int)q.dir);
-               if (linktype == DLT_IEEE802_11 ||
-                   linktype == DLT_IEEE802_11_RADIO_AVS ||
-                   linktype == DLT_IEEE802_11_RADIO ||
-                   linktype == DLT_PRISM_HEADER)
-                       return gen_wlanhostop(eaddr, (int)q.dir);
-               if (linktype == DLT_SUNATM && is_lane) {
+            switch (linktype) {
+            case DLT_EN10MB:
+                return gen_ehostop(eaddr, (int)q.dir);
+            case DLT_FDDI:
+                return gen_fhostop(eaddr, (int)q.dir);
+            case DLT_IEEE802:
+                return gen_thostop(eaddr, (int)q.dir);
+           case DLT_IEEE802_11:
+           case DLT_IEEE802_11_RADIO_AVS:
+           case DLT_IEEE802_11_RADIO:
+           case DLT_PRISM_HEADER:
+                return gen_wlanhostop(eaddr, (int)q.dir);
+            case DLT_SUNATM:
+               if (is_lane) {
                        /*
                         * Check that the packet doesn't begin with an
                         * LE Control marker.  (We've already generated
@@ -5125,9 +5266,13 @@ gen_ecode(eaddr, q)
                        gen_and(tmp, b);
                        return b;
                }
-               if (linktype == DLT_IP_OVER_FC)
-                       return gen_ipfchostop(eaddr, (int)q.dir);
+                break;
+           case DLT_IP_OVER_FC:
+                return gen_ipfchostop(eaddr, (int)q.dir);
+            default:
                bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+                break;
+            }
        }
        bpf_error("ethernet address used in non-ether expression");
        /* NOTREACHED */
@@ -5662,22 +5807,25 @@ gen_broadcast(proto)
 
        case Q_DEFAULT:
        case Q_LINK:
-               if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX)
-                       return gen_ahostop(abroadcast, Q_DST);
-               if (linktype == DLT_EN10MB)
-                       return gen_ehostop(ebroadcast, Q_DST);
-               if (linktype == DLT_FDDI)
-                       return gen_fhostop(ebroadcast, Q_DST);
-               if (linktype == DLT_IEEE802)
-                       return gen_thostop(ebroadcast, Q_DST);
-               if (linktype == DLT_IEEE802_11 ||
-                   linktype == DLT_IEEE802_11_RADIO_AVS ||
-                   linktype == DLT_IEEE802_11_RADIO ||
-                   linktype == DLT_PRISM_HEADER)
-                       return gen_wlanhostop(ebroadcast, Q_DST);
-               if (linktype == DLT_IP_OVER_FC)
-                       return gen_ipfchostop(ebroadcast, Q_DST);
-               if (linktype == DLT_SUNATM && is_lane) {
+                switch (linktype) {
+                case DLT_ARCNET:
+                case DLT_ARCNET_LINUX:
+                    return gen_ahostop(abroadcast, Q_DST);
+                case DLT_EN10MB:    
+                    return gen_ehostop(ebroadcast, Q_DST);
+                case DLT_FDDI:
+                    return gen_fhostop(ebroadcast, Q_DST);
+                case DLT_IEEE802:
+                    return gen_thostop(ebroadcast, Q_DST);
+                case DLT_IEEE802_11:
+                case DLT_IEEE802_11_RADIO_AVS:
+                case DLT_IEEE802_11_RADIO:
+                case DLT_PRISM_HEADER:
+                    return gen_wlanhostop(ebroadcast, Q_DST);
+                case DLT_IP_OVER_FC:
+                    return gen_ipfchostop(ebroadcast, Q_DST);
+                case DLT_SUNATM:
+                    if (is_lane) {
                        /*
                         * Check that the packet doesn't begin with an
                         * LE Control marker.  (We've already generated
@@ -5693,8 +5841,11 @@ gen_broadcast(proto)
                        b0 = gen_ehostop(ebroadcast, Q_DST);
                        gen_and(b1, b0);
                        return b0;
-               }
-               bpf_error("not a broadcast link");
+                    }
+                    break;
+                default:
+                    bpf_error("not a broadcast link");
+                }
                break;
 
        case Q_IP:
@@ -5741,154 +5892,146 @@ gen_multicast(proto)
 
        case Q_DEFAULT:
        case Q_LINK:
-               if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX)
-                       /* all ARCnet multicasts use the same address */
-                       return gen_ahostop(abroadcast, Q_DST);
-
-               if (linktype == DLT_EN10MB) {
-                       /* ether[0] & 1 != 0 */
-                       return gen_mac_multicast(0);
-               }
-
-               if (linktype == DLT_FDDI) {
-                       /*
-                        * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
-                        *
-                        * XXX - was that referring to bit-order issues?
-                        */
-                       /* fddi[1] & 1 != 0 */
-                       return gen_mac_multicast(1);
-               }
-
-               if (linktype == DLT_IEEE802) {
-                       /* tr[2] & 1 != 0 */
-                       return gen_mac_multicast(2);
-               }
-
-               if (linktype == DLT_IEEE802_11 ||
-                   linktype == DLT_IEEE802_11_RADIO_AVS ||
-                   linktype == DLT_IEEE802_11_RADIO ||
-                   linktype == DLT_PRISM_HEADER) {
-                       /*
-                        * Oh, yuk.
-                        *
-                        *      For control frames, there is no DA.
-                        *
-                        *      For management frames, DA is at an
-                        *      offset of 4 from the beginning of
-                        *      the packet.
-                        *
-                        *      For data frames, DA is at an offset
-                        *      of 4 from the beginning of the packet
-                        *      if To DS is clear and at an offset of
-                        *      16 from the beginning of the packet
-                        *      if To DS is set.
-                        */
-
-                       /*
-                        * Generate the tests to be done for data frames.
-                        *
-                        * First, check for To DS set, i.e. "link[1] & 0x01".
-                        */
-                       s = gen_load_a(OR_LINK, 1, BPF_B);
-                       b1 = new_block(JMP(BPF_JSET));
-                       b1->s.k = 0x01; /* To DS */
-                       b1->stmts = s;
-
-                       /*
-                        * If To DS is set, the DA is at 16.
-                        */
-                       b0 = gen_mac_multicast(16);
-                       gen_and(b1, b0);
-
-                       /*
-                        * Now, check for To DS not set, i.e. check
-                        * "!(link[1] & 0x01)".
-                        */
-                       s = gen_load_a(OR_LINK, 1, BPF_B);
-                       b2 = new_block(JMP(BPF_JSET));
-                       b2->s.k = 0x01; /* To DS */
-                       b2->stmts = s;
-                       gen_not(b2);
-
-                       /*
-                        * If To DS is not set, the DA is at 4.
-                        */
-                       b1 = gen_mac_multicast(4);
-                       gen_and(b2, b1);
-
-                       /*
-                        * Now OR together the last two checks.  That gives
-                        * the complete set of checks for data frames.
-                        */
-                       gen_or(b1, b0);
-
-                       /*
-                        * Now check for a data frame.
-                        * I.e, check "link[0] & 0x08".
-                        */
-                       s = gen_load_a(OR_LINK, 0, BPF_B);
-                       b1 = new_block(JMP(BPF_JSET));
-                       b1->s.k = 0x08;
-                       b1->stmts = s;
-
-                       /*
-                        * AND that with the checks done for data frames.
-                        */
-                       gen_and(b1, b0);
-
-                       /*
-                        * If the high-order bit of the type value is 0, this
-                        * is a management frame.
-                        * I.e, check "!(link[0] & 0x08)".
-                        */
-                       s = gen_load_a(OR_LINK, 0, BPF_B);
-                       b2 = new_block(JMP(BPF_JSET));
-                       b2->s.k = 0x08;
-                       b2->stmts = s;
-                       gen_not(b2);
-
-                       /*
-                        * For management frames, the DA is at 4.
-                        */
-                       b1 = gen_mac_multicast(4);
-                       gen_and(b2, b1);
-
-                       /*
-                        * OR that with the checks done for data frames.
-                        * That gives the checks done for management and
-                        * data frames.
-                        */
-                       gen_or(b1, b0);
-
-                       /*
-                        * If the low-order bit of the type value is 1,
-                        * this is either a control frame or a frame
-                        * with a reserved type, and thus not a
-                        * frame with an SA.
-                        *
-                        * I.e., check "!(link[0] & 0x04)".
-                        */
-                       s = gen_load_a(OR_LINK, 0, BPF_B);
-                       b1 = new_block(JMP(BPF_JSET));
-                       b1->s.k = 0x04;
-                       b1->stmts = s;
-                       gen_not(b1);
-
-                       /*
-                        * AND that with the checks for data and management
-                        * frames.
-                        */
-                       gen_and(b1, b0);
-                       return b0;
-               }
-
-               if (linktype == DLT_IP_OVER_FC) {
-                       b0 = gen_mac_multicast(2);
-                       return b0;
-               }
-
-               if (linktype == DLT_SUNATM && is_lane) {
+                switch (linktype) {
+                case DLT_ARCNET:
+                case DLT_ARCNET_LINUX:
+                    /* all ARCnet multicasts use the same address */
+                    return gen_ahostop(abroadcast, Q_DST);
+                case  DLT_EN10MB:
+                    /* ether[0] & 1 != 0 */
+                    return gen_mac_multicast(0);
+                case DLT_FDDI:
+                    /*
+                     * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
+                     *
+                     * XXX - was that referring to bit-order issues?
+                     */
+                    /* fddi[1] & 1 != 0 */
+                    return gen_mac_multicast(1);
+                case DLT_IEEE802:
+                    /* tr[2] & 1 != 0 */
+                    return gen_mac_multicast(2);
+                case DLT_IEEE802_11:
+                case DLT_IEEE802_11_RADIO_AVS:
+                case DLT_IEEE802_11_RADIO:
+                case DLT_PRISM_HEADER:
+                    /*
+                     * Oh, yuk.
+                     *
+                     * For control frames, there is no DA.
+                     *
+                     * For management frames, DA is at an
+                     * offset of 4 from the beginning of
+                     * the packet.
+                     *
+                     * For data frames, DA is at an offset
+                     * of 4 from the beginning of the packet
+                     * if To DS is clear and at an offset of
+                     * 16 from the beginning of the packet
+                     * if To DS is set.
+                     */
+                    
+                    /*
+                     * Generate the tests to be done for data frames.
+                     *
+                     * First, check for To DS set, i.e. "link[1] & 0x01".
+                     */
+                    s = gen_load_a(OR_LINK, 1, BPF_B);
+                    b1 = new_block(JMP(BPF_JSET));
+                    b1->s.k = 0x01;    /* To DS */
+                    b1->stmts = s;
+                    
+                    /*
+                     * If To DS is set, the DA is at 16.
+                     */
+                    b0 = gen_mac_multicast(16);
+                    gen_and(b1, b0);
+                    
+                    /*
+                     * Now, check for To DS not set, i.e. check
+                     * "!(link[1] & 0x01)".
+                     */
+                    s = gen_load_a(OR_LINK, 1, BPF_B);
+                    b2 = new_block(JMP(BPF_JSET));
+                    b2->s.k = 0x01;    /* To DS */
+                    b2->stmts = s;
+                    gen_not(b2);
+                    
+                    /*
+                     * If To DS is not set, the DA is at 4.
+                     */
+                    b1 = gen_mac_multicast(4);
+                    gen_and(b2, b1);
+                    
+                    /*
+                     * Now OR together the last two checks.  That gives
+                     * the complete set of checks for data frames.
+                     */
+                    gen_or(b1, b0);
+                    
+                    /*
+                     * Now check for a data frame.
+                     * I.e, check "link[0] & 0x08".
+                     */
+                    s = gen_load_a(OR_LINK, 0, BPF_B);
+                    b1 = new_block(JMP(BPF_JSET));
+                    b1->s.k = 0x08;
+                    b1->stmts = s;
+                    
+                    /*
+                     * AND that with the checks done for data frames.
+                     */
+                    gen_and(b1, b0);
+                    
+                    /*
+                     * If the high-order bit of the type value is 0, this
+                     * is a management frame.
+                     * I.e, check "!(link[0] & 0x08)".
+                     */
+                    s = gen_load_a(OR_LINK, 0, BPF_B);
+                    b2 = new_block(JMP(BPF_JSET));
+                    b2->s.k = 0x08;
+                    b2->stmts = s;
+                    gen_not(b2);
+                    
+                    /*
+                     * For management frames, the DA is at 4.
+                     */
+                    b1 = gen_mac_multicast(4);
+                    gen_and(b2, b1);
+                    
+                    /*
+                     * OR that with the checks done for data frames.
+                     * That gives the checks done for management and
+                     * data frames.
+                     */
+                    gen_or(b1, b0);
+                    
+                    /*
+                     * If the low-order bit of the type value is 1,
+                     * this is either a control frame or a frame
+                     * with a reserved type, and thus not a
+                     * frame with an SA.
+                     *
+                     * I.e., check "!(link[0] & 0x04)".
+                     */
+                    s = gen_load_a(OR_LINK, 0, BPF_B);
+                    b1 = new_block(JMP(BPF_JSET));
+                    b1->s.k = 0x04;
+                    b1->stmts = s;
+                    gen_not(b1);
+                    
+                    /*
+                     * AND that with the checks for data and management
+                     * frames.
+                     */
+                    gen_and(b1, b0);
+                    return b0;
+                case DLT_IP_OVER_FC:
+                    b0 = gen_mac_multicast(2);
+                    return b0;
+                case DLT_SUNATM:
+                    if (is_lane) {
                        /*
                         * Check that the packet doesn't begin with an
                         * LE Control marker.  (We've already generated
@@ -5902,10 +6045,13 @@ gen_multicast(proto)
                        b0 = gen_mac_multicast(off_mac);
                        gen_and(b1, b0);
                        return b0;
-               }
-
-               /* Link not known to support multicasts */
-               break;
+                    }
+                    break;
+                default:
+                    break;
+                }
+                /* Link not known to support multicasts */
+                break;
 
        case Q_IP:
                b0 = gen_linktype(ETHERTYPE_IP);
@@ -5983,6 +6129,7 @@ gen_inbound(dir)
                }
                break;
 
+        case DLT_JUNIPER_MFR:
         case DLT_JUNIPER_MLFR:
         case DLT_JUNIPER_MLPPP:
        case DLT_JUNIPER_ATM1:
@@ -5993,6 +6140,10 @@ gen_inbound(dir)
         case DLT_JUNIPER_ES:
         case DLT_JUNIPER_MONITOR:
         case DLT_JUNIPER_SERVICES:
+        case DLT_JUNIPER_ETHER:
+        case DLT_JUNIPER_PPP:
+        case DLT_JUNIPER_FRELAY:
+        case DLT_JUNIPER_CHDLC:
                /* juniper flags (including direction) are stored
                 * the byte after the 3-byte magic number */
                if (dir) {
@@ -6036,7 +6187,7 @@ gen_pf_ifname(const char *ifname)
        return (b0);
 }
 
-/* PF firewall log matched interface */
+/* PF firewall log ruleset name */
 struct block *
 gen_pf_ruleset(char *ruleset)
 {
@@ -6175,7 +6326,11 @@ struct block *
 gen_vlan(vlan_num)
        int vlan_num;
 {
-       struct  block   *b0;
+       struct  block   *b0, *b1;
+
+       /* can't check for VLAN-encapsulated packets inside MPLS */
+       if (label_stack_depth > 0)
+               bpf_error("no VLAN match after MPLS");
 
        /*
         * Change the offsets to point to the type and data fields within
@@ -6207,30 +6362,28 @@ 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;
+       orig_linktype = off_linktype;   /* save original values */
+       orig_nl = off_nl;
 
-        switch (linktype) {
+       switch (linktype) {
 
-        case DLT_EN10MB:
-                off_linktype += 4;
-                off_nl_nosnap += 4;
-                off_nl += 4;
-                break;
+       case DLT_EN10MB:
+               off_linktype += 4;
+               off_nl_nosnap += 4;
+               off_nl += 4;
+               break;
 
-        default:
-                bpf_error("no VLAN support for data link type %d",
-                      linktype);
-            /*NOTREACHED*/
-        }
+       default:
+               bpf_error("no VLAN support for data link type %d",
+                     linktype);
+               /*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) {
-               struct block *b1;
-
                b1 = gen_mcmp(OR_LINK, orig_nl, BPF_H, (bpf_int32)vlan_num,
                    0x0fff);
                gen_and(b0, b1);
@@ -6247,7 +6400,7 @@ struct block *
 gen_mpls(label_num)
        int label_num;
 {
-       struct  block   *b0;
+       struct  block   *b0,*b1;
 
        /*
         * Change the offsets to point to the type and data fields within
@@ -6258,44 +6411,46 @@ gen_mpls(label_num)
         *
         * XXX - this is a bit of a kludge.  See comments in gen_vlan().
         */
-        orig_linktype = off_linktype;  /* save original values */
         orig_nl = off_nl;
 
-        switch (linktype) {
-            
-        case DLT_C_HDLC: /* fall through */
-        case DLT_EN10MB:
-                off_nl_nosnap += 4;
-                off_nl += 4;
-                        
-                b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H,
-                    (bpf_int32)ETHERTYPE_MPLS);
-                break;
-
-        case DLT_PPP:
-                off_nl_nosnap += 4;
-                off_nl += 4;
-
-                b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H,
-                    (bpf_int32)PPP_MPLS_UCAST);
-                break;
-
-                /* FIXME add other DLT_s ...
-                 * for Frame-Relay/and ATM this may get messy due to SNAP headers
-                 * leave it for now */
-
-        default:
-                bpf_error("no MPLS support for data link type %d",
+        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);
+        } else {
+            /*
+             * Indicate that we're checking MPLS-encapsulated headers,
+             * to make sure higher level code generators don't try to
+             * match against IP-related protocols such as Q_ARP, Q_RARP
+             * etc.
+             */
+            switch (linktype) {
+                
+            case DLT_C_HDLC: /* fall through */
+            case DLT_EN10MB:
+                    b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+                                 (bpf_int32)ETHERTYPE_MPLS);
+                    break;
+                
+            case DLT_PPP:
+                    b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+                                 (bpf_int32)PPP_MPLS_UCAST);
+                    break;
+                
+                    /* FIXME add other DLT_s ...
+                     * for Frame-Relay/and ATM this may get messy due to SNAP headers
+                     * leave it for now */
+                
+            default:
+                    bpf_error("no MPLS support for data link type %d",
                           linktype);
-                b0 = NULL;
-                /*NOTREACHED*/
-                break;
+                    b0 = NULL;
+                    /*NOTREACHED*/
+                    break;
+            }
         }
 
        /* If a specific MPLS label is requested, check it */
        if (label_num >= 0) {
-               struct block *b1;
-
                label_num = label_num << 12; /* label is shifted 12 bits on the wire */
                b1 = gen_mcmp(OR_LINK, orig_nl, BPF_W, (bpf_int32)label_num,
                    0xfffff000); /* only compare the first 20 bits */
@@ -6303,9 +6458,84 @@ gen_mpls(label_num)
                b0 = b1;
        }
 
+        off_nl_nosnap += 4;
+        off_nl += 4;
+        label_stack_depth++;
        return (b0);
 }
 
+/*
+ * Support PPPOE discovery and session.
+ */
+struct block *
+gen_pppoed()
+{
+       /* check for PPPoE discovery */
+       return gen_linktype((bpf_int32)ETHERTYPE_PPPOED);
+}
+
+struct block *
+gen_pppoes()
+{
+       struct block *b0;
+
+       /*
+        * Test against the PPPoE session link-layer type.
+        */
+       b0 = gen_linktype((bpf_int32)ETHERTYPE_PPPOES);
+
+       /*
+        * Change the offsets to point to the type and data fields within
+        * the PPP packet.
+        *
+        * XXX - this is a bit of a kludge.  If we were to split the
+        * compiler into a parser that parses an expression and
+        * generates an expression tree, and a code generator that
+        * takes an expression tree (which could come from our
+        * parser or from some other parser) and generates BPF code,
+        * we could perhaps make the offsets parameters of routines
+        * and, in the handler for an "AND" node, pass to subnodes
+        * other than the PPPoE node the adjusted offsets.
+        *
+        * This would mean that "pppoes" would, instead of changing the
+        * behavior of *all* tests after it, change only the behavior
+        * of tests ANDed with it.  That would change the documented
+        * semantics of "pppoes", which might break some expressions.
+        * However, it would mean that "(pppoes and ip) or ip" would check
+        * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than
+        * checking only for VLAN-encapsulated IP, so that could still
+        * be considered worth doing; it wouldn't break expressions
+        * that are of the form "pppoes and ..." which I suspect are the
+        * most common expressions involving "pppoes".  "pppoes or ..."
+        * doesn't necessarily do what the user would really want, now,
+        * as all the "or ..." tests would be done assuming PPPoE, even
+        * though the "or" could be viewed as meaning "or, if this isn't
+        * a PPPoE packet...".
+        */
+       orig_linktype = off_linktype;   /* save original values */
+       orig_nl = off_nl;
+
+       /*
+        * 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).
+        */
+       off_linktype = orig_nl + 6;
+       off_nl = orig_nl + 6 + 2;
+       off_nl_nosnap = orig_nl + 6 + 2;
+
+       /*
+        * Set the link-layer type to PPP, as all subsequent tests will
+        * be on the encapsulated PPP header.
+        */
+       linktype = DLT_PPP;
+
+       return b0;
+}
+
 struct block *
 gen_atmfield_code(atmfield, jvalue, jtype, reverse)
        int atmfield;