]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
Consolidate MAC-48 address matching code.
[libpcap] / gencode.c
index b4c1c58693054110277963a64d79dee4eb920a00..eed4863cbb7189c5730d1fb5ddec4969295dfb3e 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -254,6 +254,12 @@ struct addrinfo {
 #define ISIS_L2_CSNP         25
 #define ISIS_L1_PSNP         26
 #define ISIS_L2_PSNP         27
+/*
+ * The maximum possible value can also be used as a bit mask because the
+ * "PDU Type" field comprises the least significant 5 bits of a particular
+ * octet, see sections 9.5~9.13 of ISO/IEC 10589:2002(E).
+ */
+#define ISIS_PDU_TYPE_MAX 0x1FU
 
 #ifndef ISO8878A_CONS
 #define        ISO8878A_CONS           0x84
@@ -629,10 +635,18 @@ static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int,
     u_int, bpf_u_int32);
 static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int,
     u_int, bpf_u_int32);
+static struct block *gen_cmp_ne(compiler_state_t *, enum e_offrel, u_int,
+    u_int size, bpf_u_int32);
 static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int,
     u_int, bpf_u_int32, bpf_u_int32);
+static struct block *gen_mcmp_ne(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32, bpf_u_int32);
 static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int,
     u_int, const u_char *);
+static struct block *gen_jmp(compiler_state_t *, int, bpf_u_int32,
+    struct slist *);
+static struct block *gen_set(compiler_state_t *, bpf_u_int32, struct slist *);
+static struct block *gen_unset(compiler_state_t *, bpf_u_int32, struct slist *);
 static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, u_int,
     u_int, bpf_u_int32, int, int, bpf_u_int32);
 static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *,
@@ -654,22 +668,21 @@ static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *);
 static void insert_compute_vloffsets(compiler_state_t *, struct block *);
 static struct slist *gen_abs_offset_varpart(compiler_state_t *,
     bpf_abs_offset *);
-static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32);
+static uint16_t ethertype_to_ppptype(compiler_state_t *, bpf_u_int32);
 static struct block *gen_linktype(compiler_state_t *, bpf_u_int32);
 static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32);
 static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32);
 static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32,
-    int, bpf_u_int32, u_int, u_int);
+    int, u_int, u_int);
 #ifdef INET6
 static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *,
-    struct in6_addr *, int, bpf_u_int32, u_int, u_int);
+    struct in6_addr *, int, u_int, u_int);
 #endif
 static struct block *gen_ahostop(compiler_state_t *, const uint8_t, int);
-static struct block *gen_ehostop(compiler_state_t *, const u_char *, int);
-static struct block *gen_fhostop(compiler_state_t *, const u_char *, int);
-static struct block *gen_thostop(compiler_state_t *, const u_char *, int);
 static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int);
-static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int);
+static unsigned char is_mac48_linktype(const int);
+static struct block *gen_mac48host(compiler_state_t *, const u_char *,
+    const u_char, const char *);
 static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int);
 static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32);
 static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32,
@@ -680,42 +693,43 @@ static struct block *gen_host6(compiler_state_t *, struct in6_addr *,
 #endif
 #ifndef INET6
 static struct block *gen_gateway(compiler_state_t *, const u_char *,
-    struct addrinfo *, int, int);
+    struct addrinfo *, int);
 #endif
+static struct block *gen_ip_proto(compiler_state_t *, const uint8_t);
+static struct block *gen_ip6_proto(compiler_state_t *, const uint8_t);
 static struct block *gen_ipfrag(compiler_state_t *);
-static struct block *gen_portatom(compiler_state_t *, int, bpf_u_int32);
-static struct block *gen_portrangeatom(compiler_state_t *, u_int, bpf_u_int32,
-    bpf_u_int32);
-static struct block *gen_portatom6(compiler_state_t *, int, bpf_u_int32);
-static struct block *gen_portrangeatom6(compiler_state_t *, u_int, bpf_u_int32,
-    bpf_u_int32);
-static struct block *gen_portop(compiler_state_t *, u_int, u_int, int);
-static struct block *gen_port(compiler_state_t *, u_int, int, int);
-static struct block *gen_portrangeop(compiler_state_t *, u_int, u_int,
-    bpf_u_int32, int);
-static struct block *gen_portrange(compiler_state_t *, u_int, u_int, int, int);
-struct block *gen_portop6(compiler_state_t *, u_int, u_int, int);
-static struct block *gen_port6(compiler_state_t *, u_int, int, int);
-static struct block *gen_portrangeop6(compiler_state_t *, u_int, u_int,
-    bpf_u_int32, int);
-static struct block *gen_portrange6(compiler_state_t *, u_int, u_int, int, int);
+static struct block *gen_portatom(compiler_state_t *, int, uint16_t);
+static struct block *gen_portrangeatom(compiler_state_t *, u_int, uint16_t,
+    uint16_t);
+static struct block *gen_portatom6(compiler_state_t *, int, uint16_t);
+static struct block *gen_portrangeatom6(compiler_state_t *, u_int, uint16_t,
+    uint16_t);
+static struct block *gen_port(compiler_state_t *, uint16_t, int, int);
+static struct block *gen_port_common(compiler_state_t *, int, struct block *);
+static struct block *gen_portrange(compiler_state_t *, uint16_t, uint16_t,
+    int, int);
+static struct block *gen_port6(compiler_state_t *, uint16_t, int, int);
+static struct block *gen_port6_common(compiler_state_t *, int, struct block *);
+static struct block *gen_portrange6(compiler_state_t *, uint16_t, uint16_t,
+    int, int);
 static int lookup_proto(compiler_state_t *, const char *, int);
 #if !defined(NO_PROTOCHAIN)
 static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int);
 #endif /* !defined(NO_PROTOCHAIN) */
-static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int, int);
+static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int);
 static struct slist *xfer_to_x(compiler_state_t *, struct arth *);
 static struct slist *xfer_to_a(compiler_state_t *, struct arth *);
 static struct block *gen_mac_multicast(compiler_state_t *, int);
 static struct block *gen_len(compiler_state_t *, int, int);
-static struct block *gen_check_802_11_data_frame(compiler_state_t *);
 static struct block *gen_encap_ll_check(compiler_state_t *cstate);
 
-static struct block *gen_ppi_dlt_check(compiler_state_t *);
 static struct block *gen_atmfield_code_internal(compiler_state_t *, int,
     bpf_u_int32, int, int);
 static struct block *gen_atmtype_llc(compiler_state_t *);
-static struct block *gen_msg_abbrev(compiler_state_t *, int type);
+static struct block *gen_msg_abbrev(compiler_state_t *, const uint8_t);
+static struct block *gen_atm_prototype(compiler_state_t *, const uint8_t);
+static struct block *gen_atm_vpi(compiler_state_t *, const uint8_t);
+static struct block *gen_atm_vci(compiler_state_t *, const uint16_t);
 
 static void
 initchunks(compiler_state_t *cstate)
@@ -859,6 +873,218 @@ syntax(compiler_state_t *cstate)
        bpf_error(cstate, "syntax error in filter expression");
 }
 
+/*
+ * For the given integer return a string with the keyword (or the nominal
+ * keyword if there is more than one).  This is a simpler version of tok2str()
+ * in tcpdump because in this problem space a valid integer value is not
+ * greater than 71.
+ */
+static const char *
+qual2kw(const char *kind, const unsigned id, const char *tokens[],
+    const size_t size)
+{
+       static char buf[4][64];
+       static int idx = 0;
+
+       if (id < size && tokens[id])
+               return tokens[id];
+
+       char *ret = buf[idx];
+       idx = (idx + 1) % (sizeof(buf) / sizeof(buf[0]));
+       ret[0] = '\0'; // just in case
+       snprintf(ret, sizeof(buf[0]), "<invalid %s %u>", kind, id);
+       return ret;
+}
+
+// protocol qualifier keywords
+static const char *
+pqkw(const unsigned id)
+{
+       const char * tokens[] = {
+               [Q_LINK] = "link",
+               [Q_IP] = "ip",
+               [Q_ARP] = "arp",
+               [Q_RARP] = "rarp",
+               [Q_SCTP] = "sctp",
+               [Q_TCP] = "tcp",
+               [Q_UDP] = "udp",
+               [Q_ICMP] = "icmp",
+               [Q_IGMP] = "igmp",
+               [Q_IGRP] = "igrp",
+               [Q_ATALK] = "atalk",
+               [Q_DECNET] = "decnet",
+               [Q_LAT] = "lat",
+               [Q_SCA] = "sca",
+               [Q_MOPRC] = "moprc",
+               [Q_MOPDL] = "mopdl",
+               [Q_IPV6] = "ip6",
+               [Q_ICMPV6] = "icmp6",
+               [Q_AH] = "ah",
+               [Q_ESP] = "esp",
+               [Q_PIM] = "pim",
+               [Q_VRRP] = "vrrp",
+               [Q_AARP] = "aarp",
+               [Q_ISO] = "iso",
+               [Q_ESIS] = "esis",
+               [Q_ISIS] = "isis",
+               [Q_CLNP] = "clnp",
+               [Q_STP] = "stp",
+               [Q_IPX] = "ipx",
+               [Q_NETBEUI] = "netbeui",
+               [Q_ISIS_L1] = "l1",
+               [Q_ISIS_L2] = "l2",
+               [Q_ISIS_IIH] = "iih",
+               [Q_ISIS_SNP] = "snp",
+               [Q_ISIS_CSNP] = "csnp",
+               [Q_ISIS_PSNP] = "psnp",
+               [Q_ISIS_LSP] = "lsp",
+               [Q_RADIO] = "radio",
+               [Q_CARP] = "carp",
+       };
+       return qual2kw("proto", id, tokens, sizeof(tokens) / sizeof(tokens[0]));
+}
+
+// direction qualifier keywords
+static const char *
+dqkw(const unsigned id)
+{
+       const char * map[] = {
+               [Q_SRC] = "src",
+               [Q_DST] = "dst",
+               [Q_OR] = "src or dst",
+               [Q_AND] = "src and dst",
+               [Q_ADDR1] = "addr1",
+               [Q_ADDR2] = "addr2",
+               [Q_ADDR3] = "addr3",
+               [Q_ADDR4] = "addr4",
+               [Q_RA] = "ra",
+               [Q_TA] = "ta",
+       };
+       return qual2kw("dir", id, map, sizeof(map) / sizeof(map[0]));
+}
+
+// ATM keywords
+static const char *
+atmkw(const unsigned id)
+{
+       const char * tokens[] = {
+               [A_METAC] = "metac",
+               [A_BCC] = "bcc",
+               [A_OAMF4SC] = "oamf4sc",
+               [A_OAMF4EC] = "oamf4ec",
+               [A_SC] = "sc",
+               [A_ILMIC] = "ilmic",
+               [A_OAM] = "oam",
+               [A_OAMF4] = "oamf4",
+               [A_LANE] = "lane",
+               [A_VPI] = "vpi",
+               [A_VCI] = "vci",
+               [A_CONNECTMSG] = "connectmsg",
+               [A_METACONNECT] = "metaconnect",
+       };
+       return qual2kw("ATM keyword", id, tokens, sizeof(tokens) / sizeof(tokens[0]));
+}
+
+// SS7 keywords
+static const char *
+ss7kw(const unsigned id)
+{
+       const char * tokens[] = {
+               [M_FISU] = "fisu",
+               [M_LSSU] = "lssu",
+               [M_MSU] = "msu",
+               [MH_FISU] = "hfisu",
+               [MH_LSSU] = "hlssu",
+               [MH_MSU] = "hmsu",
+               [M_SIO] = "sio",
+               [M_OPC] = "opc",
+               [M_DPC] = "dpc",
+               [M_SLS] = "sls",
+               [MH_SIO] = "hsio",
+               [MH_OPC] = "hopc",
+               [MH_DPC] = "hdpc",
+               [MH_SLS] = "hsls",
+       };
+       return qual2kw("MTP keyword", id, tokens, sizeof(tokens) / sizeof(tokens[0]));
+}
+
+static PCAP_NORETURN_DEF void
+fail_kw_on_dlt(compiler_state_t *cstate, const char *keyword)
+{
+       bpf_error(cstate, "'%s' not supported on %s", keyword,
+           pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+}
+
+static void
+assert_pflog(compiler_state_t *cstate, const char *kw)
+{
+       if (cstate->linktype != DLT_PFLOG)
+               bpf_error(cstate, "'%s' supported only on PFLOG linktype", kw);
+}
+
+static void
+assert_atm(compiler_state_t *cstate, const char *kw)
+{
+       /*
+        * Belt and braces: init_linktype() sets either all of these struct
+        * members (for DLT_SUNATM) or none (otherwise).
+        */
+       if (cstate->linktype != DLT_SUNATM ||
+           ! cstate->is_atm ||
+           cstate->off_vpi == OFFSET_NOT_SET ||
+           cstate->off_vci == OFFSET_NOT_SET ||
+           cstate->off_proto == OFFSET_NOT_SET ||
+           cstate->off_payload == OFFSET_NOT_SET)
+               bpf_error(cstate, "'%s' supported only on SUNATM", kw);
+}
+
+static void
+assert_ss7(compiler_state_t *cstate, const char *kw)
+{
+       switch (cstate->linktype) {
+       case DLT_MTP2:
+       case DLT_ERF:
+       case DLT_MTP2_WITH_PHDR:
+               // Belt and braces, same as in assert_atm().
+               if (cstate->off_sio != OFFSET_NOT_SET &&
+                   cstate->off_opc != OFFSET_NOT_SET &&
+                   cstate->off_dpc != OFFSET_NOT_SET &&
+                   cstate->off_sls != OFFSET_NOT_SET)
+                       return;
+       }
+       bpf_error(cstate, "'%s' supported only on SS7", kw);
+}
+
+static void
+assert_maxval(compiler_state_t *cstate, const char *name,
+    const bpf_u_int32 val, const bpf_u_int32 maxval)
+{
+       if (val > maxval)
+               bpf_error(cstate, "%s %u greater than maximum %u",
+                   name, val, maxval);
+}
+
+#define ERRSTR_802_11_ONLY_KW "'%s' is valid for 802.11 syntax only"
+#define ERRSTR_INVALID_QUAL "'%s' is not a valid qualifier for '%s'"
+#define ERRSTR_UNKNOWN_MAC48HOST "unknown Ethernet-like host '%s'"
+
+// Validate a port/portrange proto qualifier and map to an IP protocol number.
+static int
+port_pq_to_ipproto(compiler_state_t *cstate, const int proto, const char *kw)
+{
+       switch (proto) {
+       case Q_UDP:
+               return IPPROTO_UDP;
+       case Q_TCP:
+               return IPPROTO_TCP;
+       case Q_SCTP:
+               return IPPROTO_SCTP;
+       case Q_DEFAULT:
+               return PROTO_UNDEF;
+       }
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), kw);
+}
+
 int
 pcap_compile(pcap_t *p, struct bpf_program *program,
             const char *buf, int optimize, bpf_u_int32 mask)
@@ -1104,8 +1330,6 @@ merge(struct block *b0, struct block *b1)
 int
 finish_parse(compiler_state_t *cstate, struct block *p)
 {
-       struct block *ppi_dlt_check;
-
        /*
         * Catch errors reported by us and routines below us, and return -1
         * on an error.
@@ -1147,9 +1371,11 @@ finish_parse(compiler_state_t *cstate, struct block *p)
         * 802.11 code (*and* anything else for which PPI is used)
         * and choose between them early in the BPF program?
         */
-       ppi_dlt_check = gen_ppi_dlt_check(cstate);
-       if (ppi_dlt_check != NULL)
+       if (cstate->linktype == DLT_PPI) {
+               struct block *ppi_dlt_check = gen_cmp(cstate, OR_PACKET,
+                       4, BPF_W, SWAPLONG(DLT_IEEE802_11));
                gen_and(ppi_dlt_check, p);
+       }
 
        backpatch(p, gen_retblk_internal(cstate, cstate->snaplen));
        p->sense = !p->sense;
@@ -1220,13 +1446,40 @@ gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
        return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v);
 }
 
+static struct block *
+gen_cmp_ne(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v)
+{
+       return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 1, v);
+}
+
 static struct block *
 gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
     u_int size, bpf_u_int32 v, bpf_u_int32 mask)
 {
+       /*
+        * For any A: if mask == 0, it means A & mask == 0, so the result is
+        * true iff v == 0.  In this case ideally the caller should have
+        * skipped this invocation and have fewer statement blocks to juggle.
+        * If the caller could have skipped, but has not, produce a block with
+        * fewer statements.
+        *
+        * This could be done in gen_ncmp() in a more generic way, but this
+        * function is the only code path that can have mask == 0.
+        */
+       if (mask == 0)
+               return v ? gen_false(cstate) : gen_true(cstate);
+
        return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v);
 }
 
+static struct block *
+gen_mcmp_ne(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v, bpf_u_int32 mask)
+{
+       return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 1, v);
+}
+
 static struct block *
 gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
     u_int size, const u_char *v)
@@ -1263,6 +1516,29 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
        return b;
 }
 
+static struct block *
+gen_jmp(compiler_state_t *cstate, int jtype, bpf_u_int32 v, struct slist *stmts)
+{
+       struct block *b = new_block(cstate, JMP(jtype));
+       b->s.k = v;
+       b->stmts = stmts;
+       return b;
+}
+
+static struct block *
+gen_set(compiler_state_t *cstate, bpf_u_int32 v, struct slist *stmts)
+{
+       return gen_jmp(cstate, BPF_JSET, v, stmts);
+}
+
+static struct block *
+gen_unset(compiler_state_t *cstate, bpf_u_int32 v, struct slist *stmts)
+{
+       struct block *b = gen_set(cstate, v, stmts);
+       gen_not(b);
+       return b;
+}
+
 /*
  * AND the field of size "size" at offset "offset" relative to the header
  * specified by "offrel" with "mask", and compare it with the value "v"
@@ -1285,9 +1561,7 @@ gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
                sappend(s, s2);
        }
 
-       b = new_block(cstate, JMP(jtype));
-       b->stmts = s;
-       b->s.k = v;
+       b = gen_jmp(cstate, jtype, v, s);
        if (reverse)
                gen_not(b);
        return b;
@@ -2080,15 +2354,11 @@ gen_loadx_iphdrlen(compiler_state_t *cstate)
 static struct block *
 gen_uncond(compiler_state_t *cstate, int rsense)
 {
-       struct block *b;
        struct slist *s;
 
        s = new_stmt(cstate, BPF_LD|BPF_IMM);
        s->s.k = !rsense;
-       b = new_block(cstate, JMP(BPF_JEQ));
-       b->stmts = s;
-
-       return b;
+       return gen_jmp(cstate, BPF_JEQ, 0, s);
 }
 
 static inline struct block *
@@ -2134,8 +2404,7 @@ gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                 * DSAP, as we do for other types <= ETHERMTU
                 * (i.e., other SAP values)?
                 */
-               b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
-               gen_not(b0);
+               b0 = gen_cmp_le(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
                b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
                gen_and(b0, b1);
                return b1;
@@ -2188,8 +2457,7 @@ gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                 * Now we generate code to check for 802.3
                 * frames in general.
                 */
-               b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
-               gen_not(b0);
+               b0 = gen_cmp_le(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
 
                /*
                 * Now add the check for 802.3 frames before the
@@ -2217,11 +2485,10 @@ gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 
                /*
                 * Check for 802.2 encapsulation (EtherTalk phase 2?);
-                * we check for an Ethernet type field less than
+                * we check for an Ethernet type field less or equal than
                 * 1500, which means it's an 802.3 length field.
                 */
-               b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
-               gen_not(b0);
+               b0 = gen_cmp_le(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
 
                /*
                 * 802.2-encapsulated ETHERTYPE_ATALK packets are
@@ -2252,6 +2519,7 @@ gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 
        default:
                if (ll_proto <= ETHERMTU) {
+                       assert_maxval(cstate, "LLC DSAP", ll_proto, UINT8_MAX);
                        /*
                         * This is an LLC SAP value, so the frames
                         * that match would be 802.2 frames.
@@ -2260,12 +2528,12 @@ gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                         * a length field, <= ETHERMTU) and
                         * then check the DSAP.
                         */
-                       b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
-                       gen_not(b0);
+                       b0 = gen_cmp_le(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
                        b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, ll_proto);
                        gen_and(b0, b1);
                        return b1;
                } else {
+                       assert_maxval(cstate, "EtherType", ll_proto, UINT16_MAX);
                        /*
                         * This is an Ethernet type, so compare
                         * the length/type field with it (if
@@ -2465,6 +2733,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 
        default:
                if (ll_proto <= ETHERMTU) {
+                       assert_maxval(cstate, "LLC DSAP", ll_proto, UINT8_MAX);
                        /*
                         * This is an LLC SAP value, so the frames
                         * that match would be 802.2 frames.
@@ -2478,6 +2747,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                        gen_and(b0, b1);
                        return b1;
                } else {
+                       assert_maxval(cstate, "EtherType", ll_proto, UINT16_MAX);
                        /*
                         * This is an Ethernet type, so compare
                         * the length/type field with it (if
@@ -2909,7 +3179,7 @@ gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct sli
         * 0x04 bit (b2) clear.
         */
        sjset_data_frame_1 = new_stmt(cstate, JMP(BPF_JSET));
-       sjset_data_frame_1->s.k = 0x08;
+       sjset_data_frame_1->s.k = IEEE80211_FC0_TYPE_DATA;
        sappend(s, sjset_data_frame_1);
 
        /*
@@ -2917,7 +3187,7 @@ gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct sli
         * the rest of the program.
         */
        sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(cstate, JMP(BPF_JSET));
-       sjset_data_frame_2->s.k = 0x04;
+       sjset_data_frame_2->s.k = IEEE80211_FC0_TYPE_CTL;
        sappend(s, sjset_data_frame_2);
        sjset_data_frame_1->s.jf = snext;
 
@@ -2928,7 +3198,7 @@ gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct sli
         */
        sjset_data_frame_2->s.jt = snext;
        sjset_data_frame_2->s.jf = sjset_qos = new_stmt(cstate, JMP(BPF_JSET));
-       sjset_qos->s.k = 0x80;  /* QoS bit */
+       sjset_qos->s.k = IEEE80211_FC0_SUBTYPE_QOS;
        sappend(s, sjset_qos);
 
        /*
@@ -3172,32 +3442,6 @@ insert_compute_vloffsets(compiler_state_t *cstate, struct block *b)
        }
 }
 
-static struct block *
-gen_ppi_dlt_check(compiler_state_t *cstate)
-{
-       struct slist *s_load_dlt;
-       struct block *b;
-
-       if (cstate->linktype == DLT_PPI)
-       {
-               /* Create the statements that check for the DLT
-                */
-               s_load_dlt = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS);
-               s_load_dlt->s.k = 4;
-
-               b = new_block(cstate, JMP(BPF_JEQ));
-
-               b->stmts = s_load_dlt;
-               b->s.k = SWAPLONG(DLT_IEEE802_11);
-       }
-       else
-       {
-               b = NULL;
-       }
-
-       return b;
-}
-
 /*
  * Take an absolute offset, and:
  *
@@ -3245,34 +3489,28 @@ gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off)
 /*
  * Map an Ethernet type to the equivalent PPP type.
  */
-static bpf_u_int32
-ethertype_to_ppptype(bpf_u_int32 ll_proto)
+static uint16_t
+ethertype_to_ppptype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
        switch (ll_proto) {
 
        case ETHERTYPE_IP:
-               ll_proto = PPP_IP;
-               break;
+               return PPP_IP;
 
        case ETHERTYPE_IPV6:
-               ll_proto = PPP_IPV6;
-               break;
+               return PPP_IPV6;
 
        case ETHERTYPE_DN:
-               ll_proto = PPP_DECNET;
-               break;
+               return PPP_DECNET;
 
        case ETHERTYPE_ATALK:
-               ll_proto = PPP_APPLE;
-               break;
+               return PPP_APPLE;
 
        case ETHERTYPE_NS:
-               ll_proto = PPP_NS;
-               break;
+               return PPP_NS;
 
        case LLCSAP_ISONS:
-               ll_proto = PPP_OSI;
-               break;
+               return PPP_OSI;
 
        case LLCSAP_8021D:
                /*
@@ -3280,14 +3518,13 @@ ethertype_to_ppptype(bpf_u_int32 ll_proto)
                 * over PPP are Spanning Tree Protocol
                 * Bridging PDUs.
                 */
-               ll_proto = PPP_BRPDU;
-               break;
+               return PPP_BRPDU;
 
        case LLCSAP_IPX:
-               ll_proto = PPP_IPX;
-               break;
+               return PPP_IPX;
        }
-       return (ll_proto);
+       assert_maxval(cstate, "PPP protocol", ll_proto, UINT16_MAX);
+       return (uint16_t)ll_proto;
 }
 
 /*
@@ -3299,8 +3536,6 @@ ethertype_to_ppptype(bpf_u_int32 ll_proto)
 static struct block *
 gen_prevlinkhdr_check(compiler_state_t *cstate)
 {
-       struct block *b0;
-
        if (cstate->is_encap)
                return gen_encap_ll_check(cstate);
 
@@ -3314,9 +3549,7 @@ gen_prevlinkhdr_check(compiler_state_t *cstate)
                 *
                 * (We've already generated a test for LANE.)
                 */
-               b0 = gen_cmp(cstate, OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00);
-               gen_not(b0);
-               return b0;
+               return gen_cmp_ne(cstate, OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00);
 
        default:
                /*
@@ -3346,7 +3579,6 @@ static struct block *
 gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
        struct block *b0, *b1, *b2;
-       const char *description;
 
        /* are we checking MPLS-encapsulated packets? */
        if (cstate->label_stack_depth > 0)
@@ -3372,6 +3604,7 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 
        case DLT_C_HDLC:
        case DLT_HDLC:
+               assert_maxval(cstate, "HDLC protocol", ll_proto, UINT16_MAX);
                switch (ll_proto) {
 
                case LLCSAP_ISONS:
@@ -3391,7 +3624,9 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                /*
                 * Check that we have a data frame.
                 */
-               b0 = gen_check_802_11_data_frame(cstate);
+               b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B,
+                       IEEE80211_FC0_TYPE_DATA,
+                       IEEE80211_FC0_TYPE_MASK);
 
                /*
                 * Now check for the specified link-layer type.
@@ -3429,7 +3664,7 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                 *
                 * Check for LLC encapsulation and then check the protocol.
                 */
-               b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+               b0 = gen_atm_prototype(cstate, PT_LLC);
                b1 = gen_llc_linktype(cstate, ll_proto);
                gen_and(b0, b1);
                return b1;
@@ -3495,7 +3730,7 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                 * map them to the corresponding PPP protocol types.
                 */
                return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
-                   ethertype_to_ppptype(ll_proto));
+                   ethertype_to_ppptype(cstate, ll_proto));
                /*NOTREACHED*/
 
        case DLT_PPP_BSDOS:
@@ -3519,7 +3754,7 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 
                default:
                        return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
-                           ethertype_to_ppptype(ll_proto));
+                           ethertype_to_ppptype(cstate, ll_proto));
                }
                /*NOTREACHED*/
 
@@ -3710,7 +3945,7 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                /*NOTREACHED*/
 
        case DLT_MFR:
-               bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented");
+               break; // not implemented
 
        case DLT_JUNIPER_MFR:
        case DLT_JUNIPER_MLFR:
@@ -3751,69 +3986,37 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                return gen_ipnet_linktype(cstate, ll_proto);
 
        case DLT_LINUX_IRDA:
-               bpf_error(cstate, "IrDA link-layer type filtering not implemented");
-
        case DLT_DOCSIS:
-               bpf_error(cstate, "DOCSIS link-layer type filtering not implemented");
-
        case DLT_MTP2:
        case DLT_MTP2_WITH_PHDR:
-               bpf_error(cstate, "MTP2 link-layer type filtering not implemented");
-
        case DLT_ERF:
-               bpf_error(cstate, "ERF link-layer type filtering not implemented");
-
        case DLT_PFSYNC:
-               bpf_error(cstate, "PFSYNC link-layer type filtering not implemented");
-
        case DLT_LINUX_LAPD:
-               bpf_error(cstate, "LAPD link-layer type filtering not implemented");
-
        case DLT_USB_FREEBSD:
        case DLT_USB_LINUX:
        case DLT_USB_LINUX_MMAPPED:
        case DLT_USBPCAP:
-               bpf_error(cstate, "USB link-layer type filtering not implemented");
-
        case DLT_BLUETOOTH_HCI_H4:
        case DLT_BLUETOOTH_HCI_H4_WITH_PHDR:
-               bpf_error(cstate, "Bluetooth link-layer type filtering not implemented");
-
        case DLT_CAN20B:
        case DLT_CAN_SOCKETCAN:
-               bpf_error(cstate, "CAN link-layer type filtering not implemented");
-
        case DLT_IEEE802_15_4:
        case DLT_IEEE802_15_4_LINUX:
        case DLT_IEEE802_15_4_NONASK_PHY:
        case DLT_IEEE802_15_4_NOFCS:
        case DLT_IEEE802_15_4_TAP:
-               bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented");
-
        case DLT_IEEE802_16_MAC_CPS_RADIO:
-               bpf_error(cstate, "IEEE 802.16 link-layer type filtering not implemented");
-
        case DLT_SITA:
-               bpf_error(cstate, "SITA link-layer type filtering not implemented");
-
        case DLT_RAIF1:
-               bpf_error(cstate, "RAIF1 link-layer type filtering not implemented");
-
        case DLT_IPMB_KONTRON:
-               bpf_error(cstate, "IPMB link-layer type filtering not implemented");
-
        case DLT_I2C_LINUX:
-               bpf_error(cstate, "I2C link-layer type filtering not implemented");
-
        case DLT_AX25_KISS:
-               bpf_error(cstate, "AX.25 link-layer type filtering not implemented");
-
        case DLT_NFLOG:
                /* Using the fixed-size NFLOG header it is possible to tell only
                 * the address family of the packet, other meaningful data is
                 * either missing or behind TLVs.
                 */
-               bpf_error(cstate, "NFLOG link-layer type filtering not implemented");
+               break; // not implemented
 
        default:
                /*
@@ -3828,18 +4031,13 @@ gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                         * it's not, it needs to be handled specially
                         * above.)
                         */
+                       assert_maxval(cstate, "EtherType", ll_proto, UINT16_MAX);
                        return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
                        /*NOTREACHED */
-               } else {
-                       /*
-                        * No; report an error.
-                        */
-                       description = pcap_datalink_val_to_description_or_dlt(cstate->linktype);
-                       bpf_error(cstate, "%s link-layer type filtering not implemented",
-                           description);
-                       /*NOTREACHED */
                }
        }
+       bpf_error(cstate, "link-layer type filtering not implemented for %s",
+           pcap_datalink_val_to_description_or_dlt(cstate->linktype));
 }
 
 /*
@@ -3877,18 +4075,16 @@ gen_llc_internal(compiler_state_t *cstate)
 
        case DLT_EN10MB:
                /*
-                * We check for an Ethernet type field less than
+                * We check for an Ethernet type field less or equal than
                 * 1500, which means it's an 802.3 length field.
                 */
-               b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
-               gen_not(b0);
+               b0 = gen_cmp_le(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
 
                /*
                 * Now check for the purported DSAP and SSAP not being
                 * 0xFF, to rule out NetWare-over-802.3.
                 */
-               b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
-               gen_not(b1);
+               b1 = gen_cmp_ne(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
                gen_and(b0, b1);
                return b1;
 
@@ -3896,8 +4092,7 @@ gen_llc_internal(compiler_state_t *cstate)
                /*
                 * We check for LLC traffic.
                 */
-               b0 = gen_atmtype_llc(cstate);
-               return b0;
+               return gen_atmtype_llc(cstate);
 
        case DLT_IEEE802:       /* Token Ring */
                /*
@@ -3930,12 +4125,12 @@ gen_llc_internal(compiler_state_t *cstate)
                /*
                 * Check that we have a data frame.
                 */
-               b0 = gen_check_802_11_data_frame(cstate);
-               return b0;
+               return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B,
+                       IEEE80211_FC0_TYPE_DATA,
+                       IEEE80211_FC0_TYPE_MASK);
 
        default:
-               bpf_error(cstate, "'llc' not supported for %s",
-                         pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+               fail_kw_on_dlt(cstate, "llc");
                /*NOTREACHED*/
        }
 }
@@ -3976,10 +4171,8 @@ gen_llc_i(compiler_state_t *cstate)
         * be clear for I frames.
         */
        s = gen_load_a(cstate, OR_LLC, 2, BPF_B);
-       b1 = new_block(cstate, JMP(BPF_JSET));
-       b1->s.k = 0x01;
-       b1->stmts = s;
-       gen_not(b1);
+       b1 = gen_unset(cstate, 0x01, s);
+
        gen_and(b0, b1);
        return b1;
 }
@@ -4142,12 +4335,14 @@ gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
                 * here, but should we check for the IPX Ethertype?
                 */
                if (ll_proto <= ETHERMTU) {
+                       assert_maxval(cstate, "LLC DSAP", ll_proto, UINT8_MAX);
                        /*
                         * This is an LLC SAP value, so check
                         * the DSAP.
                         */
                        return gen_cmp(cstate, OR_LLC, 0, BPF_B, ll_proto);
                } else {
+                       assert_maxval(cstate, "EtherType", ll_proto, UINT16_MAX);
                        /*
                         * This is an Ethernet type; we assume that it's
                         * unlikely that it'll appear in the right place
@@ -4174,7 +4369,7 @@ gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 
 static struct block *
 gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
-    int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off)
+    int dir, u_int src_off, u_int dst_off)
 {
        struct block *b0, *b1;
        u_int offset;
@@ -4190,57 +4385,38 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
                break;
 
        case Q_AND:
-               b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
-               b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+               b0 = gen_hostop(cstate, addr, mask, Q_SRC, src_off, dst_off);
+               b1 = gen_hostop(cstate, addr, mask, Q_DST, src_off, dst_off);
                gen_and(b0, b1);
                return b1;
 
        case Q_DEFAULT:
        case Q_OR:
-               b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
-               b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+               b0 = gen_hostop(cstate, addr, mask, Q_SRC, src_off, dst_off);
+               b1 = gen_hostop(cstate, addr, mask, Q_DST, src_off, dst_off);
                gen_or(b0, b1);
                return b1;
 
        case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
                /*NOTREACHED*/
 
        default:
                abort();
                /*NOTREACHED*/
        }
-       b0 = gen_linktype(cstate, ll_proto);
-       b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask);
-       gen_and(b0, b1);
-       return b1;
+       return gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask);
 }
 
 #ifdef INET6
 static struct block *
 gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
-    struct in6_addr *mask, int dir, bpf_u_int32 ll_proto, u_int src_off,
-    u_int dst_off)
+    struct in6_addr *mask, int dir, u_int src_off, u_int dst_off)
 {
        struct block *b0, *b1;
        u_int offset;
@@ -4266,40 +4442,25 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
                break;
 
        case Q_AND:
-               b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
-               b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+               b0 = gen_hostop6(cstate, addr, mask, Q_SRC, src_off, dst_off);
+               b1 = gen_hostop6(cstate, addr, mask, Q_DST, src_off, dst_off);
                gen_and(b0, b1);
                return b1;
 
        case Q_DEFAULT:
        case Q_OR:
-               b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
-               b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+               b0 = gen_hostop6(cstate, addr, mask, Q_SRC, src_off, dst_off);
+               b1 = gen_hostop6(cstate, addr, mask, Q_DST, src_off, dst_off);
                gen_or(b0, b1);
                return b1;
 
        case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
                /*NOTREACHED*/
 
        default:
@@ -4309,283 +4470,111 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
        /* this order is important */
        memcpy(a, addr, sizeof(a));
        memcpy(m, mask, sizeof(m));
-       b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
-       b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
-       gen_and(b0, b1);
-       b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1]));
-       gen_and(b0, b1);
-       b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
-       gen_and(b0, b1);
-       b0 = gen_linktype(cstate, ll_proto);
-       gen_and(b0, b1);
-       return b1;
+       b1 = NULL;
+       for (int i = 3; i >= 0; i--) {
+               // Same as the Q_IP case in gen_host().
+               if (m[i] == 0 && a[i] == 0)
+                       continue;
+               b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4 * i, BPF_W,
+                   ntohl(a[i]), ntohl(m[i]));
+               if (b1)
+                       gen_and(b0, b1);
+               else
+                       b1 = b0;
+       }
+       return b1 ? b1 : gen_true(cstate);
 }
 #endif
 
+/*
+ * Like gen_mac48host(), but for DLT_IEEE802_11 (802.11 wireless LAN) and
+ * various 802.11 + radio headers.
+ */
 static struct block *
-gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
 {
-       register struct block *b0, *b1;
+       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
+        */
+       cstate->no_optimize = 1;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
 
        switch (dir) {
        case Q_SRC:
-               return gen_bcmp(cstate, OR_LINKHDR, 6, 6, eaddr);
-
-       case Q_DST:
-               return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr);
+               /*
+                * Oh, yuk.
+                *
+                *      For control frames, there is no SA.
+                *
+                *      For management frames, SA is at an
+                *      offset of 10 from the beginning of
+                *      the packet.
+                *
+                *      For data frames, SA is at an offset
+                *      of 10 from the beginning of the packet
+                *      if From DS is clear, at an offset of
+                *      16 from the beginning of the packet
+                *      if From DS is set and To DS is clear,
+                *      and an offset of 24 from the beginning
+                *      of the packet if From DS is set and To DS
+                *      is set.
+                */
 
-       case Q_AND:
-               b0 = gen_ehostop(cstate, eaddr, Q_SRC);
-               b1 = gen_ehostop(cstate, eaddr, Q_DST);
-               gen_and(b0, b1);
-               return b1;
+               /*
+                * Generate the tests to be done for data frames
+                * with From DS set.
+                *
+                * First, check for To DS set, i.e. check "link[1] & 0x01".
+                */
+               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+               b1 = gen_set(cstate, IEEE80211_FC1_DIR_TODS, s);
 
-       case Q_DEFAULT:
-       case Q_OR:
-               b0 = gen_ehostop(cstate, eaddr, Q_SRC);
-               b1 = gen_ehostop(cstate, eaddr, Q_DST);
-               gen_or(b0, b1);
-               return b1;
+               /*
+                * If To DS is set, the SA is at 24.
+                */
+               b0 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
+               gen_and(b1, b0);
 
-       case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers");
-               /*NOTREACHED*/
+               /*
+                * Now, check for To DS not set, i.e. check
+                * "!(link[1] & 0x01)".
+                */
+               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+               b2 = gen_unset(cstate, IEEE80211_FC1_DIR_TODS, s);
 
-       case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers");
-               /*NOTREACHED*/
+               /*
+                * If To DS is not set, the SA is at 16.
+                */
+               b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+               gen_and(b2, b1);
 
-       case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers");
-               /*NOTREACHED*/
+               /*
+                * Now OR together the last two checks.  That gives
+                * the complete set of checks for data frames with
+                * From DS set.
+                */
+               gen_or(b1, b0);
 
-       case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers");
-               /*NOTREACHED*/
+               /*
+                * Now check for From DS being set, and AND that with
+                * the ORed-together checks.
+                */
+               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+               b1 = gen_set(cstate, IEEE80211_FC1_DIR_FROMDS, s);
+               gen_and(b1, b0);
 
-       case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers");
-               /*NOTREACHED*/
-
-       case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers");
-               /*NOTREACHED*/
-       }
-       abort();
-       /*NOTREACHED*/
-}
-
-/*
- * Like gen_ehostop, but for DLT_FDDI
- */
-static struct block *
-gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
-{
-       struct block *b0, *b1;
-
-       switch (dir) {
-       case Q_SRC:
-               return gen_bcmp(cstate, OR_LINKHDR, 6 + 1 + cstate->pcap_fddipad, 6, eaddr);
-
-       case Q_DST:
-               return gen_bcmp(cstate, OR_LINKHDR, 0 + 1 + cstate->pcap_fddipad, 6, eaddr);
-
-       case Q_AND:
-               b0 = gen_fhostop(cstate, eaddr, Q_SRC);
-               b1 = gen_fhostop(cstate, eaddr, Q_DST);
-               gen_and(b0, b1);
-               return b1;
-
-       case Q_DEFAULT:
-       case Q_OR:
-               b0 = gen_fhostop(cstate, eaddr, Q_SRC);
-               b1 = gen_fhostop(cstate, eaddr, Q_DST);
-               gen_or(b0, b1);
-               return b1;
-
-       case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
-               /*NOTREACHED*/
-       }
-       abort();
-       /*NOTREACHED*/
-}
-
-/*
- * Like gen_ehostop, but for DLT_IEEE802 (Token Ring)
- */
-static struct block *
-gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
-{
-       register struct block *b0, *b1;
-
-       switch (dir) {
-       case Q_SRC:
-               return gen_bcmp(cstate, OR_LINKHDR, 8, 6, eaddr);
-
-       case Q_DST:
-               return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr);
-
-       case Q_AND:
-               b0 = gen_thostop(cstate, eaddr, Q_SRC);
-               b1 = gen_thostop(cstate, eaddr, Q_DST);
-               gen_and(b0, b1);
-               return b1;
-
-       case Q_DEFAULT:
-       case Q_OR:
-               b0 = gen_thostop(cstate, eaddr, Q_SRC);
-               b1 = gen_thostop(cstate, eaddr, Q_DST);
-               gen_or(b0, b1);
-               return b1;
-
-       case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
-               /*NOTREACHED*/
-       }
-       abort();
-       /*NOTREACHED*/
-}
-
-/*
- * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and
- * various 802.11 + radio headers.
- */
-static struct block *
-gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int 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
-        */
-       cstate->no_optimize = 1;
-#endif /* ENABLE_WLAN_FILTERING_PATCH */
-
-       switch (dir) {
-       case Q_SRC:
-               /*
-                * Oh, yuk.
-                *
-                *      For control frames, there is no SA.
-                *
-                *      For management frames, SA is at an
-                *      offset of 10 from the beginning of
-                *      the packet.
-                *
-                *      For data frames, SA is at an offset
-                *      of 10 from the beginning of the packet
-                *      if From DS is clear, at an offset of
-                *      16 from the beginning of the packet
-                *      if From DS is set and To DS is clear,
-                *      and an offset of 24 from the beginning
-                *      of the packet if From DS is set and To DS
-                *      is set.
-                */
-
-               /*
-                * Generate the tests to be done for data frames
-                * with From DS set.
-                *
-                * First, check for To DS set, i.e. check "link[1] & 0x01".
-                */
-               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x01; /* To DS */
-               b1->stmts = s;
-
-               /*
-                * If To DS is set, the SA is at 24.
-                */
-               b0 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
-               gen_and(b1, b0);
-
-               /*
-                * Now, check for To DS not set, i.e. check
-                * "!(link[1] & 0x01)".
-                */
-               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-               b2 = new_block(cstate, JMP(BPF_JSET));
-               b2->s.k = 0x01; /* To DS */
-               b2->stmts = s;
-               gen_not(b2);
-
-               /*
-                * If To DS is not set, the SA is at 16.
-                */
-               b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
-               gen_and(b2, b1);
-
-               /*
-                * Now OR together the last two checks.  That gives
-                * the complete set of checks for data frames with
-                * From DS set.
-                */
-               gen_or(b1, b0);
-
-               /*
-                * Now check for From DS being set, and AND that with
-                * the ORed-together checks.
-                */
-               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x02; /* From DS */
-               b1->stmts = s;
-               gen_and(b1, b0);
-
-               /*
-                * Now check for data frames with From DS not set.
-                */
-               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-               b2 = new_block(cstate, JMP(BPF_JSET));
-               b2->s.k = 0x02; /* From DS */
-               b2->stmts = s;
-               gen_not(b2);
+               /*
+                * Now check for data frames with From DS not set.
+                */
+               s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+               b2 = gen_unset(cstate, IEEE80211_FC1_DIR_FROMDS, s);
 
                /*
                 * If From DS isn't set, the SA is at 10.
@@ -4605,9 +4594,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e, check "link[0] & 0x08".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x08;
-               b1->stmts = s;
+               b1 = gen_set(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                /*
                 * AND that with the checks done for data frames.
@@ -4620,10 +4607,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e, check "!(link[0] & 0x08)".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b2 = new_block(cstate, JMP(BPF_JSET));
-               b2->s.k = 0x08;
-               b2->stmts = s;
-               gen_not(b2);
+               b2 = gen_unset(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                /*
                 * For management frames, the SA is at 10.
@@ -4647,10 +4631,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e., check "!(link[0] & 0x04)".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x04;
-               b1->stmts = s;
-               gen_not(b1);
+               b1 = gen_unset(cstate, IEEE80211_FC0_TYPE_CTL, s);
 
                /*
                 * AND that with the checks for data and management
@@ -4682,9 +4663,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * First, check for To DS set, i.e. "link[1] & 0x01".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x01; /* To DS */
-               b1->stmts = s;
+               b1 = gen_set(cstate, IEEE80211_FC1_DIR_TODS, s);
 
                /*
                 * If To DS is set, the DA is at 16.
@@ -4697,10 +4676,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * "!(link[1] & 0x01)".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-               b2 = new_block(cstate, JMP(BPF_JSET));
-               b2->s.k = 0x01; /* To DS */
-               b2->stmts = s;
-               gen_not(b2);
+               b2 = gen_unset(cstate, IEEE80211_FC1_DIR_TODS, s);
 
                /*
                 * If To DS is not set, the DA is at 4.
@@ -4719,9 +4695,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e, check "link[0] & 0x08".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x08;
-               b1->stmts = s;
+               b1 = gen_set(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                /*
                 * AND that with the checks done for data frames.
@@ -4734,10 +4708,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e, check "!(link[0] & 0x08)".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b2 = new_block(cstate, JMP(BPF_JSET));
-               b2->s.k = 0x08;
-               b2->stmts = s;
-               gen_not(b2);
+               b2 = gen_unset(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                /*
                 * For management frames, the DA is at 4.
@@ -4761,10 +4732,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e., check "!(link[0] & 0x04)".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x04;
-               b1->stmts = s;
-               gen_not(b1);
+               b1 = gen_unset(cstate, IEEE80211_FC0_TYPE_CTL, s);
 
                /*
                 * AND that with the checks for data and management
@@ -4796,15 +4764,12 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                /*
                 * Not present in CTS or ACK control frames.
                 */
-               b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+               b0 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
                        IEEE80211_FC0_TYPE_MASK);
-               gen_not(b0);
-               b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+               b1 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
                        IEEE80211_FC0_SUBTYPE_MASK);
-               gen_not(b1);
-               b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+               b2 = gen_mcmp_ne(cstate, OR_LINKHDR, 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(cstate, OR_LINKHDR, 10, 6, eaddr);
@@ -4815,9 +4780,8 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                /*
                 * Not present in control frames.
                 */
-               b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+               b0 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
                        IEEE80211_FC0_TYPE_MASK);
-               gen_not(b0);
                b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
                gen_and(b0, b1);
                return b1;
@@ -4847,9 +4811,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e, check "(link[0] & 0x08)".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x08;
-               b1->stmts = s;
+               b1 = gen_set(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                /*
                 * Check addr1.
@@ -4871,15 +4833,12 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                /*
                 * Not present in CTS or ACK control frames.
                 */
-               b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+               b0 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
                        IEEE80211_FC0_TYPE_MASK);
-               gen_not(b0);
-               b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+               b1 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
                        IEEE80211_FC0_SUBTYPE_MASK);
-               gen_not(b1);
-               b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+               b2 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
                        IEEE80211_FC0_SUBTYPE_MASK);
-               gen_not(b2);
                gen_and(b1, b2);
                gen_or(b0, b2);
 
@@ -4889,9 +4848,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * I.e, check "(link[0] & 0x08)".
                 */
                s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-               b1 = new_block(cstate, JMP(BPF_JSET));
-               b1->s.k = 0x08;
-               b1->stmts = s;
+               b1 = gen_set(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                /*
                 * AND that with the check for frames other than
@@ -4910,64 +4867,6 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
        /*NOTREACHED*/
 }
 
-/*
- * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel.
- * (We assume that the addresses are IEEE 48-bit MAC addresses,
- * as the RFC states.)
- */
-static struct block *
-gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
-{
-       register struct block *b0, *b1;
-
-       switch (dir) {
-       case Q_SRC:
-               return gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
-
-       case Q_DST:
-               return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr);
-
-       case Q_AND:
-               b0 = gen_ipfchostop(cstate, eaddr, Q_SRC);
-               b1 = gen_ipfchostop(cstate, eaddr, Q_DST);
-               gen_and(b0, b1);
-               return b1;
-
-       case Q_DEFAULT:
-       case Q_OR:
-               b0 = gen_ipfchostop(cstate, eaddr, Q_SRC);
-               b1 = gen_ipfchostop(cstate, eaddr, Q_DST);
-               gen_or(b0, b1);
-               return b1;
-
-       case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               /*NOTREACHED*/
-
-       case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
-               /*NOTREACHED*/
-       }
-       abort();
-       /*NOTREACHED*/
-}
-
 /*
  * This is quite tricky because there may be pad bytes in front of the
  * DECNET header, and then there are two possible data packet formats that
@@ -5021,27 +4920,12 @@ gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir)
                return b1;
 
        case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
-               /*NOTREACHED*/
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
                /*NOTREACHED*/
 
        default:
@@ -5138,16 +5022,16 @@ gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
        case ETHERTYPE_IPV6:
                /* match the bottom-of-stack bit */
                b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
-               /* match the IPv4 version number */
+               /* match the IPv6 version number */
                b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0);
                gen_and(b0, b1);
                return b1;
 
- default:
-        /* FIXME add other L3 proto IDs */
-        bpf_error(cstate, "unsupported protocol over mpls");
-        /*NOTREACHED*/
- }
      default:
+               /* FIXME add other L3 proto IDs */
+               bpf_error(cstate, "unsupported protocol over mpls");
+               /*NOTREACHED*/
      }
 }
 
 static struct block *
@@ -5155,12 +5039,6 @@ gen_host(compiler_state_t *cstate, 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) {
 
@@ -5179,37 +5057,50 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
                return b0;
 
        case Q_LINK:
-               bpf_error(cstate, "link-layer modifier applied to %s", typestr);
+               // "link net NETNAME" and variations thereof
+               break; // invalid qualifier
 
        case Q_IP:
-               return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16);
+               b0 = gen_linktype(cstate, ETHERTYPE_IP);
+               /*
+                * Belt and braces: if other code works correctly, any host
+                * bits are clear and mask == 0 means addr == 0.  In this case
+                * the call to gen_hostop() would produce an "always true"
+                * instruction block and ANDing it with the link type check
+                * would be a no-op.
+                */
+               if (mask == 0 && addr == 0)
+                       return b0;
+               b1 = gen_hostop(cstate, addr, mask, dir, 12, 16);
+               gen_and(b0, b1);
+               return b1;
 
        case Q_RARP:
-               return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_REVARP, 14, 24);
+               b0 = gen_linktype(cstate, ETHERTYPE_REVARP);
+               // Same as for Q_IP above.
+               if (mask == 0 && addr == 0)
+                       return b0;
+               b1 = gen_hostop(cstate, addr, mask, dir, 14, 24);
+               gen_and(b0, b1);
+               return b1;
 
        case Q_ARP:
-               return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24);
+               b0 = gen_linktype(cstate, ETHERTYPE_ARP);
+               // Same as for Q_IP above.
+               if (mask == 0 && addr == 0)
+                       return b0;
+               b1 = gen_hostop(cstate, addr, mask, dir, 14, 24);
+               gen_and(b0, b1);
+               return b1;
 
        case Q_SCTP:
-               bpf_error(cstate, "'sctp' modifier applied to %s", typestr);
-
        case Q_TCP:
-               bpf_error(cstate, "'tcp' modifier applied to %s", typestr);
-
        case Q_UDP:
-               bpf_error(cstate, "'udp' modifier applied to %s", typestr);
-
        case Q_ICMP:
-               bpf_error(cstate, "'icmp' modifier applied to %s", typestr);
-
        case Q_IGMP:
-               bpf_error(cstate, "'igmp' modifier applied to %s", typestr);
-
        case Q_IGRP:
-               bpf_error(cstate, "'igrp' modifier applied to %s", typestr);
-
        case Q_ATALK:
-               bpf_error(cstate, "AppleTalk host filtering not implemented");
+               break; // invalid qualifier
 
        case Q_DECNET:
                b0 = gen_linktype(cstate, ETHERTYPE_DN);
@@ -5218,89 +5109,39 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
                return b1;
 
        case Q_LAT:
-               bpf_error(cstate, "LAT host filtering not implemented");
-
        case Q_SCA:
-               bpf_error(cstate, "SCA host filtering not implemented");
-
        case Q_MOPRC:
-               bpf_error(cstate, "MOPRC host filtering not implemented");
-
        case Q_MOPDL:
-               bpf_error(cstate, "MOPDL host filtering not implemented");
-
        case Q_IPV6:
-               bpf_error(cstate, "'ip6' modifier applied to ip host");
-
        case Q_ICMPV6:
-               bpf_error(cstate, "'icmp6' modifier applied to %s", typestr);
-
        case Q_AH:
-               bpf_error(cstate, "'ah' modifier applied to %s", typestr);
-
        case Q_ESP:
-               bpf_error(cstate, "'esp' modifier applied to %s", typestr);
-
        case Q_PIM:
-               bpf_error(cstate, "'pim' modifier applied to %s", typestr);
-
        case Q_VRRP:
-               bpf_error(cstate, "'vrrp' modifier applied to %s", typestr);
-
        case Q_AARP:
-               bpf_error(cstate, "AARP host filtering not implemented");
-
        case Q_ISO:
-               bpf_error(cstate, "ISO host filtering not implemented");
-
        case Q_ESIS:
-               bpf_error(cstate, "'esis' modifier applied to %s", typestr);
-
        case Q_ISIS:
-               bpf_error(cstate, "'isis' modifier applied to %s", typestr);
-
        case Q_CLNP:
-               bpf_error(cstate, "'clnp' modifier applied to %s", typestr);
-
        case Q_STP:
-               bpf_error(cstate, "'stp' modifier applied to %s", typestr);
-
        case Q_IPX:
-               bpf_error(cstate, "IPX host filtering not implemented");
-
        case Q_NETBEUI:
-               bpf_error(cstate, "'netbeui' modifier applied to %s", typestr);
-
        case Q_ISIS_L1:
-               bpf_error(cstate, "'l1' modifier applied to %s", typestr);
-
        case Q_ISIS_L2:
-               bpf_error(cstate, "'l2' modifier applied to %s", typestr);
-
        case Q_ISIS_IIH:
-               bpf_error(cstate, "'iih' modifier applied to %s", typestr);
-
        case Q_ISIS_SNP:
-               bpf_error(cstate, "'snp' modifier applied to %s", typestr);
-
        case Q_ISIS_CSNP:
-               bpf_error(cstate, "'csnp' modifier applied to %s", typestr);
-
        case Q_ISIS_PSNP:
-               bpf_error(cstate, "'psnp' modifier applied to %s", typestr);
-
        case Q_ISIS_LSP:
-               bpf_error(cstate, "'lsp' modifier applied to %s", typestr);
-
        case Q_RADIO:
-               bpf_error(cstate, "'radio' modifier applied to %s", typestr);
-
        case Q_CARP:
-               bpf_error(cstate, "'carp' modifier applied to %s", typestr);
+               break; // invalid qualifier
 
        default:
                abort();
        }
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto),
+           type == Q_NET ? "ip net" : "ip host");
        /*NOTREACHED*/
 }
 
@@ -5309,195 +5150,189 @@ static struct block *
 gen_host6(compiler_state_t *cstate, 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";
+       struct block *b0, *b1;
 
        switch (proto) {
 
        case Q_DEFAULT:
-               return gen_host6(cstate, addr, mask, Q_IPV6, dir, type);
+       case Q_IPV6:
+               b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+               // Same as the Q_IP case in gen_host().
+               if (
+                       ! memcmp(mask, &in6addr_any, sizeof(struct in6_addr)) &&
+                       ! memcmp(addr, &in6addr_any, sizeof(struct in6_addr))
+               )
+                       return b0;
+               b1 = gen_hostop6(cstate, addr, mask, dir, 8, 24);
+               gen_and(b0, b1);
+               return b1;
 
        case Q_LINK:
-               bpf_error(cstate, "link-layer modifier applied to ip6 %s", typestr);
-
        case Q_IP:
-               bpf_error(cstate, "'ip' modifier applied to ip6 %s", typestr);
-
        case Q_RARP:
-               bpf_error(cstate, "'rarp' modifier applied to ip6 %s", typestr);
-
        case Q_ARP:
-               bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr);
-
        case Q_SCTP:
-               bpf_error(cstate, "'sctp' modifier applied to ip6 %s", typestr);
-
        case Q_TCP:
-               bpf_error(cstate, "'tcp' modifier applied to ip6 %s", typestr);
-
        case Q_UDP:
-               bpf_error(cstate, "'udp' modifier applied to ip6 %s", typestr);
-
        case Q_ICMP:
-               bpf_error(cstate, "'icmp' modifier applied to ip6 %s", typestr);
-
        case Q_IGMP:
-               bpf_error(cstate, "'igmp' modifier applied to ip6 %s", typestr);
-
        case Q_IGRP:
-               bpf_error(cstate, "'igrp' modifier applied to ip6 %s", typestr);
-
        case Q_ATALK:
-               bpf_error(cstate, "AppleTalk modifier applied to ip6 %s", typestr);
-
        case Q_DECNET:
-               bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr);
-
        case Q_LAT:
-               bpf_error(cstate, "'lat' modifier applied to ip6 %s", typestr);
-
        case Q_SCA:
-               bpf_error(cstate, "'sca' modifier applied to ip6 %s", typestr);
-
        case Q_MOPRC:
-               bpf_error(cstate, "'moprc' modifier applied to ip6 %s", typestr);
-
        case Q_MOPDL:
-               bpf_error(cstate, "'mopdl' modifier applied to ip6 %s", typestr);
-
-       case Q_IPV6:
-               return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24);
-
        case Q_ICMPV6:
-               bpf_error(cstate, "'icmp6' modifier applied to ip6 %s", typestr);
-
        case Q_AH:
-               bpf_error(cstate, "'ah' modifier applied to ip6 %s", typestr);
-
        case Q_ESP:
-               bpf_error(cstate, "'esp' modifier applied to ip6 %s", typestr);
-
        case Q_PIM:
-               bpf_error(cstate, "'pim' modifier applied to ip6 %s", typestr);
-
        case Q_VRRP:
-               bpf_error(cstate, "'vrrp' modifier applied to ip6 %s", typestr);
-
        case Q_AARP:
-               bpf_error(cstate, "'aarp' modifier applied to ip6 %s", typestr);
-
        case Q_ISO:
-               bpf_error(cstate, "'iso' modifier applied to ip6 %s", typestr);
-
        case Q_ESIS:
-               bpf_error(cstate, "'esis' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS:
-               bpf_error(cstate, "'isis' modifier applied to ip6 %s", typestr);
-
        case Q_CLNP:
-               bpf_error(cstate, "'clnp' modifier applied to ip6 %s", typestr);
-
        case Q_STP:
-               bpf_error(cstate, "'stp' modifier applied to ip6 %s", typestr);
-
        case Q_IPX:
-               bpf_error(cstate, "'ipx' modifier applied to ip6 %s", typestr);
-
        case Q_NETBEUI:
-               bpf_error(cstate, "'netbeui' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS_L1:
-               bpf_error(cstate, "'l1' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS_L2:
-               bpf_error(cstate, "'l2' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS_IIH:
-               bpf_error(cstate, "'iih' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS_SNP:
-               bpf_error(cstate, "'snp' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS_CSNP:
-               bpf_error(cstate, "'csnp' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS_PSNP:
-               bpf_error(cstate, "'psnp' modifier applied to ip6 %s", typestr);
-
        case Q_ISIS_LSP:
-               bpf_error(cstate, "'lsp' modifier applied to ip6 %s", typestr);
-
        case Q_RADIO:
-               bpf_error(cstate, "'radio' modifier applied to ip6 %s", typestr);
-
        case Q_CARP:
-               bpf_error(cstate, "'carp' modifier applied to ip6 %s", typestr);
+               break; // invalid qualifier
 
        default:
                abort();
        }
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto),
+           type == Q_NET ? "ip6 net" : "ip6 host");
        /*NOTREACHED*/
 }
 #endif
 
+static unsigned char
+is_mac48_linktype(const int linktype)
+{
+       switch (linktype) {
+       case DLT_EN10MB:
+       case DLT_FDDI:
+       case DLT_IEEE802:
+       case DLT_IEEE802_11:
+       case DLT_IEEE802_11_RADIO:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IP_OVER_FC:
+       case DLT_NETANALYZER:
+       case DLT_NETANALYZER_TRANSPARENT:
+       case DLT_PPI:
+       case DLT_PRISM_HEADER:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static struct block *
+gen_mac48host(compiler_state_t *cstate, const u_char *eaddr, const u_char dir,
+    const char *keyword)
+{
+       struct block *b1 = NULL;
+       u_int src_off, dst_off;
+
+       switch (cstate->linktype) {
+       case DLT_EN10MB:
+       case DLT_NETANALYZER:
+       case DLT_NETANALYZER_TRANSPARENT:
+               b1 = gen_prevlinkhdr_check(cstate);
+               src_off = 6;
+               dst_off = 0;
+               break;
+       case DLT_FDDI:
+               src_off = 6 + 1 + cstate->pcap_fddipad;
+               dst_off = 0 + 1 + cstate->pcap_fddipad;
+               break;
+       case DLT_IEEE802:
+               src_off = 8;
+               dst_off = 2;
+               break;
+       case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
+       case DLT_PPI:
+               return gen_wlanhostop(cstate, eaddr, dir);
+       case DLT_IP_OVER_FC:
+               /*
+                * Assume that the addresses are IEEE 48-bit MAC addresses,
+                * as RFC 2625 states.
+                */
+               src_off = 10;
+               dst_off = 2;
+               break;
+       case DLT_SUNATM:
+               /*
+                * This is LLC-multiplexed traffic; if it were
+                * LANE, cstate->linktype would have been set to
+                * DLT_EN10MB.
+                */
+                /* FALLTHROUGH */
+       default:
+               fail_kw_on_dlt(cstate, keyword);
+       }
+
+       struct block *b0, *tmp;
+
+       switch (dir) {
+       case Q_SRC:
+               b0 = gen_bcmp(cstate, OR_LINKHDR, src_off, 6, eaddr);
+               break;
+       case Q_DST:
+               b0 = gen_bcmp(cstate, OR_LINKHDR, dst_off, 6, eaddr);
+               break;
+       case Q_AND:
+               tmp = gen_bcmp(cstate, OR_LINKHDR, src_off, 6, eaddr);
+               b0 = gen_bcmp(cstate, OR_LINKHDR, dst_off, 6, eaddr);
+               gen_and(tmp, b0);
+               break;
+       case Q_DEFAULT:
+       case Q_OR:
+               tmp = gen_bcmp(cstate, OR_LINKHDR, src_off, 6, eaddr);
+               b0 = gen_bcmp(cstate, OR_LINKHDR, dst_off, 6, eaddr);
+               gen_or(tmp, b0);
+               break;
+       default:
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
+       }
+
+       if (b1 != NULL)
+               gen_and(b1, b0);
+       return b0;
+}
+
 #ifndef INET6
+/*
+ * This primitive is non-directional by design, so the grammar does not allow
+ * to qualify it with a direction.
+ */
 static struct block *
 gen_gateway(compiler_state_t *cstate, const u_char *eaddr,
-    struct addrinfo *alist, int proto, int dir)
+    struct addrinfo *alist, int proto)
 {
        struct block *b0, *b1, *tmp;
        struct addrinfo *ai;
        struct sockaddr_in *sin;
 
-       if (dir != 0)
-               bpf_error(cstate, "direction applied to 'gateway'");
-
        switch (proto) {
        case Q_DEFAULT:
        case Q_IP:
        case Q_ARP:
        case Q_RARP:
-               switch (cstate->linktype) {
-               case DLT_EN10MB:
-               case DLT_NETANALYZER:
-               case DLT_NETANALYZER_TRANSPARENT:
-                       b1 = gen_prevlinkhdr_check(cstate);
-                       b0 = gen_ehostop(cstate, eaddr, Q_OR);
-                       if (b1 != NULL)
-                               gen_and(b1, b0);
-                       break;
-               case DLT_FDDI:
-                       b0 = gen_fhostop(cstate, eaddr, Q_OR);
-                       break;
-               case DLT_IEEE802:
-                       b0 = gen_thostop(cstate, eaddr, Q_OR);
-                       break;
-               case DLT_IEEE802_11:
-               case DLT_PRISM_HEADER:
-               case DLT_IEEE802_11_RADIO_AVS:
-               case DLT_IEEE802_11_RADIO:
-               case DLT_PPI:
-                       b0 = gen_wlanhostop(cstate, eaddr, Q_OR);
-                       break;
-               case DLT_IP_OVER_FC:
-                       b0 = gen_ipfchostop(cstate, eaddr, Q_OR);
-                       break;
-               case DLT_SUNATM:
-                       /*
-                        * This is LLC-multiplexed traffic; if it were
-                        * LANE, cstate->linktype would have been set to
-                        * DLT_EN10MB.
-                        */
-                        /* FALLTHROUGH */
-               default:
-                       bpf_error(cstate,
-                           "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
-               }
+               b0 = gen_mac48host(cstate, eaddr, Q_OR, "gateway");
                b1 = NULL;
                for (ai = alist; ai != NULL; ai = ai->ai_next) {
                        /*
@@ -5545,7 +5380,7 @@ gen_gateway(compiler_state_t *cstate, const u_char *eaddr,
                gen_and(b0, b1);
                return b1;
        }
-       bpf_error(cstate, "illegal modifier of 'gateway'");
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "gateway");
        /*NOTREACHED*/
 }
 #endif
@@ -5559,223 +5394,193 @@ gen_proto_abbrev_internal(compiler_state_t *cstate, int proto)
        switch (proto) {
 
        case Q_SCTP:
-               b1 = gen_proto(cstate, IPPROTO_SCTP, Q_DEFAULT, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_SCTP, Q_DEFAULT);
 
        case Q_TCP:
-               b1 = gen_proto(cstate, IPPROTO_TCP, Q_DEFAULT, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_TCP, Q_DEFAULT);
 
        case Q_UDP:
-               b1 = gen_proto(cstate, IPPROTO_UDP, Q_DEFAULT, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_UDP, Q_DEFAULT);
 
        case Q_ICMP:
-               b1 = gen_proto(cstate, IPPROTO_ICMP, Q_IP, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_ICMP, Q_IP);
 
 #ifndef        IPPROTO_IGMP
 #define        IPPROTO_IGMP    2
 #endif
 
        case Q_IGMP:
-               b1 = gen_proto(cstate, IPPROTO_IGMP, Q_IP, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_IGMP, Q_IP);
 
 #ifndef        IPPROTO_IGRP
 #define        IPPROTO_IGRP    9
 #endif
        case Q_IGRP:
-               b1 = gen_proto(cstate, IPPROTO_IGRP, Q_IP, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_IGRP, Q_IP);
 
 #ifndef IPPROTO_PIM
 #define IPPROTO_PIM    103
 #endif
 
        case Q_PIM:
-               b1 = gen_proto(cstate, IPPROTO_PIM, Q_DEFAULT, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_PIM, Q_DEFAULT);
 
 #ifndef IPPROTO_VRRP
 #define IPPROTO_VRRP   112
 #endif
 
        case Q_VRRP:
-               b1 = gen_proto(cstate, IPPROTO_VRRP, Q_IP, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_VRRP, Q_IP);
 
 #ifndef IPPROTO_CARP
 #define IPPROTO_CARP   112
 #endif
 
        case Q_CARP:
-               b1 = gen_proto(cstate, IPPROTO_CARP, Q_IP, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_CARP, Q_IP);
 
        case Q_IP:
-               b1 = gen_linktype(cstate, ETHERTYPE_IP);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_IP);
 
        case Q_ARP:
-               b1 = gen_linktype(cstate, ETHERTYPE_ARP);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_ARP);
 
        case Q_RARP:
-               b1 = gen_linktype(cstate, ETHERTYPE_REVARP);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_REVARP);
 
        case Q_LINK:
-               bpf_error(cstate, "link layer applied in wrong context");
+               break; // invalid syntax
 
        case Q_ATALK:
-               b1 = gen_linktype(cstate, ETHERTYPE_ATALK);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_ATALK);
 
        case Q_AARP:
-               b1 = gen_linktype(cstate, ETHERTYPE_AARP);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_AARP);
 
        case Q_DECNET:
-               b1 = gen_linktype(cstate, ETHERTYPE_DN);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_DN);
 
        case Q_SCA:
-               b1 = gen_linktype(cstate, ETHERTYPE_SCA);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_SCA);
 
        case Q_LAT:
-               b1 = gen_linktype(cstate, ETHERTYPE_LAT);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_LAT);
 
        case Q_MOPDL:
-               b1 = gen_linktype(cstate, ETHERTYPE_MOPDL);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_MOPDL);
 
        case Q_MOPRC:
-               b1 = gen_linktype(cstate, ETHERTYPE_MOPRC);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_MOPRC);
 
        case Q_IPV6:
-               b1 = gen_linktype(cstate, ETHERTYPE_IPV6);
-               break;
+               return gen_linktype(cstate, ETHERTYPE_IPV6);
 
 #ifndef IPPROTO_ICMPV6
 #define IPPROTO_ICMPV6 58
 #endif
        case Q_ICMPV6:
-               b1 = gen_proto(cstate, IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_ICMPV6, Q_IPV6);
 
 #ifndef IPPROTO_AH
 #define IPPROTO_AH     51
 #endif
        case Q_AH:
-               b1 = gen_proto(cstate, IPPROTO_AH, Q_DEFAULT, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_AH, Q_DEFAULT);
 
 #ifndef IPPROTO_ESP
 #define IPPROTO_ESP    50
 #endif
        case Q_ESP:
-               b1 = gen_proto(cstate, IPPROTO_ESP, Q_DEFAULT, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, IPPROTO_ESP, Q_DEFAULT);
 
        case Q_ISO:
-               b1 = gen_linktype(cstate, LLCSAP_ISONS);
-               break;
+               return gen_linktype(cstate, LLCSAP_ISONS);
 
        case Q_ESIS:
-               b1 = gen_proto(cstate, ISO9542_ESIS, Q_ISO, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, ISO9542_ESIS, Q_ISO);
 
        case Q_ISIS:
-               b1 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, ISO10589_ISIS, Q_ISO);
 
        case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */
-               b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT);
-               b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */
+               b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS);
+               b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS); /* FIXME extract the circuit-type bits */
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS);
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS);
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS);
                gen_or(b0, b1);
-               break;
+               return b1;
 
        case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */
-               b0 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT);
-               b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */
+               b0 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS);
+               b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS); /* FIXME extract the circuit-type bits */
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS);
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS);
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS);
                gen_or(b0, b1);
-               break;
+               return b1;
 
        case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */
-               b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT);
-               b1 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS);
+               b1 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS);
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS);
                gen_or(b0, b1);
-               break;
+               return b1;
 
        case Q_ISIS_LSP:
-               b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT);
-               b1 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS);
+               b1 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS);
                gen_or(b0, b1);
-               break;
+               return b1;
 
        case Q_ISIS_SNP:
-               b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
-               b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS);
+               b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS);
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS);
                gen_or(b0, b1);
-               b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS);
                gen_or(b0, b1);
-               break;
+               return b1;
 
        case Q_ISIS_CSNP:
-               b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
-               b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS);
+               b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS);
                gen_or(b0, b1);
-               break;
+               return b1;
 
        case Q_ISIS_PSNP:
-               b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
-               b1 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+               b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS);
+               b1 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS);
                gen_or(b0, b1);
-               break;
+               return b1;
 
        case Q_CLNP:
-               b1 = gen_proto(cstate, ISO8473_CLNP, Q_ISO, Q_DEFAULT);
-               break;
+               return gen_proto(cstate, ISO8473_CLNP, Q_ISO);
 
        case Q_STP:
-               b1 = gen_linktype(cstate, LLCSAP_8021D);
-               break;
+               return gen_linktype(cstate, LLCSAP_8021D);
 
        case Q_IPX:
-               b1 = gen_linktype(cstate, LLCSAP_IPX);
-               break;
+               return gen_linktype(cstate, LLCSAP_IPX);
 
        case Q_NETBEUI:
-               b1 = gen_linktype(cstate, LLCSAP_NETBEUI);
-               break;
+               return gen_linktype(cstate, LLCSAP_NETBEUI);
 
        case Q_RADIO:
-               bpf_error(cstate, "'radio' is not a valid protocol type");
+               break; // invalid syntax
 
        default:
                abort();
        }
-       return b1;
+       bpf_error(cstate, "'%s' cannot be used as an abbreviation", pqkw(proto));
 }
 
 struct block *
@@ -5791,20 +5596,26 @@ gen_proto_abbrev(compiler_state_t *cstate, int proto)
        return gen_proto_abbrev_internal(cstate, proto);
 }
 
+static struct block *
+gen_ip_proto(compiler_state_t *cstate, const uint8_t proto)
+{
+       return gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
+}
+
+static struct block *
+gen_ip6_proto(compiler_state_t *cstate, const uint8_t proto)
+{
+       return gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
+}
+
 static struct block *
 gen_ipfrag(compiler_state_t *cstate)
 {
        struct slist *s;
-       struct block *b;
 
        /* not IPv4 frag other than the first frag */
        s = gen_load_a(cstate, OR_LINKPL, 6, BPF_H);
-       b = new_block(cstate, JMP(BPF_JSET));
-       b->s.k = 0x1fff;
-       b->stmts = s;
-       gen_not(b);
-
-       return b;
+       return gen_unset(cstate, 0x1fff, s);
 }
 
 /*
@@ -5817,26 +5628,21 @@ gen_ipfrag(compiler_state_t *cstate)
  * headers).
  */
 static struct block *
-gen_portatom(compiler_state_t *cstate, int off, bpf_u_int32 v)
+gen_portatom(compiler_state_t *cstate, int off, uint16_t v)
 {
        return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v);
 }
 
 static struct block *
-gen_portatom6(compiler_state_t *cstate, int off, bpf_u_int32 v)
+gen_portatom6(compiler_state_t *cstate, int off, uint16_t v)
 {
        return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v);
 }
 
 static struct block *
-gen_portop(compiler_state_t *cstate, u_int port, u_int proto, int dir)
+gen_port(compiler_state_t *cstate, uint16_t port, int proto, int dir)
 {
-       struct block *b0, *b1, *tmp;
-
-       /* ip proto 'proto' and not a fragment other than the first fragment */
-       tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
-       b0 = gen_ipfrag(cstate);
-       gen_and(tmp, b0);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
@@ -5861,42 +5667,26 @@ gen_portop(compiler_state_t *cstate, u_int port, u_int proto, int dir)
                break;
 
        case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for ports");
-               /*NOTREACHED*/
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for ports");
-               /*NOTREACHED*/
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for ports");
-               /*NOTREACHED*/
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for ports");
-               /*NOTREACHED*/
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is not a valid qualifier for ports");
-               /*NOTREACHED*/
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is not a valid qualifier for ports");
+               bpf_error(cstate, ERRSTR_INVALID_QUAL, dqkw(dir), "port");
                /*NOTREACHED*/
 
        default:
                abort();
                /*NOTREACHED*/
        }
-       gen_and(b0, b1);
 
-       return b1;
+       return gen_port_common(cstate, proto, b1);
 }
 
 static struct block *
-gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
+gen_port_common(compiler_state_t *cstate, int proto, struct block *b1)
 {
-       struct block *b0, *b1, *tmp;
+       struct block *b0, *tmp;
 
        /*
         * ether proto ip
@@ -5914,39 +5704,47 @@ gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
         * encapsulation with LLCSAP_IP.
         *
         * So we always check for ETHERTYPE_IP.
+        *
+        * At the time of this writing all three L4 protocols the "port" and
+        * "portrange" primitives support (TCP, UDP and SCTP) have the source
+        * and the destination ports identically encoded in the transport
+        * protocol header.  So without a proto qualifier the only difference
+        * between the implemented cases is the protocol number and all other
+        * checks need to be made exactly once.
+        *
+        * If the expression syntax in future starts to support ports for
+        * another L4 protocol that has unsigned integer ports encoded using a
+        * different size and/or offset, this will require a different code.
         */
-       b0 = gen_linktype(cstate, ETHERTYPE_IP);
-
-       switch (ip_proto) {
+       switch (proto) {
        case IPPROTO_UDP:
        case IPPROTO_TCP:
        case IPPROTO_SCTP:
-               b1 = gen_portop(cstate, port, (u_int)ip_proto, dir);
+               tmp = gen_ip_proto(cstate, (uint8_t)proto);
                break;
 
        case PROTO_UNDEF:
-               tmp = gen_portop(cstate, port, IPPROTO_TCP, dir);
-               b1 = gen_portop(cstate, port, IPPROTO_UDP, dir);
-               gen_or(tmp, b1);
-               tmp = gen_portop(cstate, port, IPPROTO_SCTP, dir);
-               gen_or(tmp, b1);
+               tmp = gen_ip_proto(cstate, IPPROTO_UDP);
+               gen_or(gen_ip_proto(cstate, IPPROTO_TCP), tmp);
+               gen_or(gen_ip_proto(cstate, IPPROTO_SCTP), tmp);
                break;
 
        default:
                abort();
        }
+       // Not a fragment other than the first fragment.
+       b0 = gen_ipfrag(cstate);
+       gen_and(tmp, b0);
        gen_and(b0, b1);
+       // "link proto \ip"
+       gen_and(gen_linktype(cstate, ETHERTYPE_IP), b1);
        return b1;
 }
 
-struct block *
-gen_portop6(compiler_state_t *cstate, u_int port, u_int proto, int dir)
+static struct block *
+gen_port6(compiler_state_t *cstate, uint16_t port, int proto, int dir)
 {
-       struct block *b0, *b1, *tmp;
-
-       /* ip6 proto 'proto' */
-       /* XXX - catch the first fragment of a fragmented packet? */
-       b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
@@ -5973,61 +5771,52 @@ gen_portop6(compiler_state_t *cstate, u_int port, u_int proto, int dir)
        default:
                abort();
        }
-       gen_and(b0, b1);
 
-       return b1;
+       return gen_port6_common(cstate, proto, b1);
 }
 
 static struct block *
-gen_port6(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
+gen_port6_common(compiler_state_t *cstate, int proto, struct block *b1)
 {
-       struct block *b0, *b1, *tmp;
-
-       /* link proto ip6 */
-       b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+       struct block *tmp;
 
-       switch (ip_proto) {
+       // "ip6 proto 'ip_proto'"
+       switch (proto) {
        case IPPROTO_UDP:
        case IPPROTO_TCP:
        case IPPROTO_SCTP:
-               b1 = gen_portop6(cstate, port, (u_int)ip_proto, dir);
+               tmp = gen_ip6_proto(cstate, (uint8_t)proto);
                break;
 
        case PROTO_UNDEF:
-               tmp = gen_portop6(cstate, port, IPPROTO_TCP, dir);
-               b1 = gen_portop6(cstate, port, IPPROTO_UDP, dir);
-               gen_or(tmp, b1);
-               tmp = gen_portop6(cstate, port, IPPROTO_SCTP, dir);
-               gen_or(tmp, b1);
+               // Same as in gen_port_common().
+               tmp = gen_ip6_proto(cstate, IPPROTO_UDP);
+               gen_or(gen_ip6_proto(cstate, IPPROTO_TCP), tmp);
+               gen_or(gen_ip6_proto(cstate, IPPROTO_SCTP), tmp);
                break;
 
        default:
                abort();
        }
-       gen_and(b0, b1);
+       // XXX - catch the first fragment of a fragmented packet?
+       gen_and(tmp, b1);
+       // "link proto \ip6"
+       gen_and(gen_linktype(cstate, ETHERTYPE_IPV6), b1);
        return b1;
 }
 
 /* gen_portrange code */
 static struct block *
-gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
-    bpf_u_int32 v2)
+gen_portrangeatom(compiler_state_t *cstate, u_int off, uint16_t v1,
+    uint16_t v2)
 {
-       struct block *b1, *b2;
-
-       if (v1 > v2) {
-               /*
-                * Reverse the order of the ports, so v1 is the lower one.
-                */
-               bpf_u_int32 vtemp;
+       if (v1 == v2)
+               return gen_portatom(cstate, off, v1);
 
-               vtemp = v1;
-               v1 = v2;
-               v2 = vtemp;
-       }
+       struct block *b1, *b2;
 
-       b1 = gen_cmp_ge(cstate, OR_TRAN_IPV4, off, BPF_H, v1);
-       b2 = gen_cmp_le(cstate, OR_TRAN_IPV4, off, BPF_H, v2);
+       b1 = gen_cmp_ge(cstate, OR_TRAN_IPV4, off, BPF_H, min(v1, v2));
+       b2 = gen_cmp_le(cstate, OR_TRAN_IPV4, off, BPF_H, max(v1, v2));
 
        gen_and(b1, b2);
 
@@ -6035,15 +5824,10 @@ gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
 }
 
 static struct block *
-gen_portrangeop(compiler_state_t *cstate, u_int port1, u_int port2,
-    bpf_u_int32 proto, int dir)
+gen_portrange(compiler_state_t *cstate, uint16_t port1, uint16_t port2,
+    int proto, int dir)
 {
-       struct block *b0, *b1, *tmp;
-
-       /* ip proto 'proto' and not a fragment other than the first fragment */
-       tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
-       b0 = gen_ipfrag(cstate);
-       gen_and(tmp, b0);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
@@ -6068,89 +5852,33 @@ gen_portrangeop(compiler_state_t *cstate, u_int port1, u_int port2,
                break;
 
        case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for port ranges");
-               /*NOTREACHED*/
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for port ranges");
-               /*NOTREACHED*/
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for port ranges");
-               /*NOTREACHED*/
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for port ranges");
-               /*NOTREACHED*/
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is not a valid qualifier for port ranges");
-               /*NOTREACHED*/
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is not a valid qualifier for port ranges");
+               bpf_error(cstate, ERRSTR_INVALID_QUAL, dqkw(dir), "portrange");
                /*NOTREACHED*/
 
        default:
                abort();
                /*NOTREACHED*/
        }
-       gen_and(b0, b1);
 
-       return b1;
+       return gen_port_common(cstate, proto, b1);
 }
 
 static struct block *
-gen_portrange(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
-    int dir)
+gen_portrangeatom6(compiler_state_t *cstate, u_int off, uint16_t v1,
+    uint16_t v2)
 {
-       struct block *b0, *b1, *tmp;
-
-       /* link proto ip */
-       b0 = gen_linktype(cstate, ETHERTYPE_IP);
-
-       switch (ip_proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_SCTP:
-               b1 = gen_portrangeop(cstate, port1, port2, (bpf_u_int32)ip_proto,
-                   dir);
-               break;
-
-       case PROTO_UNDEF:
-               tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_TCP, dir);
-               b1 = gen_portrangeop(cstate, port1, port2, IPPROTO_UDP, dir);
-               gen_or(tmp, b1);
-               tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_SCTP, dir);
-               gen_or(tmp, b1);
-               break;
-
-       default:
-               abort();
-       }
-       gen_and(b0, b1);
-       return b1;
-}
+       if (v1 == v2)
+               return gen_portatom6(cstate, off, v1);
 
-static struct block *
-gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
-    bpf_u_int32 v2)
-{
        struct block *b1, *b2;
 
-       if (v1 > v2) {
-               /*
-                * Reverse the order of the ports, so v1 is the lower one.
-                */
-               bpf_u_int32 vtemp;
-
-               vtemp = v1;
-               v1 = v2;
-               v2 = vtemp;
-       }
-
-       b1 = gen_cmp_ge(cstate, OR_TRAN_IPV6, off, BPF_H, v1);
-       b2 = gen_cmp_le(cstate, OR_TRAN_IPV6, off, BPF_H, v2);
+       b1 = gen_cmp_ge(cstate, OR_TRAN_IPV6, off, BPF_H, min(v1, v2));
+       b2 = gen_cmp_le(cstate, OR_TRAN_IPV6, off, BPF_H, max(v1, v2));
 
        gen_and(b1, b2);
 
@@ -6158,14 +5886,10 @@ gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
 }
 
 static struct block *
-gen_portrangeop6(compiler_state_t *cstate, u_int port1, u_int port2,
-    bpf_u_int32 proto, int dir)
+gen_portrange6(compiler_state_t *cstate, uint16_t port1, uint16_t port2,
+    int proto, int dir)
 {
-       struct block *b0, *b1, *tmp;
-
-       /* ip6 proto 'proto' */
-       /* XXX - catch the first fragment of a fragmented packet? */
-       b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
@@ -6192,41 +5916,8 @@ gen_portrangeop6(compiler_state_t *cstate, u_int port1, u_int port2,
        default:
                abort();
        }
-       gen_and(b0, b1);
-
-       return b1;
-}
-
-static struct block *
-gen_portrange6(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
-    int dir)
-{
-       struct block *b0, *b1, *tmp;
-
-       /* link proto ip6 */
-       b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
-
-       switch (ip_proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_SCTP:
-               b1 = gen_portrangeop6(cstate, port1, port2, (bpf_u_int32)ip_proto,
-                   dir);
-               break;
-
-       case PROTO_UNDEF:
-               tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_TCP, dir);
-               b1 = gen_portrangeop6(cstate, port1, port2, IPPROTO_UDP, dir);
-               gen_or(tmp, b1);
-               tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_SCTP, dir);
-               gen_or(tmp, b1);
-               break;
 
-       default:
-               abort();
-       }
-       gen_and(b0, b1);
-       return b1;
+       return gen_port6_common(cstate, proto, b1);
 }
 
 static int
@@ -6273,6 +5964,10 @@ lookup_proto(compiler_state_t *cstate, const char *name, int proto)
 }
 
 #if !defined(NO_PROTOCHAIN)
+/*
+ * This primitive is non-directional by design, so the grammar does not allow
+ * to qualify it with a direction.
+ */
 static struct block *
 gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
 {
@@ -6289,6 +5984,7 @@ gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
        switch (proto) {
        case Q_IP:
        case Q_IPV6:
+               assert_maxval(cstate, "protocol number", v, UINT8_MAX);
                break;
        case Q_DEFAULT:
                b0 = gen_protochain(cstate, v, Q_IP);
@@ -6296,7 +5992,7 @@ gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
                gen_or(b0, b);
                return b;
        default:
-               bpf_error(cstate, "bad protocol applied for 'protochain'");
+               bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "protochain");
                /*NOTREACHED*/
        }
 
@@ -6495,12 +6191,10 @@ gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
         * A = P[X];
         * X = X + (P[X + 1] + 2) * 4;
         */
-       /* A = X */
-       s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA);
-       i++;
        /* A = P[X + packet head]; */
        s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
        s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+       s[i - 1]->s.jt = s[i];
        i++;
        /* MEM[reg2] = A */
        s[i] = new_stmt(cstate, BPF_ST);
@@ -6560,10 +6254,9 @@ gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
 
        /*
         * emit final check
+        * Remember, s[0] is dummy.
         */
-       b = new_block(cstate, JMP(BPF_JEQ));
-       b->stmts = s[1];        /*remember, s[0] is dummy*/
-       b->s.k = v;
+       b = gen_jmp(cstate, BPF_JEQ, v, s[1]);
 
        free_reg(cstate, reg2);
 
@@ -6572,32 +6265,6 @@ gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
 }
 #endif /* !defined(NO_PROTOCHAIN) */
 
-static struct block *
-gen_check_802_11_data_frame(compiler_state_t *cstate)
-{
-       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(cstate, OR_LINKHDR, 0, BPF_B);
-       b0 = new_block(cstate, JMP(BPF_JSET));
-       b0->s.k = 0x08;
-       b0->stmts = s;
-
-       s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-       b1 = new_block(cstate, 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
@@ -6606,20 +6273,20 @@ gen_check_802_11_data_frame(compiler_state_t *cstate)
  *
  * If <proto> is Q_DEFAULT, i.e. just "proto" was specified, it checks
  * against Q_IP and Q_IPV6.
+ *
+ * This primitive is non-directional by design, so the grammar does not allow
+ * to qualify it with a direction.
  */
 static struct block *
-gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
+gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto)
 {
        struct block *b0, *b1;
        struct block *b2;
 
-       if (dir != Q_DEFAULT)
-               bpf_error(cstate, "direction applied to 'proto'");
-
        switch (proto) {
        case Q_DEFAULT:
-               b0 = gen_proto(cstate, v, Q_IP, dir);
-               b1 = gen_proto(cstate, v, Q_IPV6, dir);
+               b0 = gen_proto(cstate, v, Q_IP);
+               b1 = gen_proto(cstate, v, Q_IPV6);
                gen_or(b0, b1);
                return b1;
 
@@ -6627,6 +6294,7 @@ gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
                return gen_linktype(cstate, v);
 
        case Q_IP:
+               assert_maxval(cstate, "protocol number", v, UINT8_MAX);
                /*
                 * For FDDI, RFC 1188 says that SNAP encapsulation is used,
                 * not LLC encapsulation with LLCSAP_IP.
@@ -6643,105 +6311,53 @@ gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
                 * So we always check for ETHERTYPE_IP.
                 */
                b0 = gen_linktype(cstate, ETHERTYPE_IP);
-               b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v);
+               // 0 <= v <= UINT8_MAX
+               b1 = gen_ip_proto(cstate, (uint8_t)v);
                gen_and(b0, b1);
                return b1;
 
        case Q_ARP:
-               bpf_error(cstate, "arp does not encapsulate another protocol");
-               /*NOTREACHED*/
-
        case Q_RARP:
-               bpf_error(cstate, "rarp does not encapsulate another protocol");
-               /*NOTREACHED*/
-
        case Q_SCTP:
-               bpf_error(cstate, "'sctp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_TCP:
-               bpf_error(cstate, "'tcp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_UDP:
-               bpf_error(cstate, "'udp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ICMP:
-               bpf_error(cstate, "'icmp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_IGMP:
-               bpf_error(cstate, "'igmp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_IGRP:
-               bpf_error(cstate, "'igrp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ATALK:
-               bpf_error(cstate, "AppleTalk encapsulation is not specifiable");
-               /*NOTREACHED*/
-
        case Q_DECNET:
-               bpf_error(cstate, "DECNET encapsulation is not specifiable");
-               /*NOTREACHED*/
-
        case Q_LAT:
-               bpf_error(cstate, "LAT does not encapsulate another protocol");
-               /*NOTREACHED*/
-
        case Q_SCA:
-               bpf_error(cstate, "SCA does not encapsulate another protocol");
-               /*NOTREACHED*/
-
        case Q_MOPRC:
-               bpf_error(cstate, "MOPRC does not encapsulate another protocol");
-               /*NOTREACHED*/
-
        case Q_MOPDL:
-               bpf_error(cstate, "MOPDL does not encapsulate another protocol");
-               /*NOTREACHED*/
+               break; // invalid qualifier
 
        case Q_IPV6:
+               assert_maxval(cstate, "protocol number", v, UINT8_MAX);
                b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
                /*
                 * Also check for a fragment header before the final
                 * header.
                 */
-               b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT);
+               b2 = gen_ip6_proto(cstate, IPPROTO_FRAGMENT);
                b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v);
                gen_and(b2, b1);
-               b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v);
+               // 0 <= v <= UINT8_MAX
+               b2 = gen_ip6_proto(cstate, (uint8_t)v);
                gen_or(b2, b1);
                gen_and(b0, b1);
                return b1;
 
        case Q_ICMPV6:
-               bpf_error(cstate, "'icmp6 proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_AH:
-               bpf_error(cstate, "'ah proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ESP:
-               bpf_error(cstate, "'esp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_PIM:
-               bpf_error(cstate, "'pim proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_VRRP:
-               bpf_error(cstate, "'vrrp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_AARP:
-               bpf_error(cstate, "'aarp proto' is bogus");
-               /*NOTREACHED*/
+               break; // invalid qualifier
 
        case Q_ISO:
+               assert_maxval(cstate, "ISO protocol", v, UINT8_MAX);
                switch (cstate->linktype) {
 
                case DLT_FRELAY:
@@ -6786,75 +6402,50 @@ gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
                }
 
        case Q_ESIS:
-               bpf_error(cstate, "'esis proto' is bogus");
-               /*NOTREACHED*/
+               break; // invalid qualifier
 
        case Q_ISIS:
-               b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT);
+               assert_maxval(cstate, "IS-IS PDU type", v, ISIS_PDU_TYPE_MAX);
+               b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO);
                /*
                 * 4 is the offset of the PDU type relative to the IS-IS
                 * header.
+                * Except when it is not, see above.
                 */
-               b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, v);
+               unsigned pdu_type_offset;
+               switch (cstate->linktype) {
+               case DLT_C_HDLC:
+               case DLT_HDLC:
+                       pdu_type_offset = 5;
+                       break;
+               default:
+                       pdu_type_offset = 4;
+               }
+               b1 = gen_mcmp(cstate, OR_LINKPL_NOSNAP, pdu_type_offset, BPF_B,
+                   v, ISIS_PDU_TYPE_MAX);
                gen_and(b0, b1);
                return b1;
 
        case Q_CLNP:
-               bpf_error(cstate, "'clnp proto' is not supported");
-               /*NOTREACHED*/
-
        case Q_STP:
-               bpf_error(cstate, "'stp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_IPX:
-               bpf_error(cstate, "'ipx proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_NETBEUI:
-               bpf_error(cstate, "'netbeui proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ISIS_L1:
-               bpf_error(cstate, "'l1 proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ISIS_L2:
-               bpf_error(cstate, "'l2 proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ISIS_IIH:
-               bpf_error(cstate, "'iih proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ISIS_SNP:
-               bpf_error(cstate, "'snp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ISIS_CSNP:
-               bpf_error(cstate, "'csnp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ISIS_PSNP:
-               bpf_error(cstate, "'psnp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_ISIS_LSP:
-               bpf_error(cstate, "'lsp proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_RADIO:
-               bpf_error(cstate, "'radio proto' is bogus");
-               /*NOTREACHED*/
-
        case Q_CARP:
-               bpf_error(cstate, "'carp proto' is bogus");
-               /*NOTREACHED*/
+               break; // invalid qualifier
 
        default:
                abort();
                /*NOTREACHED*/
        }
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "proto");
        /*NOTREACHED*/
 }
 
@@ -7132,7 +6723,8 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
        int proto = q.proto;
        int dir = q.dir;
        int tproto;
-       u_char *eaddr;
+       u_char *eaddrp;
+       u_char eaddr[6];
        bpf_u_int32 mask, addr;
        struct addrinfo *res, *res0;
        struct sockaddr_in *sin4;
@@ -7169,64 +6761,15 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
        case Q_DEFAULT:
        case Q_HOST:
                if (proto == Q_LINK) {
-                       switch (cstate->linktype) {
-
-                       case DLT_EN10MB:
-                       case DLT_NETANALYZER:
-                       case DLT_NETANALYZER_TRANSPARENT:
-                               eaddr = pcap_ether_hostton(name);
-                               if (eaddr == NULL)
-                                       bpf_error(cstate,
-                                           "unknown ether host '%s'", name);
-                               tmp = gen_prevlinkhdr_check(cstate);
-                               b = gen_ehostop(cstate, eaddr, dir);
-                               if (tmp != NULL)
-                                       gen_and(tmp, b);
-                               free(eaddr);
-                               return b;
-
-                       case DLT_FDDI:
-                               eaddr = pcap_ether_hostton(name);
-                               if (eaddr == NULL)
-                                       bpf_error(cstate,
-                                           "unknown FDDI host '%s'", name);
-                               b = gen_fhostop(cstate, eaddr, dir);
-                               free(eaddr);
-                               return b;
-
-                       case DLT_IEEE802:
-                               eaddr = pcap_ether_hostton(name);
-                               if (eaddr == NULL)
-                                       bpf_error(cstate,
-                                           "unknown token ring host '%s'", name);
-                               b = gen_thostop(cstate, eaddr, dir);
-                               free(eaddr);
-                               return b;
-
-                       case DLT_IEEE802_11:
-                       case DLT_PRISM_HEADER:
-                       case DLT_IEEE802_11_RADIO_AVS:
-                       case DLT_IEEE802_11_RADIO:
-                       case DLT_PPI:
-                               eaddr = pcap_ether_hostton(name);
-                               if (eaddr == NULL)
-                                       bpf_error(cstate,
-                                           "unknown 802.11 host '%s'", name);
-                               b = gen_wlanhostop(cstate, eaddr, dir);
-                               free(eaddr);
-                               return b;
-
-                       case DLT_IP_OVER_FC:
-                               eaddr = pcap_ether_hostton(name);
-                               if (eaddr == NULL)
-                                       bpf_error(cstate,
-                                           "unknown Fibre Channel host '%s'", name);
-                               b = gen_ipfchostop(cstate, eaddr, dir);
-                               free(eaddr);
-                               return b;
-                       }
-
-                       bpf_error(cstate, "only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name");
+                       const char *context = "link host NAME";
+                       if (! is_mac48_linktype(cstate->linktype))
+                               fail_kw_on_dlt(cstate, context);
+                       eaddrp = pcap_ether_hostton(name);
+                       if (eaddrp == NULL)
+                               bpf_error(cstate, ERRSTR_UNKNOWN_MAC48HOST, name);
+                       memcpy(eaddr, eaddrp, sizeof(eaddr));
+                       free(eaddrp);
+                       return gen_mac48host(cstate, eaddr, q.dir, context);
                } else if (proto == Q_DECNET) {
                        /*
                         * A long time ago on Ultrix libpcap supported
@@ -7297,9 +6840,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                }
 
        case Q_PORT:
-               if (proto != Q_DEFAULT &&
-                   proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP)
-                       bpf_error(cstate, "illegal qualifier of 'port'");
+               (void)port_pq_to_ipproto(cstate, proto, "port"); // validate only
                if (pcap_nametoport(name, &port, &real_proto) == 0)
                        bpf_error(cstate, "unknown port '%s'", name);
                if (proto == Q_UDP) {
@@ -7335,14 +6876,13 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                        bpf_error(cstate, "illegal port number %d < 0", port);
                if (port > 65535)
                        bpf_error(cstate, "illegal port number %d > 65535", port);
-               b = gen_port(cstate, port, real_proto, dir);
-               gen_or(gen_port6(cstate, port, real_proto, dir), b);
+               // real_proto can be PROTO_UNDEF
+               b = gen_port(cstate, (uint16_t)port, real_proto, dir);
+               gen_or(gen_port6(cstate, (uint16_t)port, real_proto, dir), b);
                return b;
 
        case Q_PORTRANGE:
-               if (proto != Q_DEFAULT &&
-                   proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP)
-                       bpf_error(cstate, "illegal qualifier of 'portrange'");
+               (void)port_pq_to_ipproto(cstate, proto, "portrange"); // validate only
                stringtoportrange(cstate, name, &port1, &port2, &real_proto);
                if (proto == Q_UDP) {
                        if (real_proto == IPPROTO_TCP)
@@ -7376,24 +6916,30 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                if (port2 > 65535)
                        bpf_error(cstate, "illegal port number %d > 65535", port2);
 
-               b = gen_portrange(cstate, port1, port2, real_proto, dir);
-               gen_or(gen_portrange6(cstate, port1, port2, real_proto, dir), b);
+               // real_proto can be PROTO_UNDEF
+               b = gen_portrange(cstate, (uint16_t)port1, (uint16_t)port2,
+                   real_proto, dir);
+               gen_or(gen_portrange6(cstate, (uint16_t)port1, (uint16_t)port2,
+                   real_proto, dir), b);
                return b;
 
        case Q_GATEWAY:
 #ifndef INET6
-               eaddr = pcap_ether_hostton(name);
-               if (eaddr == NULL)
-                       bpf_error(cstate, "unknown ether host: %s", name);
+               if (! is_mac48_linktype(cstate->linktype))
+                       fail_kw_on_dlt(cstate, "gateway");
+               eaddrp = pcap_ether_hostton(name);
+               if (eaddrp == NULL)
+                       bpf_error(cstate, ERRSTR_UNKNOWN_MAC48HOST, name);
+               memcpy(eaddr, eaddrp, sizeof(eaddr));
+               free(eaddrp);
 
                res = pcap_nametoaddrinfo(name);
                cstate->ai = res;
                if (res == NULL)
                        bpf_error(cstate, "unknown host '%s'", name);
-               b = gen_gateway(cstate, eaddr, res, proto, dir);
+               b = gen_gateway(cstate, eaddr, res, proto);
                cstate->ai = NULL;
                freeaddrinfo(res);
-               free(eaddr);
                if (b == NULL)
                        bpf_error(cstate, "unknown host '%s'", name);
                return b;
@@ -7404,7 +6950,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
        case Q_PROTO:
                real_proto = lookup_proto(cstate, name, proto);
                if (real_proto >= 0)
-                       return gen_proto(cstate, real_proto, proto, dir);
+                       return gen_proto(cstate, real_proto, proto);
                else
                        bpf_error(cstate, "unknown protocol: %s", name);
 
@@ -7472,6 +7018,7 @@ gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
                return gen_host(cstate, n, m, q.proto, q.dir, q.addr);
 
        default:
+               // Q_HOST and Q_GATEWAY only (see the grammar)
                bpf_error(cstate, "Mask syntax for networks only");
                /*NOTREACHED*/
        }
@@ -7537,6 +7084,7 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
                if (proto == Q_DECNET)
                        return gen_host(cstate, v, 0, proto, dir, q.addr);
                else if (proto == Q_LINK) {
+                       // "link (host|net) IPV4ADDR" and variations thereof
                        bpf_error(cstate, "illegal link layer address");
                } else {
                        mask = 0xffffffff;
@@ -7555,46 +7103,32 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
                }
 
        case Q_PORT:
-               if (proto == Q_UDP)
-                       proto = IPPROTO_UDP;
-               else if (proto == Q_TCP)
-                       proto = IPPROTO_TCP;
-               else if (proto == Q_SCTP)
-                       proto = IPPROTO_SCTP;
-               else if (proto == Q_DEFAULT)
-                       proto = PROTO_UNDEF;
-               else
-                       bpf_error(cstate, "illegal qualifier of 'port'");
+               proto = port_pq_to_ipproto(cstate, proto, "port");
 
                if (v > 65535)
                        bpf_error(cstate, "illegal port number %u > 65535", v);
 
+               // proto can be PROTO_UNDEF
            {
                struct block *b;
-               b = gen_port(cstate, v, proto, dir);
-               gen_or(gen_port6(cstate, v, proto, dir), b);
+               b = gen_port(cstate, (uint16_t)v, proto, dir);
+               gen_or(gen_port6(cstate, (uint16_t)v, proto, dir), b);
                return b;
            }
 
        case Q_PORTRANGE:
-               if (proto == Q_UDP)
-                       proto = IPPROTO_UDP;
-               else if (proto == Q_TCP)
-                       proto = IPPROTO_TCP;
-               else if (proto == Q_SCTP)
-                       proto = IPPROTO_SCTP;
-               else if (proto == Q_DEFAULT)
-                       proto = PROTO_UNDEF;
-               else
-                       bpf_error(cstate, "illegal qualifier of 'portrange'");
+               proto = port_pq_to_ipproto(cstate, proto, "portrange");
 
                if (v > 65535)
                        bpf_error(cstate, "illegal port number %u > 65535", v);
 
+               // proto can be PROTO_UNDEF
            {
                struct block *b;
-               b = gen_portrange(cstate, v, v, proto, dir);
-               gen_or(gen_portrange6(cstate, v, v, proto, dir), b);
+               b = gen_portrange(cstate, (uint16_t)v, (uint16_t)v,
+                   proto, dir);
+               gen_or(gen_portrange6(cstate, (uint16_t)v, (uint16_t)v,
+                   proto, dir), b);
                return b;
            }
 
@@ -7603,7 +7137,7 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
                /*NOTREACHED*/
 
        case Q_PROTO:
-               return gen_proto(cstate, v, proto, dir);
+               return gen_proto(cstate, v, proto);
 
 #if !defined(NO_PROTOCHAIN)
        case Q_PROTOCHAIN:
@@ -7678,6 +7212,7 @@ gen_mcode6(compiler_state_t *cstate, const char *s, bpf_u_int32 masklen,
                return b;
 
        default:
+               // Q_GATEWAY only (see the grammar)
                bpf_error(cstate, "invalid qualifier against IPv6 address");
                /*NOTREACHED*/
        }
@@ -7687,8 +7222,6 @@ gen_mcode6(compiler_state_t *cstate, const char *s, bpf_u_int32 masklen,
 struct block *
 gen_ecode(compiler_state_t *cstate, const char *s, struct qual q)
 {
-       struct block *b, *tmp;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -7697,40 +7230,13 @@ gen_ecode(compiler_state_t *cstate, const char *s, struct qual q)
                return (NULL);
 
        if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
+               const char *context = "link host XX:XX:XX:XX:XX:XX";
+               if (! is_mac48_linktype(cstate->linktype))
+                       fail_kw_on_dlt(cstate, context);
                cstate->e = pcap_ether_aton(s);
                if (cstate->e == NULL)
                        bpf_error(cstate, "malloc");
-               switch (cstate->linktype) {
-               case DLT_EN10MB:
-               case DLT_NETANALYZER:
-               case DLT_NETANALYZER_TRANSPARENT:
-                       tmp = gen_prevlinkhdr_check(cstate);
-                       b = gen_ehostop(cstate, cstate->e, (int)q.dir);
-                       if (tmp != NULL)
-                               gen_and(tmp, b);
-                       break;
-               case DLT_FDDI:
-                       b = gen_fhostop(cstate, cstate->e, (int)q.dir);
-                       break;
-               case DLT_IEEE802:
-                       b = gen_thostop(cstate, cstate->e, (int)q.dir);
-                       break;
-               case DLT_IEEE802_11:
-               case DLT_PRISM_HEADER:
-               case DLT_IEEE802_11_RADIO_AVS:
-               case DLT_IEEE802_11_RADIO:
-               case DLT_PPI:
-                       b = gen_wlanhostop(cstate, cstate->e, (int)q.dir);
-                       break;
-               case DLT_IP_OVER_FC:
-                       b = gen_ipfchostop(cstate, cstate->e, (int)q.dir);
-                       break;
-               default:
-                       free(cstate->e);
-                       cstate->e = NULL;
-                       bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
-                       /*NOTREACHED*/
-               }
+               struct block *b = gen_mac48host(cstate, cstate->e, q.dir, context);
                free(cstate->e);
                cstate->e = NULL;
                return (b);
@@ -7808,7 +7314,7 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst,
        }
        switch (proto) {
        default:
-               bpf_error(cstate, "unsupported index operation");
+               bpf_error(cstate, "'%s' does not support the index operation", pqkw(proto));
 
        case Q_RADIO:
                /*
@@ -8005,7 +7511,7 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst,
                /*
                 * Check if we have an icmp6 next header
                 */
-               b = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, 58);
+               b = gen_ip6_proto(cstate, 58);
                if (inst->b)
                        gen_and(inst->b, b);
                inst->b = b;
@@ -8310,14 +7816,9 @@ static struct block *
 gen_len(compiler_state_t *cstate, int jmp, int n)
 {
        struct slist *s;
-       struct block *b;
 
        s = new_stmt(cstate, BPF_LD|BPF_LEN);
-       b = new_block(cstate, JMP(jmp));
-       b->stmts = s;
-       b->s.k = n;
-
-       return b;
+       return gen_jmp(cstate, jmp, n, s);
 }
 
 struct block *
@@ -8377,6 +7878,8 @@ gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
+       assert_maxval(cstate, "byte argument", val, UINT8_MAX);
+
        switch (op) {
        default:
                abort();
@@ -8385,12 +7888,10 @@ gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
                return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
 
        case '<':
-               b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
-               return b;
+               return gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
 
        case '>':
-               b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
-               return b;
+               return gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
 
        case '|':
                s = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_K);
@@ -8401,8 +7902,10 @@ gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
                break;
        }
        s->s.k = val;
-       b = new_block(cstate, JMP(BPF_JEQ));
-       b->stmts = s;
+       // Load the required byte first.
+       struct slist *s0 = gen_load_a(cstate, OR_LINKHDR, idx, BPF_B);
+       sappend(s0, s);
+       b = gen_jmp(cstate, BPF_JEQ, 0, s0);
        gen_not(b);
 
        return b;
@@ -8431,29 +7934,8 @@ gen_broadcast(compiler_state_t *cstate, int proto)
                case DLT_ARCNET_LINUX:
                        // ARCnet broadcast is [8-bit] destination address 0.
                        return gen_ahostop(cstate, 0, Q_DST);
-               case DLT_EN10MB:
-               case DLT_NETANALYZER:
-               case DLT_NETANALYZER_TRANSPARENT:
-                       b1 = gen_prevlinkhdr_check(cstate);
-                       b0 = gen_ehostop(cstate, ebroadcast, Q_DST);
-                       if (b1 != NULL)
-                               gen_and(b1, b0);
-                       return b0;
-               case DLT_FDDI:
-                       return gen_fhostop(cstate, ebroadcast, Q_DST);
-               case DLT_IEEE802:
-                       return gen_thostop(cstate, ebroadcast, Q_DST);
-               case DLT_IEEE802_11:
-               case DLT_PRISM_HEADER:
-               case DLT_IEEE802_11_RADIO_AVS:
-               case DLT_IEEE802_11_RADIO:
-               case DLT_PPI:
-                       return gen_wlanhostop(cstate, ebroadcast, Q_DST);
-               case DLT_IP_OVER_FC:
-                       return gen_ipfchostop(cstate, ebroadcast, Q_DST);
-               default:
-                       bpf_error(cstate, "not a broadcast link");
                }
+               return gen_mac48host(cstate, ebroadcast, Q_DST, "broadcast");
                /*NOTREACHED*/
 
        case Q_IP:
@@ -8472,7 +7954,7 @@ gen_broadcast(compiler_state_t *cstate, int proto)
                gen_and(b0, b2);
                return b2;
        }
-       bpf_error(cstate, "only link-layer/IP broadcast filters supported");
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "broadcast");
        /*NOTREACHED*/
 }
 
@@ -8483,15 +7965,11 @@ gen_broadcast(compiler_state_t *cstate, int proto)
 static struct block *
 gen_mac_multicast(compiler_state_t *cstate, int offset)
 {
-       register struct block *b0;
        register struct slist *s;
 
        /* link[offset] & 1 != 0 */
        s = gen_load_a(cstate, OR_LINKHDR, offset, BPF_B);
-       b0 = new_block(cstate, JMP(BPF_JSET));
-       b0->s.k = 1;
-       b0->stmts = s;
-       return b0;
+       return gen_set(cstate, 1, s);
 }
 
 struct block *
@@ -8563,9 +8041,7 @@ gen_multicast(compiler_state_t *cstate, int proto)
                         * First, check for To DS set, i.e. "link[1] & 0x01".
                         */
                        s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-                       b1 = new_block(cstate, JMP(BPF_JSET));
-                       b1->s.k = 0x01; /* To DS */
-                       b1->stmts = s;
+                       b1 = gen_set(cstate, IEEE80211_FC1_DIR_TODS, s);
 
                        /*
                         * If To DS is set, the DA is at 16.
@@ -8578,10 +8054,7 @@ gen_multicast(compiler_state_t *cstate, int proto)
                         * "!(link[1] & 0x01)".
                         */
                        s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
-                       b2 = new_block(cstate, JMP(BPF_JSET));
-                       b2->s.k = 0x01; /* To DS */
-                       b2->stmts = s;
-                       gen_not(b2);
+                       b2 = gen_unset(cstate, IEEE80211_FC1_DIR_TODS, s);
 
                        /*
                         * If To DS is not set, the DA is at 4.
@@ -8600,9 +8073,7 @@ gen_multicast(compiler_state_t *cstate, int proto)
                         * I.e, check "link[0] & 0x08".
                         */
                        s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-                       b1 = new_block(cstate, JMP(BPF_JSET));
-                       b1->s.k = 0x08;
-                       b1->stmts = s;
+                       b1 = gen_set(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                        /*
                         * AND that with the checks done for data frames.
@@ -8615,10 +8086,7 @@ gen_multicast(compiler_state_t *cstate, int proto)
                         * I.e, check "!(link[0] & 0x08)".
                         */
                        s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-                       b2 = new_block(cstate, JMP(BPF_JSET));
-                       b2->s.k = 0x08;
-                       b2->stmts = s;
-                       gen_not(b2);
+                       b2 = gen_unset(cstate, IEEE80211_FC0_TYPE_DATA, s);
 
                        /*
                         * For management frames, the DA is at 4.
@@ -8642,10 +8110,7 @@ gen_multicast(compiler_state_t *cstate, int proto)
                         * I.e., check "!(link[0] & 0x04)".
                         */
                        s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
-                       b1 = new_block(cstate, JMP(BPF_JSET));
-                       b1->s.k = 0x04;
-                       b1->stmts = s;
-                       gen_not(b1);
+                       b1 = gen_unset(cstate, IEEE80211_FC0_TYPE_CTL, s);
 
                        /*
                         * AND that with the checks for data and management
@@ -8654,13 +8119,12 @@ gen_multicast(compiler_state_t *cstate, int proto)
                        gen_and(b1, b0);
                        return b0;
                case DLT_IP_OVER_FC:
-                       b0 = gen_mac_multicast(cstate, 2);
-                       return b0;
+                       return gen_mac_multicast(cstate, 2);
                default:
                        break;
                }
-               /* Link not known to support multicasts */
-               break;
+               fail_kw_on_dlt(cstate, "multicast");
+               /*NOTREACHED*/
 
        case Q_IP:
                b0 = gen_linktype(cstate, ETHERTYPE_IP);
@@ -8674,7 +8138,7 @@ gen_multicast(compiler_state_t *cstate, int proto)
                gen_and(b0, b1);
                return b1;
        }
-       bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel");
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "multicast");
        /*NOTREACHED*/
 }
 
@@ -8700,8 +8164,6 @@ require_basic_bpf_extensions(compiler_state_t *cstate, const char *keyword)
 struct block *
 gen_ifindex(compiler_state_t *cstate, int ifindex)
 {
-       register struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -8715,21 +8177,18 @@ gen_ifindex(compiler_state_t *cstate, int ifindex)
        switch (cstate->linktype) {
        case DLT_LINUX_SLL2:
                /* match packets on this interface */
-               b0 = gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex);
-               break;
+               return gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex);
        default:
 #if defined(__linux__)
                require_basic_bpf_extensions(cstate, "ifindex");
                /* match ifindex */
-               b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W,
+               return gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W,
                             ifindex);
 #else /* defined(__linux__) */
-               bpf_error(cstate, "ifindex not supported on %s",
-                   pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+               fail_kw_on_dlt(cstate, "ifindex");
                /*NOTREACHED*/
 #endif /* defined(__linux__) */
        }
-       return (b0);
 }
 
 /*
@@ -8758,16 +8217,12 @@ gen_inbound_outbound(compiler_state_t *cstate, const int outbound)
         */
        switch (cstate->linktype) {
        case DLT_SLIP:
-               b0 = gen_relation_internal(cstate, BPF_JEQ,
-                         gen_load_internal(cstate, Q_LINK, gen_loadi_internal(cstate, 0), 1),
-                         gen_loadi_internal(cstate, 0),
+               return gen_cmp(cstate, OR_LINKHDR, 0, BPF_B,
                          outbound ? SLIPDIR_OUT : SLIPDIR_IN);
-               break;
 
        case DLT_IPNET:
-               b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H,
+               return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H,
                    outbound ? IPNET_OUTBOUND : IPNET_INBOUND);
-               break;
 
        case DLT_LINUX_SLL:
                /* match outgoing packets */
@@ -8776,7 +8231,7 @@ gen_inbound_outbound(compiler_state_t *cstate, const int outbound)
                        /* to filter on inbound traffic, invert the match */
                        gen_not(b0);
                }
-               break;
+               return b0;
 
        case DLT_LINUX_SLL2:
                /* match outgoing packets */
@@ -8785,16 +8240,14 @@ gen_inbound_outbound(compiler_state_t *cstate, const int outbound)
                        /* to filter on inbound traffic, invert the match */
                        gen_not(b0);
                }
-               break;
+               return b0;
 
        case DLT_PFLOG:
-               b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
+               return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
                    outbound ? PF_OUT : PF_IN);
-               break;
 
        case DLT_PPP_PPPD:
-               b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, outbound ? PPP_PPPD_OUT : PPP_PPPD_IN);
-               break;
+               return gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, outbound ? PPP_PPPD_OUT : PPP_PPPD_IN);
 
        case DLT_JUNIPER_MFR:
        case DLT_JUNIPER_MLFR:
@@ -8820,8 +8273,7 @@ gen_inbound_outbound(compiler_state_t *cstate, const int outbound)
        case DLT_JUNIPER_ATM_CEMIC:
                /* juniper flags (including direction) are stored
                 * the byte after the 3-byte magic number */
-               b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, outbound ? 0 : 1, 0x01);
-               break;
+               return gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, outbound ? 0 : 1, 0x01);
 
        default:
                /*
@@ -8848,20 +8300,18 @@ gen_inbound_outbound(compiler_state_t *cstate, const int outbound)
                        /* to filter on inbound traffic, invert the match */
                        gen_not(b0);
                }
+               return b0;
 #else /* defined(__linux__) */
-               bpf_error(cstate, "inbound/outbound not supported on %s",
-                   pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+               fail_kw_on_dlt(cstate, outbound ? "outbound" : "inbound");
                /*NOTREACHED*/
 #endif /* defined(__linux__) */
        }
-       return (b0);
 }
 
 /* PF firewall log matched interface */
 struct block *
 gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
 {
-       struct block *b0;
        u_int len, off;
 
        /*
@@ -8871,10 +8321,8 @@ gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "ifname supported only on PF linktype");
-               /*NOTREACHED*/
-       }
+       assert_pflog(cstate, "ifname");
+
        len = sizeof(((struct pfloghdr *)0)->ifname);
        off = offsetof(struct pfloghdr, ifname);
        if (strlen(ifname) >= len) {
@@ -8882,17 +8330,14 @@ gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
                    len-1);
                /*NOTREACHED*/
        }
-       b0 = gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname),
+       return gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname),
            (const u_char *)ifname);
-       return (b0);
 }
 
 /* PF firewall log ruleset name */
 struct block *
 gen_pf_ruleset(compiler_state_t *cstate, char *ruleset)
 {
-       struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -8900,10 +8345,7 @@ gen_pf_ruleset(compiler_state_t *cstate, char *ruleset)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "ruleset supported only on PF linktype");
-               /*NOTREACHED*/
-       }
+       assert_pflog(cstate, "ruleset");
 
        if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) {
                bpf_error(cstate, "ruleset names can only be %ld characters",
@@ -8911,17 +8353,14 @@ gen_pf_ruleset(compiler_state_t *cstate, char *ruleset)
                /*NOTREACHED*/
        }
 
-       b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset),
+       return gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset),
            (u_int)strlen(ruleset), (const u_char *)ruleset);
-       return (b0);
 }
 
 /* PF firewall log rule number */
 struct block *
 gen_pf_rnr(compiler_state_t *cstate, int rnr)
 {
-       struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -8929,22 +8368,16 @@ gen_pf_rnr(compiler_state_t *cstate, int rnr)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "rnr supported only on PF linktype");
-               /*NOTREACHED*/
-       }
+       assert_pflog(cstate, "rnr");
 
-       b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
                 (bpf_u_int32)rnr);
-       return (b0);
 }
 
 /* PF firewall log sub-rule number */
 struct block *
 gen_pf_srnr(compiler_state_t *cstate, int srnr)
 {
-       struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -8952,22 +8385,16 @@ gen_pf_srnr(compiler_state_t *cstate, int srnr)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "srnr supported only on PF linktype");
-               /*NOTREACHED*/
-       }
+       assert_pflog(cstate, "srnr");
 
-       b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
            (bpf_u_int32)srnr);
-       return (b0);
 }
 
 /* PF firewall log reason code */
 struct block *
 gen_pf_reason(compiler_state_t *cstate, int reason)
 {
-       struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -8975,22 +8402,16 @@ gen_pf_reason(compiler_state_t *cstate, int reason)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "reason supported only on PF linktype");
-               /*NOTREACHED*/
-       }
+       assert_pflog(cstate, "reason");
 
-       b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
            (bpf_u_int32)reason);
-       return (b0);
 }
 
 /* PF firewall log action */
 struct block *
 gen_pf_action(compiler_state_t *cstate, int action)
 {
-       struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -8998,22 +8419,16 @@ gen_pf_action(compiler_state_t *cstate, int action)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "action supported only on PF linktype");
-               /*NOTREACHED*/
-       }
+       assert_pflog(cstate, "action");
 
-       b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
            (bpf_u_int32)action);
-       return (b0);
 }
 
 /* IEEE 802.11 wireless header */
 struct block *
 gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask)
 {
-       struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -9027,22 +8442,18 @@ gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask)
        case DLT_PRISM_HEADER:
        case DLT_IEEE802_11_RADIO_AVS:
        case DLT_IEEE802_11_RADIO:
-               b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask);
-               break;
+       case DLT_PPI:
+               return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask);
 
        default:
-               bpf_error(cstate, "802.11 link-layer types supported only on 802.11");
+               fail_kw_on_dlt(cstate, "type/subtype");
                /*NOTREACHED*/
        }
-
-       return (b0);
 }
 
 struct block *
 gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir)
 {
-       struct block *b0;
-
        /*
         * Catch errors reported by us and routines below us, and return NULL
         * on an error.
@@ -9056,17 +8467,14 @@ gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir)
        case DLT_PRISM_HEADER:
        case DLT_IEEE802_11_RADIO_AVS:
        case DLT_IEEE802_11_RADIO:
-               break;
+       case DLT_PPI:
+               return gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir,
+                   IEEE80211_FC1_DIR_MASK);
 
        default:
-               bpf_error(cstate, "frame direction supported only with 802.11 headers");
+               fail_kw_on_dlt(cstate, "dir");
                /*NOTREACHED*/
        }
-
-       b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir,
-           IEEE80211_FC1_DIR_MASK);
-
-       return (b0);
 }
 
 // Process an ARCnet host address string.
@@ -9140,27 +8548,12 @@ gen_ahostop(compiler_state_t *cstate, const uint8_t eaddr, int dir)
                return b1;
 
        case Q_ADDR1:
-               bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
-               /*NOTREACHED*/
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
-               /*NOTREACHED*/
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
-               /*NOTREACHED*/
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
-               /*NOTREACHED*/
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               /*NOTREACHED*/
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
                /*NOTREACHED*/
        }
        abort();
@@ -9186,10 +8579,7 @@ gen_vlan_tpid_test(compiler_state_t *cstate)
 static struct block *
 gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num)
 {
-       if (vlan_num > 0x0fff) {
-               bpf_error(cstate, "VLAN tag %u greater than maximum %u",
-                   vlan_num, 0x0fff);
-       }
+       assert_maxval(cstate, "VLAN tag", vlan_num, 0x0fff);
        return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff);
 }
 
@@ -9321,9 +8711,7 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
        s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
        s->s.k = (bpf_u_int32)(SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT);
 
-       b0 = new_block(cstate, JMP(BPF_JEQ));
-       b0->stmts = s;
-       b0->s.k = 1;
+       b0 = gen_jmp(cstate, BPF_JEQ, 1, s);
 
        /*
         * This is tricky. We need to insert the statements updating variable
@@ -9514,10 +8902,7 @@ gen_mpls_internal(compiler_state_t *cstate, bpf_u_int32 label_num,
 
        /* If a specific MPLS label is requested, check it */
        if (has_label_num) {
-               if (label_num > 0xFFFFF) {
-                       bpf_error(cstate, "MPLS label %u greater than maximum %u",
-                           label_num, 0xFFFFF);
-               }
+               assert_maxval(cstate, "MPLS label", label_num, 0xFFFFF);
                label_num = label_num << 12; /* label is shifted 12 bits on the wire */
                b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num,
                    0xfffff000); /* only compare the first 20 bits */
@@ -9607,10 +8992,7 @@ gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
 
        /* If a specific session is requested, check PPPoE session id */
        if (has_sess_num) {
-               if (sess_num > UINT16_MAX) {
-                       bpf_error(cstate, "PPPoE session number %u greater than maximum %u",
-                           sess_num, UINT16_MAX);
-               }
+               assert_maxval(cstate, "PPPoE session number", sess_num, UINT16_MAX);
                b1 = gen_cmp(cstate, OR_LINKPL, 2, BPF_H, sess_num);
                gen_and(b0, b1);
                b0 = b1;
@@ -9651,7 +9033,7 @@ gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
  * specified. Parameterized to handle both IPv4 and IPv6. */
 static struct block *
 gen_geneve_check(compiler_state_t *cstate,
-    struct block *(*gen_portfn)(compiler_state_t *, u_int, int, int),
+    struct block *(*gen_portfn)(compiler_state_t *, uint16_t, int, int),
     enum e_offrel offrel, bpf_u_int32 vni, int has_vni)
 {
        struct block *b0, *b1;
@@ -9666,10 +9048,7 @@ gen_geneve_check(compiler_state_t *cstate,
        b0 = b1;
 
        if (has_vni) {
-               if (vni > 0xffffff) {
-                       bpf_error(cstate, "Geneve VNI %u greater than maximum %u",
-                           vni, 0xffffff);
-               }
+               assert_maxval(cstate, "Geneve VNI", vni, 0xffffff);
                vni <<= 8; /* VNI is in the upper 3 bytes */
                b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00);
                gen_and(b0, b1);
@@ -9701,9 +9080,7 @@ gen_geneve4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
        /* Forcibly append these statements to the true condition
         * of the protocol check by creating a new block that is
         * always true and ANDing them. */
-       b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
-       b1->stmts = s;
-       b1->s.k = 0;
+       b1 = gen_jmp(cstate, BPF_JMP|BPF_JEQ|BPF_X, 0, s);
 
        gen_and(b0, b1);
 
@@ -9740,9 +9117,7 @@ gen_geneve6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
        s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
        sappend(s, s1);
 
-       b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
-       b1->stmts = s;
-       b1->s.k = 0;
+       b1 = gen_jmp(cstate, BPF_JMP|BPF_JEQ|BPF_X, 0, s);
 
        gen_and(b0, b1);
 
@@ -9927,7 +9302,7 @@ gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
  * specified. Parameterized to handle both IPv4 and IPv6. */
 static struct block *
 gen_vxlan_check(compiler_state_t *cstate,
-    struct block *(*gen_portfn)(compiler_state_t *, u_int, int, int),
+    struct block *(*gen_portfn)(compiler_state_t *, uint16_t, int, int),
     enum e_offrel offrel, bpf_u_int32 vni, int has_vni)
 {
        struct block *b0, *b1;
@@ -9941,10 +9316,7 @@ gen_vxlan_check(compiler_state_t *cstate,
        b0 = b1;
 
        if (has_vni) {
-               if (vni > 0xffffff) {
-                       bpf_error(cstate, "VXLAN VNI %u greater than maximum %u",
-                           vni, 0xffffff);
-               }
+               assert_maxval(cstate, "VXLAN VNI", vni, 0xffffff);
                vni <<= 8; /* VNI is in the upper 3 bytes */
                b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00);
                gen_and(b0, b1);
@@ -9976,9 +9348,7 @@ gen_vxlan4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
        /* Forcibly append these statements to the true condition
         * of the protocol check by creating a new block that is
         * always true and ANDing them. */
-       b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
-       b1->stmts = s;
-       b1->s.k = 0;
+       b1 = gen_jmp(cstate, BPF_JMP|BPF_JEQ|BPF_X, 0, s);
 
        gen_and(b0, b1);
 
@@ -10015,9 +9385,7 @@ gen_vxlan6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
        s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
        sappend(s, s1);
 
-       b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
-       b1->stmts = s;
-       b1->s.k = 0;
+       b1 = gen_jmp(cstate, BPF_JMP|BPF_JEQ|BPF_X, 0, s);
 
        gen_and(b0, b1);
 
@@ -10148,9 +9516,7 @@ gen_encap_ll_check(compiler_state_t *cstate)
        s1->s.k = cstate->off_linkpl.reg;
        sappend(s, s1);
 
-       b0 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
-       b0->stmts = s;
-       b0->s.k = 0;
+       b0 = gen_jmp(cstate, BPF_JMP|BPF_JEQ|BPF_X, 0, s);
        gen_not(b0);
 
        return b0;
@@ -10160,81 +9526,41 @@ static struct block *
 gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
     bpf_u_int32 jvalue, int jtype, int reverse)
 {
-       struct block *b0;
+       assert_atm(cstate, atmkw(atmfield));
 
        switch (atmfield) {
 
        case A_VPI:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'vpi' supported only on raw ATM");
-               if (cstate->off_vpi == OFFSET_NOT_SET)
-                       abort();
-               if (jvalue > UINT8_MAX)
-                       bpf_error(cstate, "VPI value %u > %u", jvalue, UINT8_MAX);
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B,
+               assert_maxval(cstate, "VPI", jvalue, UINT8_MAX);
+               return gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B,
                    0xffffffffU, jtype, reverse, jvalue);
-               break;
 
        case A_VCI:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'vci' supported only on raw ATM");
-               if (cstate->off_vci == OFFSET_NOT_SET)
-                       abort();
-               if (jvalue > UINT16_MAX)
-                       bpf_error(cstate, "VCI value %u > %u", jvalue, UINT16_MAX);
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H,
-                   0xffffffffU, jtype, reverse, jvalue);
-               break;
-
-       case A_PROTOTYPE:
-               if (cstate->off_proto == OFFSET_NOT_SET)
-                       abort();        /* XXX - this isn't on FreeBSD */
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
-                   0x0fU, jtype, reverse, jvalue);
-               break;
-
-       case A_MSGTYPE:
-               if (cstate->off_payload == OFFSET_NOT_SET)
-                       abort();
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B,
-                   0xffffffffU, jtype, reverse, jvalue);
-               break;
-
-       case A_CALLREFTYPE:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'callref' supported only on raw ATM");
-               if (cstate->off_proto == OFFSET_NOT_SET)
-                       abort();
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+               assert_maxval(cstate, "VCI", jvalue, UINT16_MAX);
+               return gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H,
                    0xffffffffU, jtype, reverse, jvalue);
-               break;
 
        default:
                abort();
        }
-       return b0;
 }
 
 static struct block *
-gen_atmtype_metac(compiler_state_t *cstate)
+gen_atm_vpi(compiler_state_t *cstate, const uint8_t v)
 {
-       struct block *b0, *b1;
-
-       b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
-       b1 = gen_atmfield_code_internal(cstate, A_VCI, 1, BPF_JEQ, 0);
-       gen_and(b0, b1);
-       return b1;
+       return gen_atmfield_code_internal(cstate, A_VPI, v, BPF_JEQ, 0);
 }
 
 static struct block *
-gen_atmtype_sc(compiler_state_t *cstate)
+gen_atm_vci(compiler_state_t *cstate, const uint16_t v)
 {
-       struct block *b0, *b1;
+       return gen_atmfield_code_internal(cstate, A_VCI, v, BPF_JEQ, 0);
+}
 
-       b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
-       b1 = gen_atmfield_code_internal(cstate, A_VCI, 5, BPF_JEQ, 0);
-       gen_and(b0, b1);
-       return b1;
+static struct block *
+gen_atm_prototype(compiler_state_t *cstate, const uint8_t v)
+{
+       return gen_mcmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, v, 0x0fU);
 }
 
 static struct block *
@@ -10242,7 +9568,7 @@ gen_atmtype_llc(compiler_state_t *cstate)
 {
        struct block *b0;
 
-       b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+       b0 = gen_atm_prototype(cstate, PT_LLC);
        cstate->linktype = cstate->prevlinktype;
        return b0;
 }
@@ -10274,63 +9600,55 @@ gen_atmtype_abbrev(compiler_state_t *cstate, int type)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
+       assert_atm(cstate, atmkw(type));
+
        switch (type) {
 
        case A_METAC:
                /* Get all packets in Meta signalling Circuit */
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'metac' supported only on raw ATM");
-               b1 = gen_atmtype_metac(cstate);
-               break;
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 1);
+               gen_and(b0, b1);
+               return b1;
 
        case A_BCC:
                /* Get all packets in Broadcast Circuit*/
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'bcc' supported only on raw ATM");
-               b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code_internal(cstate, A_VCI, 2, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 2);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        case A_OAMF4SC:
                /* Get all cells in Segment OAM F4 circuit*/
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'oam4sc' supported only on raw ATM");
-               b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 3);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        case A_OAMF4EC:
                /* Get all cells in End-to-End OAM F4 Circuit*/
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'oam4ec' supported only on raw ATM");
-               b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 4);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        case A_SC:
                /*  Get all packets in connection Signalling Circuit */
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'sc' supported only on raw ATM");
-               b1 = gen_atmtype_sc(cstate);
-               break;
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 5);
+               gen_and(b0, b1);
+               return b1;
 
        case A_ILMIC:
                /* Get all packets in ILMI Circuit */
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'ilmic' supported only on raw ATM");
-               b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code_internal(cstate, A_VCI, 16, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 16);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        case A_LANE:
                /* Get all LANE packets */
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'lane' supported only on raw ATM");
-               b1 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0);
+               b1 = gen_atm_prototype(cstate, PT_LANE);
 
                /*
                 * Arrange that all subsequent tests assume LANE
@@ -10347,19 +9665,11 @@ gen_atmtype_abbrev(compiler_state_t *cstate, int type)
                cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14;      /* Ethernet */
                cstate->off_nl = 0;                     /* Ethernet II */
                cstate->off_nl_nosnap = 3;              /* 802.3+802.2 */
-               break;
-
-       case A_LLC:
-               /* Get all LLC-encapsulated packets */
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'llc' supported only on raw ATM");
-               b1 = gen_atmtype_llc(cstate);
-               break;
+               return b1;
 
        default:
                abort();
        }
-       return b1;
 }
 
 /*
@@ -10381,74 +9691,45 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
+       assert_ss7(cstate, ss7kw(type));
+
        switch (type) {
 
        case M_FISU:
-               if ( (cstate->linktype != DLT_MTP2) &&
-                    (cstate->linktype != DLT_ERF) &&
-                    (cstate->linktype != DLT_MTP2_WITH_PHDR) )
-                       bpf_error(cstate, "'fisu' supported only on MTP2");
-               /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
-               b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
                    0x3fU, BPF_JEQ, 0, 0U);
-               break;
 
        case M_LSSU:
-               if ( (cstate->linktype != DLT_MTP2) &&
-                    (cstate->linktype != DLT_ERF) &&
-                    (cstate->linktype != DLT_MTP2_WITH_PHDR) )
-                       bpf_error(cstate, "'lssu' supported only on MTP2");
                b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
                    0x3fU, BPF_JGT, 1, 2U);
                b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
                    0x3fU, BPF_JGT, 0, 0U);
                gen_and(b1, b0);
-               break;
+               return b0;
 
        case M_MSU:
-               if ( (cstate->linktype != DLT_MTP2) &&
-                    (cstate->linktype != DLT_ERF) &&
-                    (cstate->linktype != DLT_MTP2_WITH_PHDR) )
-                       bpf_error(cstate, "'msu' supported only on MTP2");
-               b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
                    0x3fU, BPF_JGT, 0, 2U);
-               break;
 
        case MH_FISU:
-               if ( (cstate->linktype != DLT_MTP2) &&
-                    (cstate->linktype != DLT_ERF) &&
-                    (cstate->linktype != DLT_MTP2_WITH_PHDR) )
-                       bpf_error(cstate, "'hfisu' supported only on MTP2_HSL");
-               /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
-               b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
                    0xff80U, BPF_JEQ, 0, 0U);
-               break;
 
        case MH_LSSU:
-               if ( (cstate->linktype != DLT_MTP2) &&
-                    (cstate->linktype != DLT_ERF) &&
-                    (cstate->linktype != DLT_MTP2_WITH_PHDR) )
-                       bpf_error(cstate, "'hlssu' supported only on MTP2_HSL");
                b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
                    0xff80U, BPF_JGT, 1, 0x0100U);
                b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
                    0xff80U, BPF_JGT, 0, 0U);
                gen_and(b1, b0);
-               break;
+               return b0;
 
        case MH_MSU:
-               if ( (cstate->linktype != DLT_MTP2) &&
-                    (cstate->linktype != DLT_ERF) &&
-                    (cstate->linktype != DLT_MTP2_WITH_PHDR) )
-                       bpf_error(cstate, "'hmsu' supported only on MTP2_HSL");
-               b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
                    0xff80U, BPF_JGT, 0, 0x0100U);
-               break;
 
        default:
                abort();
        }
-       return b0;
 }
 
 /*
@@ -10463,7 +9744,6 @@ static struct block *
 gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
     bpf_u_int32 jvalue, int jtype, int reverse)
 {
-       struct block *b0;
        u_int newoff_sio;
        u_int newoff_opc;
        u_int newoff_dpc;
@@ -10473,6 +9753,9 @@ gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
        newoff_opc = cstate->off_opc;
        newoff_dpc = cstate->off_dpc;
        newoff_sls = cstate->off_sls;
+
+       assert_ss7(cstate, ss7kw(mtp3field));
+
        switch (mtp3field) {
 
        /*
@@ -10487,15 +9770,10 @@ gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
                /* FALLTHROUGH */
 
        case M_SIO:
-               if (cstate->off_sio == OFFSET_NOT_SET)
-                       bpf_error(cstate, "'sio' supported only on SS7");
-               if(jvalue > MTP2_SIO_MAXVAL)
-                       bpf_error(cstate, "sio value %u too big; max value = %u",
-                           jvalue, MTP2_SIO_MAXVAL);
+               assert_maxval(cstate, ss7kw(mtp3field), jvalue, MTP2_SIO_MAXVAL);
                // Here the bitmask means "do not apply a bitmask".
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, UINT32_MAX,
+               return gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, UINT32_MAX,
                    jtype, reverse, jvalue);
-               break;
 
        /*
         * See UTU-T Rec. Q.704, Section 2.2, Figure 3/Q.704.
@@ -10531,50 +9809,34 @@ gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
 
                /* FALLTHROUGH */
        case M_OPC:
-               if (cstate->off_opc == OFFSET_NOT_SET)
-                       bpf_error(cstate, "'opc' supported only on SS7");
-               if (jvalue > MTP3_PC_MAXVAL)
-                       bpf_error(cstate, "opc value %u too big; max value = %u",
-                           jvalue, MTP3_PC_MAXVAL);
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W,
+               assert_maxval(cstate, ss7kw(mtp3field), jvalue, MTP3_PC_MAXVAL);
+               return gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W,
                    SWAPLONG(MTP3_PC_MAXVAL << 14), jtype, reverse,
                    SWAPLONG(jvalue << 14));
-               break;
 
        case MH_DPC:
                newoff_dpc += 3;
                /* FALLTHROUGH */
 
        case M_DPC:
-               if (cstate->off_dpc == OFFSET_NOT_SET)
-                       bpf_error(cstate, "'dpc' supported only on SS7");
-               if (jvalue > MTP3_PC_MAXVAL)
-                       bpf_error(cstate, "dpc value %u too big; max value = %u",
-                           jvalue, MTP3_PC_MAXVAL);
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_H,
+               assert_maxval(cstate, ss7kw(mtp3field), jvalue, MTP3_PC_MAXVAL);
+               return gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_H,
                    SWAPSHORT(MTP3_PC_MAXVAL), jtype, reverse,
                    SWAPSHORT(jvalue));
-               break;
 
        case MH_SLS:
                newoff_sls += 3;
                /* FALLTHROUGH */
 
        case M_SLS:
-               if (cstate->off_sls == OFFSET_NOT_SET)
-                       bpf_error(cstate, "'sls' supported only on SS7");
-               if (jvalue > MTP3_SLS_MAXVAL)
-                        bpf_error(cstate, "sls value %u too big; max value = %u",
-                            jvalue, MTP3_SLS_MAXVAL);
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B,
+               assert_maxval(cstate, ss7kw(mtp3field), jvalue, MTP3_SLS_MAXVAL);
+               return gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B,
                    MTP3_SLS_MAXVAL << 4, jtype, reverse,
                    jvalue << 4);
-               break;
 
        default:
                abort();
        }
-       return b0;
 }
 
 struct block *
@@ -10593,44 +9855,14 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
 }
 
 static struct block *
-gen_msg_abbrev(compiler_state_t *cstate, int type)
+gen_msg_abbrev(compiler_state_t *cstate, const uint8_t type)
 {
-       struct block *b1;
-
        /*
         * Q.2931 signalling protocol messages for handling virtual circuits
         * establishment and teardown
         */
-       switch (type) {
-
-       case A_SETUP:
-               b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0);
-               break;
-
-       case A_CALLPROCEED:
-               b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0);
-               break;
-
-       case A_CONNECT:
-               b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0);
-               break;
-
-       case A_CONNECTACK:
-               b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0);
-               break;
-
-       case A_RELEASE:
-               b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0);
-               break;
-
-       case A_RELEASE_DONE:
-               b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0);
-               break;
-
-       default:
-               abort();
-       }
-       return b1;
+       return gen_cmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS,
+           BPF_B, type);
 }
 
 struct block *
@@ -10645,70 +9877,63 @@ gen_atmmulti_abbrev(compiler_state_t *cstate, int type)
        if (setjmp(cstate->top_ctx))
                return (NULL);
 
+       assert_atm(cstate, atmkw(type));
+
        switch (type) {
 
        case A_OAM:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'oam' supported only on raw ATM");
                /* OAM F4 type */
-               b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
-               b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+               b0 = gen_atm_vci(cstate, 3);
+               b1 = gen_atm_vci(cstate, 4);
                gen_or(b0, b1);
-               b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        case A_OAMF4:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'oamf4' supported only on raw ATM");
                /* OAM F4 type */
-               b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
-               b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+               b0 = gen_atm_vci(cstate, 3);
+               b1 = gen_atm_vci(cstate, 4);
                gen_or(b0, b1);
-               b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        case A_CONNECTMSG:
                /*
                 * Get Q.2931 signalling messages for switched
                 * virtual connection
                 */
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'connectmsg' supported only on raw ATM");
-               b0 = gen_msg_abbrev(cstate, A_SETUP);
-               b1 = gen_msg_abbrev(cstate, A_CALLPROCEED);
+               b0 = gen_msg_abbrev(cstate, SETUP);
+               b1 = gen_msg_abbrev(cstate, CALL_PROCEED);
                gen_or(b0, b1);
-               b0 = gen_msg_abbrev(cstate, A_CONNECT);
+               b0 = gen_msg_abbrev(cstate, CONNECT);
                gen_or(b0, b1);
-               b0 = gen_msg_abbrev(cstate, A_CONNECTACK);
+               b0 = gen_msg_abbrev(cstate, CONNECT_ACK);
                gen_or(b0, b1);
-               b0 = gen_msg_abbrev(cstate, A_RELEASE);
+               b0 = gen_msg_abbrev(cstate, RELEASE);
                gen_or(b0, b1);
-               b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE);
+               b0 = gen_msg_abbrev(cstate, RELEASE_DONE);
                gen_or(b0, b1);
-               b0 = gen_atmtype_sc(cstate);
+               b0 = gen_atmtype_abbrev(cstate, A_SC);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        case A_METACONNECT:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'metaconnect' supported only on raw ATM");
-               b0 = gen_msg_abbrev(cstate, A_SETUP);
-               b1 = gen_msg_abbrev(cstate, A_CALLPROCEED);
+               b0 = gen_msg_abbrev(cstate, SETUP);
+               b1 = gen_msg_abbrev(cstate, CALL_PROCEED);
                gen_or(b0, b1);
-               b0 = gen_msg_abbrev(cstate, A_CONNECT);
+               b0 = gen_msg_abbrev(cstate, CONNECT);
                gen_or(b0, b1);
-               b0 = gen_msg_abbrev(cstate, A_RELEASE);
+               b0 = gen_msg_abbrev(cstate, RELEASE);
                gen_or(b0, b1);
-               b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE);
+               b0 = gen_msg_abbrev(cstate, RELEASE_DONE);
                gen_or(b0, b1);
-               b0 = gen_atmtype_metac(cstate);
+               b0 = gen_atmtype_abbrev(cstate, A_METAC);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        default:
                abort();
        }
-       return b1;
 }