]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
Consolidate MAC-48 address matching code.
[libpcap] / gencode.c
index d284981425c4fce477c2df45467c804db0a43c39..eed4863cbb7189c5730d1fb5ddec4969295dfb3e 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -1,4 +1,3 @@
-/*#define CHASE_CHAIN*/
 /*
  * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
  *     The Regents of the University of California.  All rights reserved.
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
 
 #ifdef _WIN32
-#include <pcap-stdinc.h>
-#else /* _WIN32 */
-#if HAVE_INTTYPES_H
-#include <inttypes.h>
-#elif HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#ifdef HAVE_SYS_BITYPES_H
-#include <sys/bitypes.h>
-#endif
-#include <sys/types.h>
-#include <sys/socket.h>
-#endif /* _WIN32 */
-
-#ifndef _WIN32
-
-#ifdef __NetBSD__
-#include <sys/param.h>
-#endif
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
+  #include <ws2tcpip.h>
+#else
+  #include <netinet/in.h>
 #endif /* _WIN32 */
 
 #include <stdlib.h>
 #include <memory.h>
 #include <setjmp.h>
 #include <stdarg.h>
-
-#ifdef MSDOS
-#include "pcap-dos.h"
-#endif
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
 
 #include "pcap-int.h"
 
+#include "extract.h"
+
 #include "ethertype.h"
-#include "nlpid.h"
 #include "llc.h"
 #include "gencode.h"
 #include "ieee80211.h"
-#include "atmuni31.h"
-#include "sunatmpos.h"
+#include "pflog.h"
 #include "ppp.h"
 #include "pcap/sll.h"
 #include "pcap/ipnet.h"
-#include "arcnet.h"
+#include "diag-control.h"
+#include "pcap-util.h"
 
-#include "grammar.h"
 #include "scanner.h"
 
-#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
+#if defined(__linux__)
 #include <linux/types.h>
 #include <linux/if_packet.h>
 #include <linux/filter.h>
 #endif
 
-#ifdef HAVE_NET_PFVAR_H
-#include <sys/socket.h>
-#include <net/if.h>
-#include <net/pfvar.h>
-#include <net/if_pflog.h>
-#endif
-
-#ifndef offsetof
-#define offsetof(s, e) ((size_t)&((s *)0)->e)
-#endif
-
-#ifdef INET6
 #ifdef _WIN32
-#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
+  #ifdef HAVE_NPCAP_BPF_H
+    /* Defines BPF extensions for Npcap */
+    #include <npcap-bpf.h>
+  #endif
+  #ifdef INET6
+    #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
 /* IPv6 address */
 struct in6_addr
   {
     union
       {
-       u_int8_t                u6_addr8[16];
-       u_int16_t       u6_addr16[8];
-       u_int32_t       u6_addr32[4];
+       uint8_t         u6_addr8[16];
+       uint16_t        u6_addr16[8];
+       uint32_t        u6_addr32[4];
       } in6_u;
 #define s6_addr                        in6_u.u6_addr8
 #define s6_addr16              in6_u.u6_addr16
@@ -121,12 +90,12 @@ typedef unsigned short     sa_family_t;
 struct sockaddr_in6
   {
     __SOCKADDR_COMMON (sin6_);
-    u_int16_t sin6_port;               /* Transport layer port # */
-    u_int32_t sin6_flowinfo;   /* IPv6 flow information */
+    uint16_t sin6_port;                /* Transport layer port # */
+    uint32_t sin6_flowinfo;    /* IPv6 flow information */
     struct in6_addr sin6_addr; /* IPv6 address */
   };
 
-#ifndef EAI_ADDRFAMILY
+      #ifndef EAI_ADDRFAMILY
 struct addrinfo {
        int     ai_flags;       /* AI_PASSIVE, AI_CANONNAME */
        int     ai_family;      /* PF_xxx */
@@ -137,22 +106,18 @@ struct addrinfo {
        struct sockaddr *ai_addr;       /* binary address */
        struct addrinfo *ai_next;       /* next structure in linked list */
 };
-#endif /* EAI_ADDRFAMILY */
-#endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */
+      #endif /* EAI_ADDRFAMILY */
+    #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */
+  #endif /* INET6 */
 #else /* _WIN32 */
-#include <netdb.h>     /* for "struct addrinfo" */
+  #include <netdb.h>   /* for "struct addrinfo" */
 #endif /* _WIN32 */
-#endif /* INET6 */
 #include <pcap/namedb.h>
 
 #include "nametoaddr.h"
 
 #define ETHERMTU       1500
 
-#ifndef ETHERTYPE_TEB
-#define ETHERTYPE_TEB 0x6558
-#endif
-
 #ifndef IPPROTO_HOPOPTS
 #define IPPROTO_HOPOPTS 0
 #endif
@@ -170,6 +135,142 @@ struct addrinfo {
 #endif
 
 #define GENEVE_PORT 6081
+#define VXLAN_PORT  4789
+
+
+/*
+ * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp
+ */
+
+/* RFC 1051 */
+#define        ARCTYPE_IP_OLD          240     /* IP protocol */
+#define        ARCTYPE_ARP_OLD         241     /* address resolution protocol */
+
+/* RFC 1201 */
+#define        ARCTYPE_IP              212     /* IP protocol */
+#define        ARCTYPE_ARP             213     /* address resolution protocol */
+#define        ARCTYPE_REVARP          214     /* reverse addr resolution protocol */
+
+#define        ARCTYPE_ATALK           221     /* Appletalk */
+#define        ARCTYPE_BANIAN          247     /* Banyan Vines */
+#define        ARCTYPE_IPX             250     /* Novell IPX */
+
+#define ARCTYPE_INET6          0xc4    /* IPng */
+#define ARCTYPE_DIAGNOSE       0x80    /* as per ANSI/ATA 878.1 */
+
+
+/* Based on UNI3.1 standard by ATM Forum */
+
+/* ATM traffic types based on VPI=0 and (the following VCI */
+#define VCI_PPC                        0x05    /* Point-to-point signal msg */
+#define VCI_BCC                        0x02    /* Broadcast signal msg */
+#define VCI_OAMF4SC            0x03    /* Segment OAM F4 flow cell */
+#define VCI_OAMF4EC            0x04    /* End-to-end OAM F4 flow cell */
+#define VCI_METAC              0x01    /* Meta signal msg */
+#define VCI_ILMIC              0x10    /* ILMI msg */
+
+/* Q.2931 signalling messages */
+#define CALL_PROCEED           0x02    /* call proceeding */
+#define CONNECT                        0x07    /* connect */
+#define CONNECT_ACK            0x0f    /* connect_ack */
+#define SETUP                  0x05    /* setup */
+#define RELEASE                        0x4d    /* release */
+#define RELEASE_DONE           0x5a    /* release_done */
+#define RESTART                        0x46    /* restart */
+#define RESTART_ACK            0x4e    /* restart ack */
+#define STATUS                 0x7d    /* status */
+#define STATUS_ENQ             0x75    /* status ack */
+#define ADD_PARTY              0x80    /* add party */
+#define ADD_PARTY_ACK          0x81    /* add party ack */
+#define ADD_PARTY_REJ          0x82    /* add party rej */
+#define DROP_PARTY             0x83    /* drop party */
+#define DROP_PARTY_ACK         0x84    /* drop party ack */
+
+/* Information Element Parameters in the signalling messages */
+#define CAUSE                  0x08    /* cause */
+#define ENDPT_REF              0x54    /* endpoint reference */
+#define AAL_PARA               0x58    /* ATM adaptation layer parameters */
+#define TRAFF_DESCRIP          0x59    /* atm traffic descriptors */
+#define CONNECT_ID             0x5a    /* connection identifier */
+#define QOS_PARA               0x5c    /* quality of service parameters */
+#define B_HIGHER               0x5d    /* broadband higher layer information */
+#define B_BEARER               0x5e    /* broadband bearer capability */
+#define B_LOWER                        0x5f    /* broadband lower information */
+#define CALLING_PARTY          0x6c    /* calling party number */
+#define CALLED_PARTY           0x70    /* called party number */
+
+#define Q2931                  0x09
+
+/* Q.2931 signalling general messages format */
+#define PROTO_POS       0      /* offset of protocol discriminator */
+#define CALL_REF_POS    2      /* offset of call reference value */
+#define MSG_TYPE_POS    5      /* offset of message type */
+#define MSG_LEN_POS     7      /* offset of message length */
+#define IE_BEGIN_POS    9      /* offset of first information element */
+
+/* format of signalling messages */
+#define TYPE_POS       0
+#define LEN_POS                2
+#define FIELD_BEGIN_POS 4
+
+
+/* SunATM header for ATM packet */
+#define SUNATM_DIR_POS         0
+#define SUNATM_VPI_POS         1
+#define SUNATM_VCI_POS         2
+#define SUNATM_PKT_BEGIN_POS   4       /* Start of ATM packet */
+
+/* Protocol type values in the bottom for bits of the byte at SUNATM_DIR_POS. */
+#define PT_LANE                0x01    /* LANE */
+#define PT_LLC         0x02    /* LLC encapsulation */
+#define PT_ILMI                0x05    /* ILMI */
+#define PT_QSAAL       0x06    /* Q.SAAL */
+
+
+/* Types missing from some systems */
+
+/*
+ * Network layer protocol identifiers
+ */
+#ifndef ISO8473_CLNP
+#define ISO8473_CLNP           0x81
+#endif
+#ifndef        ISO9542_ESIS
+#define        ISO9542_ESIS            0x82
+#endif
+#ifndef ISO9542X25_ESIS
+#define ISO9542X25_ESIS                0x8a
+#endif
+#ifndef        ISO10589_ISIS
+#define        ISO10589_ISIS           0x83
+#endif
+
+#define ISIS_L1_LAN_IIH      15
+#define ISIS_L2_LAN_IIH      16
+#define ISIS_PTP_IIH         17
+#define ISIS_L1_LSP          18
+#define ISIS_L2_LSP          20
+#define ISIS_L1_CSNP         24
+#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
+#endif
+#ifndef        ISO10747_IDRP
+#define        ISO10747_IDRP           0x85
+#endif
+
+// Same as in tcpdump/print-sl.c.
+#define SLIPDIR_IN 0
+#define SLIPDIR_OUT 1
 
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
@@ -190,7 +291,7 @@ struct addrinfo {
        (cs)->off_linkhdr.is_variable = (new_is_variable); \
        (cs)->off_linkhdr.constant_part = (new_constant_part); \
        (cs)->off_linkhdr.reg = (new_reg); \
-       (cs)->is_geneve = 0; \
+       (cs)->is_encap = 0; \
 }
 
 /*
@@ -239,7 +340,7 @@ enum e_offrel {
 };
 
 /*
- * We divy out chunks of memory rather than call malloc each time so
+ * We divvy out chunks of memory rather than call malloc each time so
  * we don't have to worry about leaking memory.  It's probably
  * not a big deal if all this memory was wasted but if this ever
  * goes into a library that would probably not be a good idea.
@@ -253,11 +354,32 @@ struct chunk {
        void *m;
 };
 
+/*
+ * A chunk can store any of:
+ *  - a string (guaranteed alignment 1 but present for completeness)
+ *  - a block
+ *  - an slist
+ *  - an arth
+ * For this simple allocator every allocated chunk gets rounded up to the
+ * alignment needed for any chunk.
+ */
+struct chunk_align {
+       char dummy;
+       union {
+               char c;
+               struct block b;
+               struct slist s;
+               struct arth a;
+       } u;
+};
+#define CHUNK_ALIGN (offsetof(struct chunk_align, u))
+
 /* Code generator state */
 
 struct _compiler_state {
        jmp_buf top_ctx;
        pcap_t *bpf_pcap;
+       int error_set;
 
        struct icode ic;
 
@@ -277,7 +399,6 @@ struct _compiler_state {
        /* XXX */
        u_int pcap_fddipad;
 
-#ifdef INET6
        /*
         * As errors are handled by a longjmp, anything allocated must
         * be freed in the longjmp handler, so it must be reachable
@@ -288,7 +409,13 @@ struct _compiler_state {
         * any addrinfo structure that would need to be freed.
         */
        struct addrinfo *ai;
-#endif
+
+       /*
+        * Another thing that's allocated is the result of pcap_ether_aton();
+        * it must be freed with free().  This variable points to any
+        * address that would need to be freed.
+        */
+       u_char *e;
 
        /*
         * Various code constructs need to know the layout of the packet.
@@ -350,12 +477,12 @@ struct _compiler_state {
         */
        int is_atm;
 
-       /*
-        * TRUE if "geneve" appeared in the filter; it causes us to
-        * generate code that checks for a Geneve header and assume
-        * that later filters apply to the encapsulated payload.
+       /* TRUE if "geneve" or "vxlan" appeared in the filter; it
+        * causes us to generate code that checks for a Geneve or
+        * VXLAN header respectively and assume that later filters
+        * apply to the encapsulated payload.
         */
-       int is_geneve;
+       int is_encap;
 
        /*
         * TRUE if we need variable length part of VLAN offset
@@ -431,35 +558,64 @@ struct _compiler_state {
        int cur_chunk;
 };
 
+/*
+ * For use by routines outside this file.
+ */
+/* VARARGS */
 void
-bpf_syntax_error(compiler_state_t *cstate, const char *msg)
+bpf_set_error(compiler_state_t *cstate, const char *fmt, ...)
 {
-       bpf_error(cstate, "syntax error in filter expression: %s", msg);
-       /* NOTREACHED */
+       va_list ap;
+
+       /*
+        * If we've already set an error, don't override it.
+        * The lexical analyzer reports some errors by setting
+        * the error and then returning a LEX_ERROR token, which
+        * is not recognized by any grammar rule, and thus forces
+        * the parse to stop.  We don't want the error reported
+        * by the lexical analyzer to be overwritten by the syntax
+        * error.
+        */
+       if (!cstate->error_set) {
+               va_start(ap, fmt);
+               (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+                   fmt, ap);
+               va_end(ap);
+               cstate->error_set = 1;
+       }
 }
 
+/*
+ * For use *ONLY* in routines in this file.
+ */
+static void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...)
+    PCAP_PRINTFLIKE(2, 3);
+
 /* VARARGS */
-void
+static void PCAP_NORETURN
 bpf_error(compiler_state_t *cstate, const char *fmt, ...)
 {
        va_list ap;
 
        va_start(ap, fmt);
-       if (cstate->bpf_pcap != NULL)
-               (void)pcap_vsnprintf(pcap_geterr(cstate->bpf_pcap),
-                   PCAP_ERRBUF_SIZE, fmt, ap);
+       (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+           fmt, ap);
        va_end(ap);
        longjmp(cstate->top_ctx, 1);
-       /* NOTREACHED */
+       /*NOTREACHED*/
+#ifdef _AIX
+       PCAP_UNREACHABLE
+#endif /* _AIX */
 }
 
-static void init_linktype(compiler_state_t *, pcap_t *);
+static int init_linktype(compiler_state_t *, pcap_t *);
 
 static void init_regs(compiler_state_t *);
 static int alloc_reg(compiler_state_t *);
 static void free_reg(compiler_state_t *, int);
 
 static void initchunks(compiler_state_t *cstate);
+static void *newchunk_nolongjmp(compiler_state_t *cstate, size_t);
 static void *newchunk(compiler_state_t *cstate, size_t);
 static void freechunks(compiler_state_t *cstate);
 static inline struct block *new_block(compiler_state_t *cstate, int);
@@ -470,21 +626,29 @@ static inline void syntax(compiler_state_t *cstate);
 static void backpatch(struct block *, struct block *);
 static void merge(struct block *, struct block *);
 static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    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_int32, bpf_u_int32);
+    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_ncmp(compiler_state_t *, enum e_offrel, bpf_u_int32,
-    bpf_u_int32, bpf_u_int32, bpf_u_int32, int, bpf_int32);
+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 *,
     u_int, u_int);
 static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int,
@@ -493,9 +657,10 @@ static struct slist *gen_loadx_iphdrlen(compiler_state_t *);
 static struct block *gen_uncond(compiler_state_t *, int);
 static inline struct block *gen_true(compiler_state_t *);
 static inline struct block *gen_false(compiler_state_t *);
-static struct block *gen_ether_linktype(compiler_state_t *, int);
-static struct block *gen_ipnet_linktype(compiler_state_t *, int);
-static struct block *gen_linux_sll_linktype(compiler_state_t *, int);
+static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32);
+static struct slist *gen_load_pflog_llprefixlen(compiler_state_t *);
 static struct slist *gen_load_prism_llprefixlen(compiler_state_t *);
 static struct slist *gen_load_avs_llprefixlen(compiler_state_t *);
 static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *);
@@ -503,24 +668,23 @@ 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 int ethertype_to_ppptype(int);
-static struct block *gen_linktype(compiler_state_t *, int);
+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 *, int);
+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, int, 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, int, u_int, u_int);
+    struct in6_addr *, int, u_int, u_int);
 #endif
-static struct block *gen_ahostop(compiler_state_t *, const u_char *, 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_ahostop(compiler_state_t *, const uint8_t, 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 *, 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,
     int, int, int);
 #ifdef INET6
@@ -529,35 +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 *,
-    bpf_u_int32 **, 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_int32);
-static struct block *gen_portrangeatom(compiler_state_t *, int, bpf_int32,
-    bpf_int32);
-static struct block *gen_portatom6(compiler_state_t *, int, bpf_int32);
-static struct block *gen_portrangeatom6(compiler_state_t *, int, bpf_int32,
-    bpf_int32);
-struct block *gen_portop(compiler_state_t *, int, int, int);
-static struct block *gen_port(compiler_state_t *, int, int, int);
-struct block *gen_portrangeop(compiler_state_t *, int, int, int, int);
-static struct block *gen_portrange(compiler_state_t *, int, int, int, int);
-struct block *gen_portop6(compiler_state_t *, int, int, int);
-static struct block *gen_port6(compiler_state_t *, int, int, int);
-struct block *gen_portrangeop6(compiler_state_t *, int, int, int, int);
-static struct block *gen_portrange6(compiler_state_t *, int, 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);
-static struct block *gen_protochain(compiler_state_t *, int, int, int);
-static struct block *gen_proto(compiler_state_t *, int, int, 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);
 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_geneve_ll_check(compiler_state_t *cstate);
+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_msg_abbrev(compiler_state_t *, int type);
+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 *, 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)
@@ -572,38 +744,53 @@ initchunks(compiler_state_t *cstate)
 }
 
 static void *
-newchunk(compiler_state_t *cstate, size_t n)
+newchunk_nolongjmp(compiler_state_t *cstate, size_t n)
 {
        struct chunk *cp;
        int k;
        size_t size;
 
-#ifndef __NetBSD__
-       /* XXX Round up to nearest long. */
-       n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
-#else
-       /* XXX Round up to structure boundary. */
-       n = ALIGN(n);
-#endif
+       /* Round up to chunk alignment. */
+       n = (n + CHUNK_ALIGN - 1) & ~(CHUNK_ALIGN - 1);
 
        cp = &cstate->chunks[cstate->cur_chunk];
        if (n > cp->n_left) {
-               ++cp, k = ++cstate->cur_chunk;
-               if (k >= NCHUNKS)
-                       bpf_error(cstate, "out of memory");
+               ++cp;
+               k = ++cstate->cur_chunk;
+               if (k >= NCHUNKS) {
+                       bpf_set_error(cstate, "out of memory");
+                       return (NULL);
+               }
                size = CHUNK0SIZE << k;
                cp->m = (void *)malloc(size);
-               if (cp->m == NULL)
-                       bpf_error(cstate, "out of memory");
+               if (cp->m == NULL) {
+                       bpf_set_error(cstate, "out of memory");
+                       return (NULL);
+               }
                memset((char *)cp->m, 0, size);
                cp->n_left = size;
-               if (n > size)
-                       bpf_error(cstate, "out of memory");
+               if (n > size) {
+                       bpf_set_error(cstate, "out of memory");
+                       return (NULL);
+               }
        }
        cp->n_left -= n;
        return (void *)((char *)cp->m + cp->n_left);
 }
 
+static void *
+newchunk(compiler_state_t *cstate, size_t n)
+{
+       void *p;
+
+       p = newchunk_nolongjmp(cstate, n);
+       if (p == NULL) {
+               longjmp(cstate->top_ctx, 1);
+               /*NOTREACHED*/
+       }
+       return (p);
+}
+
 static void
 freechunks(compiler_state_t *cstate)
 {
@@ -616,14 +803,19 @@ freechunks(compiler_state_t *cstate)
 
 /*
  * A strdup whose allocations are freed after code generation is over.
+ * This is used by the lexical analyzer, so it can't longjmp; it just
+ * returns NULL on an allocation error, and the callers must check
+ * for it.
  */
 char *
 sdup(compiler_state_t *cstate, const char *s)
 {
        size_t n = strlen(s) + 1;
-       char *cp = newchunk(cstate, n);
+       char *cp = newchunk_nolongjmp(cstate, n);
 
-       strlcpy(cp, s, n);
+       if (cp == NULL)
+               return (NULL);
+       pcapint_strlcpy(cp, s, n);
        return (cp);
 }
 
@@ -651,7 +843,7 @@ new_stmt(compiler_state_t *cstate, int code)
 }
 
 static struct block *
-gen_retblk(compiler_state_t *cstate, int v)
+gen_retblk_internal(compiler_state_t *cstate, int v)
 {
        struct block *b = new_block(cstate, BPF_RET|BPF_K);
 
@@ -659,43 +851,279 @@ gen_retblk(compiler_state_t *cstate, int v)
        return b;
 }
 
-static inline void
+static struct block *
+gen_retblk(compiler_state_t *cstate, int v)
+{
+       if (setjmp(cstate->top_ctx)) {
+               /*
+                * gen_retblk() only fails because a memory
+                * allocation failed in newchunk(), meaning
+                * that it can't return a pointer.
+                *
+                * Return NULL.
+                */
+               return NULL;
+       }
+       return gen_retblk_internal(cstate, v);
+}
+
+static inline PCAP_NORETURN_DEF void
 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)
 {
 #ifdef _WIN32
-       static int done = 0;
+       int err;
+       WSADATA wsaData;
 #endif
        compiler_state_t cstate;
-       const char * volatile xbuf = buf;
        yyscan_t scanner = NULL;
        YY_BUFFER_STATE in_buffer = NULL;
        u_int len;
-       int  rc;
+       int rc;
 
        /*
         * If this pcap_t hasn't been activated, it doesn't have a
         * link-layer type, so we can't use it.
         */
        if (!p->activated) {
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "not-yet-activated pcap_t passed to pcap_compile");
-               return (-1);
+               return (PCAP_ERROR);
        }
 
 #ifdef _WIN32
-       if (!done)
-               pcap_wsockinit();
-       done = 1;
+       /*
+        * Initialize Winsock, asking for the latest version (2.2),
+        * as we may be calling Winsock routines to translate
+        * host names to addresses.
+        */
+       err = WSAStartup(MAKEWORD(2, 2), &wsaData);
+       if (err != 0) {
+               pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+                   err, "Error calling WSAStartup()");
+               return (PCAP_ERROR);
+       }
 #endif
 
-#ifdef HAVE_REMOTE
+#ifdef ENABLE_REMOTE
        /*
         * If the device on which we're capturing need to be notified
         * that a new filter is being compiled, do so.
@@ -710,7 +1138,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
         * filter for this pcap_t; we might be running it from userland
         * on captured packets to do packet classification.  We really
         * need a better way of handling this, but this is all that
-        * the WinPcap code did.
+        * the WinPcap remote capture code did.
         */
        if (p->save_current_filter_op != NULL)
                (p->save_current_filter_op)(p, buf);
@@ -721,33 +1149,30 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
 #ifdef INET6
        cstate.ai = NULL;
 #endif
+       cstate.e = NULL;
        cstate.ic.root = NULL;
        cstate.ic.cur_mark = 0;
        cstate.bpf_pcap = p;
+       cstate.error_set = 0;
        init_regs(&cstate);
 
-       if (setjmp(cstate.top_ctx)) {
-#ifdef INET6
-               if (cstate.ai != NULL)
-                       freeaddrinfo(cstate.ai);
-#endif
-               rc = -1;
-               goto quit;
-       }
-
        cstate.netmask = mask;
 
        cstate.snaplen = pcap_snapshot(p);
        if (cstate.snaplen == 0) {
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                         "snaplen of 0 rejects all packets");
-               rc = -1;
+               rc = PCAP_ERROR;
                goto quit;
        }
 
-       if (pcap_lex_init(&scanner) != 0)
-               bpf_error(&cstate, "can't initialize scanner: %s", pcap_strerror(errno));
-       in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner);
+       if (pcap_lex_init(&scanner) != 0) {
+               pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "can't initialize scanner");
+               rc = PCAP_ERROR;
+               goto quit;
+       }
+       in_buffer = pcap__scan_string(buf ? buf : "", scanner);
 
        /*
         * Associate the compiler state with the lexical analyzer
@@ -755,19 +1180,54 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
         */
        pcap_set_extra(&cstate, scanner);
 
-       init_linktype(&cstate, p);
-       (void)pcap_parse(scanner, &cstate);
+       if (init_linktype(&cstate, p) == -1) {
+               rc = PCAP_ERROR;
+               goto quit;
+       }
+       if (pcap_parse(scanner, &cstate) != 0) {
+#ifdef INET6
+               if (cstate.ai != NULL)
+                       freeaddrinfo(cstate.ai);
+#endif
+               if (cstate.e != NULL)
+                       free(cstate.e);
+               rc = PCAP_ERROR;
+               goto quit;
+       }
 
-       if (cstate.ic.root == NULL)
+       if (cstate.ic.root == NULL) {
                cstate.ic.root = gen_retblk(&cstate, cstate.snaplen);
 
+               /*
+                * Catch errors reported by gen_retblk().
+                */
+               if (cstate.ic.root== NULL) {
+                       rc = PCAP_ERROR;
+                       goto quit;
+               }
+       }
+
        if (optimize && !cstate.no_optimize) {
-               bpf_optimize(&cstate, &cstate.ic);
+               if (bpf_optimize(&cstate.ic, p->errbuf) == -1) {
+                       /* Failure */
+                       rc = PCAP_ERROR;
+                       goto quit;
+               }
                if (cstate.ic.root == NULL ||
-                   (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0))
-                       bpf_error(&cstate, "expression rejects all packets");
+                   (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) {
+                       (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "expression rejects all packets");
+                       rc = PCAP_ERROR;
+                       goto quit;
+               }
+       }
+       program->bf_insns = icode_to_fcode(&cstate.ic,
+           cstate.ic.root, &len, p->errbuf);
+       if (program->bf_insns == NULL) {
+               /* Failure */
+               rc = PCAP_ERROR;
+               goto quit;
        }
-       program->bf_insns = icode_to_fcode(&cstate, &cstate.ic, cstate.ic.root, &len);
        program->bf_len = len;
 
        rc = 0;  /* We're all okay */
@@ -786,6 +1246,10 @@ quit:
         */
        freechunks(&cstate);
 
+#ifdef _WIN32
+       WSACleanup();
+#endif
+
        return (rc);
 }
 
@@ -796,14 +1260,14 @@ quit:
 int
 pcap_compile_nopcap(int snaplen_arg, int linktype_arg,
                    struct bpf_program *program,
-            const char *buf, int optimize, bpf_u_int32 mask)
+                   const char *buf, int optimize, bpf_u_int32 mask)
 {
        pcap_t *p;
        int ret;
 
        p = pcap_open_dead(linktype_arg, snaplen_arg);
        if (p == NULL)
-               return (-1);
+               return (PCAP_ERROR);
        ret = pcap_compile(p, program, buf, optimize, mask);
        pcap_close(p);
        return (ret);
@@ -830,8 +1294,7 @@ pcap_freecode(struct bpf_program *program)
  * in each block is already resolved.
  */
 static void
-backpatch(list, target)
-       struct block *list, *target;
+backpatch(struct block *list, struct block *target)
 {
        struct block *next;
 
@@ -852,8 +1315,7 @@ backpatch(list, target)
  * which of jt and jf is the link.
  */
 static void
-merge(b0, b1)
-       struct block *b0, *b1;
+merge(struct block *b0, struct block *b1)
 {
        register struct block **p = &b0;
 
@@ -865,10 +1327,15 @@ merge(b0, b1)
        *p = b1;
 }
 
-void
+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.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (-1);
 
        /*
         * Insert before the statements of the first (root) block any
@@ -904,19 +1371,21 @@ 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(cstate, cstate->snaplen));
+       backpatch(p, gen_retblk_internal(cstate, cstate->snaplen));
        p->sense = !p->sense;
-       backpatch(p, gen_retblk(cstate, 0));
+       backpatch(p, gen_retblk_internal(cstate, 0));
        cstate->ic.root = p->head;
+       return (0);
 }
 
 void
-gen_and(b0, b1)
-       struct block *b0, *b1;
+gen_and(struct block *b0, struct block *b1)
 {
        backpatch(b0, b1->head);
        b0->sense = !b0->sense;
@@ -927,8 +1396,7 @@ gen_and(b0, b1)
 }
 
 void
-gen_or(b0, b1)
-       struct block *b0, *b1;
+gen_or(struct block *b0, struct block *b1)
 {
        b0->sense = !b0->sense;
        backpatch(b0, b1->head);
@@ -938,54 +1406,80 @@ gen_or(b0, b1)
 }
 
 void
-gen_not(b)
-       struct block *b;
+gen_not(struct block *b)
 {
        b->sense = !b->sense;
 }
 
 static struct block *
 gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
        return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v);
 }
 
 static struct block *
 gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
        return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v);
 }
 
 static struct block *
 gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
        return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v);
 }
 
 static struct block *
 gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
        return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v);
 }
 
 static struct block *
 gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
        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_int32 v, bpf_u_int32 mask)
+    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)
@@ -995,10 +1489,9 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
        b = NULL;
        while (size >= 4) {
                register const u_char *p = &v[size - 4];
-               bpf_int32 w = ((bpf_int32)p[0] << 24) |
-                   ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3];
 
-               tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, w);
+               tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W,
+                   EXTRACT_BE_U_4(p));
                if (b != NULL)
                        gen_and(b, tmp);
                b = tmp;
@@ -1006,16 +1499,16 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
        }
        while (size >= 2) {
                register const u_char *p = &v[size - 2];
-               bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1];
 
-               tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, w);
+               tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H,
+                   EXTRACT_BE_U_2(p));
                if (b != NULL)
                        gen_and(b, tmp);
                b = tmp;
                size -= 2;
        }
        if (size > 0) {
-               tmp = gen_cmp(cstate, offrel, offset, BPF_B, (bpf_int32)v[0]);
+               tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]);
                if (b != NULL)
                        gen_and(b, tmp);
                b = tmp;
@@ -1023,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"
@@ -1030,9 +1546,9 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
  * should test the opposite of "jtype".
  */
 static struct block *
-gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, bpf_u_int32 offset,
-    bpf_u_int32 size, bpf_u_int32 mask, bpf_u_int32 jtype, int reverse,
-    bpf_int32 v)
+gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 mask, int jtype, int reverse,
+    bpf_u_int32 v)
 {
        struct slist *s, *s2;
        struct block *b;
@@ -1045,15 +1561,13 @@ gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, bpf_u_int32 offset,
                sappend(s, s2);
        }
 
-       b = new_block(cstate, JMP(jtype));
-       b->stmts = s;
-       b->s.k = v;
-       if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE))
+       b = gen_jmp(cstate, jtype, v, s);
+       if (reverse)
                gen_not(b);
        return b;
 }
 
-static void
+static int
 init_linktype(compiler_state_t *cstate, pcap_t *p)
 {
        cstate->pcap_fddipad = p->fddipad;
@@ -1091,15 +1605,15 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
         * Assume it's not raw ATM with a pseudo-header, for now.
         */
        cstate->is_atm = 0;
-       cstate->off_vpi = -1;
-       cstate->off_vci = -1;
-       cstate->off_proto = -1;
-       cstate->off_payload = -1;
+       cstate->off_vpi = OFFSET_NOT_SET;
+       cstate->off_vci = OFFSET_NOT_SET;
+       cstate->off_proto = OFFSET_NOT_SET;
+       cstate->off_payload = OFFSET_NOT_SET;
 
        /*
-        * And not Geneve.
+        * And not encapsulated with either Geneve or VXLAN.
         */
-       cstate->is_geneve = 0;
+       cstate->is_encap = 0;
 
        /*
         * No variable length VLAN offset by default
@@ -1109,12 +1623,12 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
        /*
         * And assume we're not doing SS7.
         */
-       cstate->off_li = -1;
-       cstate->off_li_hsl = -1;
-       cstate->off_sio = -1;
-       cstate->off_opc = -1;
-       cstate->off_dpc = -1;
-       cstate->off_sls = -1;
+       cstate->off_li = OFFSET_NOT_SET;
+       cstate->off_li_hsl = OFFSET_NOT_SET;
+       cstate->off_sio = OFFSET_NOT_SET;
+       cstate->off_opc = OFFSET_NOT_SET;
+       cstate->off_dpc = OFFSET_NOT_SET;
+       cstate->off_sls = OFFSET_NOT_SET;
 
        cstate->label_stack_depth = 0;
        cstate->vlan_stack_depth = 0;
@@ -1124,7 +1638,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
        case DLT_ARCNET:
                cstate->off_linktype.constant_part = 2;
                cstate->off_linkpl.constant_part = 6;
-               cstate->off_nl = 0;     /* XXX in reality, variable! */
+               cstate->off_nl = 0;             /* XXX in reality, variable! */
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
                break;
 
@@ -1180,6 +1694,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
        case DLT_PPP:
        case DLT_PPP_PPPD:
        case DLT_C_HDLC:                /* BSD/OS Cisco HDLC */
+       case DLT_HDLC:                  /* NetBSD (Cisco) HDLC */
        case DLT_PPP_SERIAL:            /* NetBSD sync/async serial PPP */
                cstate->off_linktype.constant_part = 2; /* skip HDLC-like framing */
                cstate->off_linkpl.constant_part = 4;   /* skip HDLC-like framing and protocol field */
@@ -1189,7 +1704,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
 
        case DLT_PPP_ETHER:
                /*
-                * This does no include the Ethernet header, and
+                * This does not include the Ethernet header, and
                 * only covers session state.
                 */
                cstate->off_linktype.constant_part = 6;
@@ -1258,6 +1773,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_linkhdr.is_variable = 1;
                /* Fall through, 802.11 doesn't have a variable link
                 * prefix but is otherwise the same. */
+               /* FALLTHROUGH */
 
        case DLT_IEEE802_11:
                /*
@@ -1347,13 +1863,20 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
                break;
 
-       case DLT_LINUX_SLL:     /* fake header for Linux cooked socket */
+       case DLT_LINUX_SLL:     /* fake header for Linux cooked socket v1 */
                cstate->off_linktype.constant_part = 14;
                cstate->off_linkpl.constant_part = 16;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
                break;
 
+       case DLT_LINUX_SLL2:    /* fake header for Linux cooked socket v2 */
+               cstate->off_linktype.constant_part = 0;
+               cstate->off_linkpl.constant_part = 20;
+               cstate->off_nl = 0;
+               cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
+               break;
+
        case DLT_LTALK:
                /*
                 * LocalTalk does have a 1-byte type field in the LLAP header,
@@ -1394,11 +1917,11 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
                break;
 
-                /*
-                 * the only BPF-interesting FRF.16 frames are non-control frames;
-                 * Frame Relay has a variable length link-layer
-                 * so lets start with offset 4 for now and increments later on (FIXME);
-                 */
+               /*
+                * the only BPF-interesting FRF.16 frames are non-control frames;
+                * Frame Relay has a variable length link-layer
+                * so lets start with offset 4 for now and increments later on (FIXME);
+                */
        case DLT_MFR:
                cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = 0;
@@ -1420,26 +1943,25 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_nl_nosnap = 0;      /* XXX - what does it do with 802.3 packets? */
                break;
 
-#ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                cstate->off_linktype.constant_part = 0;
-               cstate->off_linkpl.constant_part = PFLOG_HDRLEN;
+               cstate->off_linkpl.constant_part = 0;   /* link-layer header is variable-length */
+               cstate->off_linkpl.is_variable = 1;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
                break;
-#endif
 
-        case DLT_JUNIPER_MFR:
-        case DLT_JUNIPER_MLFR:
-        case DLT_JUNIPER_MLPPP:
-        case DLT_JUNIPER_PPP:
-        case DLT_JUNIPER_CHDLC:
-        case DLT_JUNIPER_FRELAY:
+       case DLT_JUNIPER_MFR:
+       case DLT_JUNIPER_MLFR:
+       case DLT_JUNIPER_MLPPP:
+       case DLT_JUNIPER_PPP:
+       case DLT_JUNIPER_CHDLC:
+       case DLT_JUNIPER_FRELAY:
                cstate->off_linktype.constant_part = 4;
                cstate->off_linkpl.constant_part = 4;
                cstate->off_nl = 0;
-               cstate->off_nl_nosnap = -1;     /* no 802.2 LLC */
-                break;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+               break;
 
        case DLT_JUNIPER_ATM1:
                cstate->off_linktype.constant_part = 4;         /* in reality variable between 4-8 */
@@ -1458,7 +1980,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                /* frames captured on a Juniper PPPoE service PIC
                 * contain raw ethernet frames */
        case DLT_JUNIPER_PPPOE:
-        case DLT_JUNIPER_ETHER:
+       case DLT_JUNIPER_ETHER:
                cstate->off_linkpl.constant_part = 14;
                cstate->off_linktype.constant_part = 16;
                cstate->off_nl = 18;            /* Ethernet II */
@@ -1469,63 +1991,63 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_linktype.constant_part = 4;
                cstate->off_linkpl.constant_part = 6;
                cstate->off_nl = 0;
-               cstate->off_nl_nosnap = -1;     /* no 802.2 LLC */
+               cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
                break;
 
        case DLT_JUNIPER_GGSN:
                cstate->off_linktype.constant_part = 6;
                cstate->off_linkpl.constant_part = 12;
                cstate->off_nl = 0;
-               cstate->off_nl_nosnap = -1;     /* no 802.2 LLC */
+               cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
                break;
 
        case DLT_JUNIPER_ES:
                cstate->off_linktype.constant_part = 6;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;      /* not really a network layer but raw IP addresses */
-               cstate->off_nl = -1;            /* not really a network layer but raw IP addresses */
-               cstate->off_nl_nosnap = -1;     /* no 802.2 LLC */
+               cstate->off_nl = OFFSET_NOT_SET;        /* not really a network layer but raw IP addresses */
+               cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
                break;
 
        case DLT_JUNIPER_MONITOR:
                cstate->off_linktype.constant_part = 12;
                cstate->off_linkpl.constant_part = 12;
-               cstate->off_nl = 0;             /* raw IP/IP6 header */
-               cstate->off_nl_nosnap = -1;     /* no 802.2 LLC */
+               cstate->off_nl = 0;                     /* raw IP/IP6 header */
+               cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
                break;
 
        case DLT_BACNET_MS_TP:
                cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_JUNIPER_SERVICES:
                cstate->off_linktype.constant_part = 12;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;      /* L3 proto location dep. on cookie type */
-               cstate->off_nl = -1;            /* L3 proto location dep. on cookie type */
-               cstate->off_nl_nosnap = -1;     /* no 802.2 LLC */
+               cstate->off_nl = OFFSET_NOT_SET;        /* L3 proto location dep. on cookie type */
+               cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
                break;
 
        case DLT_JUNIPER_VP:
                cstate->off_linktype.constant_part = 18;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_JUNIPER_ST:
                cstate->off_linktype.constant_part = 18;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_JUNIPER_ISM:
                cstate->off_linktype.constant_part = 8;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_JUNIPER_VS:
@@ -1534,8 +2056,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
        case DLT_JUNIPER_ATM_CEMIC:
                cstate->off_linktype.constant_part = 8;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_MTP2:
@@ -1547,8 +2069,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_sls = 7;
                cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_MTP2_WITH_PHDR:
@@ -1560,8 +2082,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_sls = 11;
                cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_ERF:
@@ -1573,8 +2095,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_sls = 27;
                cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl = OFFSET_NOT_SET;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_PFSYNC:
@@ -1590,15 +2112,15 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                 */
                cstate->off_linktype.constant_part = OFFSET_NOT_SET;    /* variable, min 15, max 71 steps of 7 */
                cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-               cstate->off_nl = -1;            /* variable, min 16, max 71 steps of 7 */
-               cstate->off_nl_nosnap = -1;     /* no 802.2 LLC */
+               cstate->off_nl = OFFSET_NOT_SET;        /* variable, min 16, max 71 steps of 7 */
+               cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
                break;
 
        case DLT_IPNET:
                cstate->off_linktype.constant_part = 1;
                cstate->off_linkpl.constant_part = 24;  /* ipnet header length */
                cstate->off_nl = 0;
-               cstate->off_nl_nosnap = -1;
+               cstate->off_nl_nosnap = OFFSET_NOT_SET;
                break;
 
        case DLT_NETANALYZER:
@@ -1622,19 +2144,22 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                 * For values in the range in which we've assigned new
                 * DLT_ values, only raw "link[N:M]" filtering is supported.
                 */
-               if (cstate->linktype >= DLT_MATCHING_MIN &&
-                   cstate->linktype <= DLT_MATCHING_MAX) {
+               if (cstate->linktype >= DLT_HIGH_MATCHING_MIN &&
+                   cstate->linktype <= DLT_HIGH_MATCHING_MAX) {
                        cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                        cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
-                       cstate->off_nl = -1;
-                       cstate->off_nl_nosnap = -1;
+                       cstate->off_nl = OFFSET_NOT_SET;
+                       cstate->off_nl_nosnap = OFFSET_NOT_SET;
                } else {
-                       bpf_error(cstate, "unknown data link type %d", cstate->linktype);
+                       bpf_set_error(cstate, "unknown data link type %d (min %d, max %d)",
+                           cstate->linktype, DLT_HIGH_MATCHING_MIN, DLT_HIGH_MATCHING_MAX);
+                       return (-1);
                }
                break;
        }
 
        cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr;
+       return (0);
 }
 
 /*
@@ -1686,11 +2211,24 @@ gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
 {
        struct slist *s, *s2;
 
+       /*
+        * Squelch warnings from compilers that *don't* assume that
+        * offrel always has a valid enum value and therefore don't
+        * assume that we'll always go through one of the case arms.
+        *
+        * If we have a default case, compilers that *do* assume that
+        * will then complain about the default case code being
+        * unreachable.
+        *
+        * Damned if you do, damned if you don't.
+        */
+       s = NULL;
+
        switch (offrel) {
 
        case OR_PACKET:
-                s = new_stmt(cstate, BPF_LD|BPF_ABS|size);
-                s->s.k = offset;
+               s = new_stmt(cstate, BPF_LD|BPF_ABS|size);
+               s->s.k = offset;
                break;
 
        case OR_LINKHDR:
@@ -1733,7 +2271,7 @@ gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
                /*
                 * Load the item at {offset of the link-layer payload} +
                 * {offset, relative to the start of the link-layer
-                * paylod, of the IPv4 header} + {length of the IPv4 header} +
+                * payload, of the IPv4 header} + {length of the IPv4 header} +
                 * {specified offset}.
                 *
                 * If the offset of the link-layer payload is variable,
@@ -1749,10 +2287,6 @@ gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
        case OR_TRAN_IPV6:
                s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size);
                break;
-
-       default:
-               abort();
-               return NULL;
        }
        return s;
 }
@@ -1800,7 +2334,7 @@ gen_loadx_iphdrlen(compiler_state_t *cstate)
        } else {
                /*
                 * The offset of the link-layer payload is a constant,
-                * so no code was generated to load the (non-existent)
+                * so no code was generated to load the (nonexistent)
                 * variable part of that offset.
                 *
                 * This means we can use the 4*([k]&0xf) addressing
@@ -1816,18 +2350,15 @@ gen_loadx_iphdrlen(compiler_state_t *cstate)
        return s;
 }
 
+
 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 *
@@ -1842,14 +2373,6 @@ gen_false(compiler_state_t *cstate)
        return gen_uncond(cstate, 0);
 }
 
-/*
- * Byte-swap a 32-bit number.
- * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on
- * big-endian platforms.)
- */
-#define        SWAPLONG(y) \
-((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
-
 /*
  * Generate code to match a particular packet type.
  *
@@ -1860,11 +2383,11 @@ gen_false(compiler_state_t *cstate)
  * the appropriate test.
  */
 static struct block *
-gen_ether_linktype(compiler_state_t *cstate, int proto)
+gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
        struct block *b0, *b1;
 
-       switch (proto) {
+       switch (ll_proto) {
 
        case LLCSAP_ISONS:
        case LLCSAP_IP:
@@ -1881,10 +2404,8 @@ gen_ether_linktype(compiler_state_t *cstate, int 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);
-               b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)
-                            ((proto << 8) | proto));
+               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;
 
@@ -1921,8 +2442,8 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
                 * This generates code to check both for the
                 * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
                 */
-               b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
-               b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF);
+               b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+               b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
                gen_or(b0, b1);
 
                /*
@@ -1936,8 +2457,7 @@ gen_ether_linktype(compiler_state_t *cstate, int 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
@@ -1952,7 +2472,7 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
                 * do that before checking for the other frame
                 * types.
                 */
-               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
+               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
                gen_or(b0, b1);
                return b1;
 
@@ -1965,11 +2485,10 @@ gen_ether_linktype(compiler_state_t *cstate, int 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
@@ -1982,9 +2501,9 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
                 * 0x000000 (encapsulated Ethernet) and a protocol
                 * type of ETHERTYPE_AARP (Appletalk ARP).
                 */
-               if (proto == ETHERTYPE_ATALK)
+               if (ll_proto == ETHERTYPE_ATALK)
                        b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
-               else    /* proto == ETHERTYPE_AARP */
+               else    /* ll_proto == ETHERTYPE_AARP */
                        b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
                gen_and(b0, b1);
 
@@ -1993,13 +2512,14 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
                 * phase 1?); we just check for the Ethernet
                 * protocol type.
                 */
-               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 
                gen_or(b0, b1);
                return b1;
 
        default:
-               if (proto <= ETHERMTU) {
+               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.
@@ -2008,29 +2528,28 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
                         * a length field, <= ETHERMTU) and
                         * then check the DSAP.
                         */
-                       b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
-                       gen_not(b0);
-                       b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, (bpf_int32)proto);
+                       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
                         * the frame is an 802.2 frame, the length
                         * field will be <= ETHERMTU, and, as
-                        * "proto" is > ETHERMTU, this test
+                        * "ll_proto" is > ETHERMTU, this test
                         * will fail and the frame won't match,
                         * which is what we want).
                         */
-                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
-                           (bpf_int32)proto);
+                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
                }
        }
 }
 
 static struct block *
-gen_loopback_linktype(compiler_state_t *cstate, int proto)
+gen_loopback_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
        /*
         * For DLT_NULL, the link-layer header is a 32-bit word
@@ -2058,10 +2577,10 @@ gen_loopback_linktype(compiler_state_t *cstate, int proto)
                 * code to compare against the result.
                 */
                if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
-                       proto = SWAPLONG(proto);
-               proto = htonl(proto);
+                       ll_proto = SWAPLONG(ll_proto);
+               ll_proto = htonl(ll_proto);
        }
-       return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
+       return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, ll_proto));
 }
 
 /*
@@ -2069,18 +2588,17 @@ gen_loopback_linktype(compiler_state_t *cstate, int proto)
  * or IPv6 then we have an error.
  */
 static struct block *
-gen_ipnet_linktype(compiler_state_t *cstate, int proto)
+gen_ipnet_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
-       switch (proto) {
+       switch (ll_proto) {
 
        case ETHERTYPE_IP:
-               return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET);
-               /* NOTREACHED */
+               return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET);
+               /*NOTREACHED*/
 
        case ETHERTYPE_IPV6:
-               return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                   (bpf_int32)IPH_AF_INET6);
-               /* NOTREACHED */
+               return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET6);
+               /*NOTREACHED*/
 
        default:
                break;
@@ -2092,17 +2610,17 @@ gen_ipnet_linktype(compiler_state_t *cstate, int proto)
 /*
  * Generate code to match a particular packet type.
  *
- * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * "ll_proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
  * value, if <= ETHERMTU.  We use that to determine whether to
  * match the type field or to check the type field for the special
  * LINUX_SLL_P_802_2 value and then do the appropriate test.
  */
 static struct block *
-gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
+gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
        struct block *b0, *b1;
 
-       switch (proto) {
+       switch (ll_proto) {
 
        case LLCSAP_ISONS:
        case LLCSAP_IP:
@@ -2120,8 +2638,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
                 * (i.e., other SAP values)?
                 */
                b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
-               b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)
-                            ((proto << 8) | proto));
+               b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
                gen_and(b0, b1);
                return b1;
 
@@ -2151,7 +2668,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
                 * then put a check for LINUX_SLL_P_802_2 frames
                 * before it.
                 */
-               b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
+               b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
                b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX);
                gen_or(b0, b1);
                b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
@@ -2169,7 +2686,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
                 * do that before checking for the other frame
                 * types.
                 */
-               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
+               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
                gen_or(b0, b1);
                return b1;
 
@@ -2198,9 +2715,9 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
                 * 0x000000 (encapsulated Ethernet) and a protocol
                 * type of ETHERTYPE_AARP (Appletalk ARP).
                 */
-               if (proto == ETHERTYPE_ATALK)
+               if (ll_proto == ETHERTYPE_ATALK)
                        b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
-               else    /* proto == ETHERTYPE_AARP */
+               else    /* ll_proto == ETHERTYPE_AARP */
                        b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
                gen_and(b0, b1);
 
@@ -2209,13 +2726,14 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
                 * phase 1?); we just check for the Ethernet
                 * protocol type.
                 */
-               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+               b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 
                gen_or(b0, b1);
                return b1;
 
        default:
-               if (proto <= ETHERMTU) {
+               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.
@@ -2225,40 +2743,94 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
                         */
                        b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
                        b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B,
-                            (bpf_int32)proto);
+                            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
                         * the frame is an 802.2 frame, the length
                         * field will be <= ETHERMTU, and, as
-                        * "proto" is > ETHERMTU, this test
+                        * "ll_proto" is > ETHERMTU, this test
                         * will fail and the frame won't match,
                         * which is what we want).
                         */
-                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
                }
        }
 }
 
+/*
+ * Load a value relative to the beginning of the link-layer header after the
+ * pflog header.
+ */
 static struct slist *
-gen_load_prism_llprefixlen(compiler_state_t *cstate)
+gen_load_pflog_llprefixlen(compiler_state_t *cstate)
 {
        struct slist *s1, *s2;
-       struct slist *sjeq_avs_cookie;
-       struct slist *sjcommon;
 
        /*
-        * This code is not compatible with the optimizer, as
-        * we are generating jmp instructions within a normal
-        * slist of instructions
-        */
-       cstate->no_optimize = 1;
-
-       /*
-        * Generate code to load the length of the radio header into
+        * Generate code to load the length of the pflog header into
+        * the register assigned to hold that length, if one has been
+        * assigned.  (If one hasn't been assigned, no code we've
+        * generated uses that prefix, so we don't need to generate any
+        * code to load it.)
+        */
+       if (cstate->off_linkpl.reg != -1) {
+               /*
+                * The length is in the first byte of the header.
+                */
+               s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+               s1->s.k = 0;
+
+               /*
+                * Round it up to a multiple of 4.
+                * Add 3, and clear the lower 2 bits.
+                */
+               s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+               s2->s.k = 3;
+               sappend(s1, s2);
+               s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+               s2->s.k = 0xfffffffc;
+               sappend(s1, s2);
+
+               /*
+                * Now allocate a register to hold that value and store
+                * it.
+                */
+               s2 = new_stmt(cstate, BPF_ST);
+               s2->s.k = cstate->off_linkpl.reg;
+               sappend(s1, s2);
+
+               /*
+                * Now move it into the X register.
+                */
+               s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+               sappend(s1, s2);
+
+               return (s1);
+       } else
+               return (NULL);
+}
+
+static struct slist *
+gen_load_prism_llprefixlen(compiler_state_t *cstate)
+{
+       struct slist *s1, *s2;
+       struct slist *sjeq_avs_cookie;
+       struct slist *sjcommon;
+
+       /*
+        * This code is not compatible with the optimizer, as
+        * we are generating jmp instructions within a normal
+        * slist of instructions
+        */
+       cstate->no_optimize = 1;
+
+       /*
+        * Generate code to load the length of the radio header into
         * the register assigned to hold that length, if one has been
         * assigned.  (If one hasn't been assigned, no code we've
         * generated uses that prefix, so we don't need to generate any
@@ -2607,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);
 
        /*
@@ -2615,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;
 
@@ -2626,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);
 
        /*
@@ -2752,7 +3324,7 @@ gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct sli
                s2->s.k = 3;
                sappend(s, s2);
                s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM);
-               s2->s.k = ~3;
+               s2->s.k = (bpf_u_int32)~3;
                sappend(s, s2);
                s2 = new_stmt(cstate, BPF_ST);
                s2->s.k = cstate->off_linkpl.reg;
@@ -2830,10 +3402,14 @@ insert_compute_vloffsets(compiler_state_t *cstate, struct block *b)
        case DLT_PPI:
                s = gen_load_802_11_header_len(cstate, s, b->stmts);
                break;
+
+       case DLT_PFLOG:
+               s = gen_load_pflog_llprefixlen(cstate);
+               break;
        }
 
        /*
-        * If there there is no initialization yet and we need variable
+        * If there is no initialization yet and we need variable
         * length offsets for VLAN, initialize them to zero
         */
        if (s == NULL && cstate->is_vlan_vloffset) {
@@ -2866,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:
  *
@@ -2939,35 +3489,28 @@ gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off)
 /*
  * Map an Ethernet type to the equivalent PPP type.
  */
-static int
-ethertype_to_ppptype(proto)
-       int proto;
+static uint16_t
+ethertype_to_ppptype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
-       switch (proto) {
+       switch (ll_proto) {
 
        case ETHERTYPE_IP:
-               proto = PPP_IP;
-               break;
+               return PPP_IP;
 
        case ETHERTYPE_IPV6:
-               proto = PPP_IPV6;
-               break;
+               return PPP_IPV6;
 
        case ETHERTYPE_DN:
-               proto = PPP_DECNET;
-               break;
+               return PPP_DECNET;
 
        case ETHERTYPE_ATALK:
-               proto = PPP_APPLE;
-               break;
+               return PPP_APPLE;
 
        case ETHERTYPE_NS:
-               proto = PPP_NS;
-               break;
+               return PPP_NS;
 
        case LLCSAP_ISONS:
-               proto = PPP_OSI;
-               break;
+               return PPP_OSI;
 
        case LLCSAP_8021D:
                /*
@@ -2975,14 +3518,13 @@ ethertype_to_ppptype(proto)
                 * over PPP are Spanning Tree Protocol
                 * Bridging PDUs.
                 */
-               proto = PPP_BRPDU;
-               break;
+               return PPP_BRPDU;
 
        case LLCSAP_IPX:
-               proto = PPP_IPX;
-               break;
+               return PPP_IPX;
        }
-       return (proto);
+       assert_maxval(cstate, "PPP protocol", ll_proto, UINT16_MAX);
+       return (uint16_t)ll_proto;
 }
 
 /*
@@ -2994,10 +3536,8 @@ ethertype_to_ppptype(proto)
 static struct block *
 gen_prevlinkhdr_check(compiler_state_t *cstate)
 {
-       struct block *b0;
-
-       if (cstate->is_geneve)
-               return gen_geneve_ll_check(cstate);
+       if (cstate->is_encap)
+               return gen_encap_ll_check(cstate);
 
        switch (cstate->prevlinktype) {
 
@@ -3009,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:
                /*
@@ -3028,7 +3566,7 @@ gen_prevlinkhdr_check(compiler_state_t *cstate)
  */
 #define BSD_AFNUM_INET6_BSD    24      /* NetBSD, OpenBSD, BSD/OS, Npcap */
 #define BSD_AFNUM_INET6_FREEBSD        28      /* FreeBSD */
-#define BSD_AFNUM_INET6_DARWIN 30      /* OS X, iOS, other Darwin-based OSes */
+#define BSD_AFNUM_INET6_DARWIN 30      /* macOS, iOS, other Darwin-based OSes */
 
 /*
  * Generate code to match a particular packet type by matching the
@@ -3038,29 +3576,13 @@ gen_prevlinkhdr_check(compiler_state_t *cstate)
  * value, if <= ETHERMTU.
  */
 static struct block *
-gen_linktype(compiler_state_t *cstate, int proto)
+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) {
-               switch (proto) {
-               case ETHERTYPE_IP:
-               case PPP_IP:
-                       /* FIXME add other L3 proto IDs */
-                       return gen_mpls_linktype(cstate, Q_IP);
-
-               case ETHERTYPE_IPV6:
-               case PPP_IPV6:
-                       /* FIXME add other L3 proto IDs */
-                       return gen_mpls_linktype(cstate, Q_IPV6);
-
-               default:
-                       bpf_error(cstate, "unsupported protocol over mpls");
-                       /* NOTREACHED */
-               }
-       }
+       if (cstate->label_stack_depth > 0)
+               return gen_mpls_linktype(cstate, ll_proto);
 
        switch (cstate->linktype) {
 
@@ -3068,32 +3590,31 @@ gen_linktype(compiler_state_t *cstate, int proto)
        case DLT_NETANALYZER:
        case DLT_NETANALYZER_TRANSPARENT:
                /* Geneve has an EtherType regardless of whether there is an
-                * L2 header. */
-               if (!cstate->is_geneve)
+                * L2 header. VXLAN always has an EtherType. */
+               if (!cstate->is_encap)
                        b0 = gen_prevlinkhdr_check(cstate);
                else
                        b0 = NULL;
 
-               b1 = gen_ether_linktype(cstate, proto);
+               b1 = gen_ether_linktype(cstate, ll_proto);
                if (b0 != NULL)
                        gen_and(b0, b1);
                return b1;
                /*NOTREACHED*/
-               break;
 
        case DLT_C_HDLC:
-               switch (proto) {
+       case DLT_HDLC:
+               assert_maxval(cstate, "HDLC protocol", ll_proto, UINT16_MAX);
+               switch (ll_proto) {
 
                case LLCSAP_ISONS:
-                       proto = (proto << 8 | LLCSAP_ISONS);
+                       ll_proto = (ll_proto << 8 | LLCSAP_ISONS);
                        /* fall through */
 
                default:
-                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
                        /*NOTREACHED*/
-                       break;
                }
-               break;
 
        case DLT_IEEE802_11:
        case DLT_PRISM_HEADER:
@@ -3103,39 +3624,37 @@ gen_linktype(compiler_state_t *cstate, int 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.
                 */
-               b1 = gen_llc_linktype(cstate, proto);
+               b1 = gen_llc_linktype(cstate, ll_proto);
                gen_and(b0, b1);
                return b1;
                /*NOTREACHED*/
-               break;
 
        case DLT_FDDI:
                /*
                 * XXX - check for LLC frames.
                 */
-               return gen_llc_linktype(cstate, proto);
+               return gen_llc_linktype(cstate, ll_proto);
                /*NOTREACHED*/
-               break;
 
        case DLT_IEEE802:
                /*
                 * XXX - check for LLC PDUs, as per IEEE 802.5.
                 */
-               return gen_llc_linktype(cstate, proto);
+               return gen_llc_linktype(cstate, ll_proto);
                /*NOTREACHED*/
-               break;
 
        case DLT_ATM_RFC1483:
        case DLT_ATM_CLIP:
        case DLT_IP_OVER_FC:
-               return gen_llc_linktype(cstate, proto);
+               return gen_llc_linktype(cstate, ll_proto);
                /*NOTREACHED*/
-               break;
 
        case DLT_SUNATM:
                /*
@@ -3145,17 +3664,15 @@ gen_linktype(compiler_state_t *cstate, int proto)
                 *
                 * Check for LLC encapsulation and then check the protocol.
                 */
-               b0 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
-               b1 = gen_llc_linktype(cstate, proto);
+               b0 = gen_atm_prototype(cstate, PT_LLC);
+               b1 = gen_llc_linktype(cstate, ll_proto);
                gen_and(b0, b1);
                return b1;
                /*NOTREACHED*/
-               break;
 
        case DLT_LINUX_SLL:
-               return gen_linux_sll_linktype(cstate, proto);
+               return gen_linux_sll_linktype(cstate, ll_proto);
                /*NOTREACHED*/
-               break;
 
        case DLT_SLIP:
        case DLT_SLIP_BSDOS:
@@ -3167,7 +3684,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
                 * XXX - for IPv4, check for a version number of 4, and,
                 * for IPv6, check for a version number of 6?
                 */
-               switch (proto) {
+               switch (ll_proto) {
 
                case ETHERTYPE_IP:
                        /* Check for a version number of 4. */
@@ -3181,31 +3698,28 @@ gen_linktype(compiler_state_t *cstate, int proto)
                        return gen_false(cstate);       /* always false */
                }
                /*NOTREACHED*/
-               break;
 
        case DLT_IPV4:
                /*
                 * Raw IPv4, so no type field.
                 */
-               if (proto == ETHERTYPE_IP)
+               if (ll_proto == ETHERTYPE_IP)
                        return gen_true(cstate);        /* always true */
 
                /* Checking for something other than IPv4; always false */
                return gen_false(cstate);
                /*NOTREACHED*/
-               break;
 
        case DLT_IPV6:
                /*
                 * Raw IPv6, so no type field.
                 */
-               if (proto == ETHERTYPE_IPV6)
+               if (ll_proto == ETHERTYPE_IPV6)
                        return gen_true(cstate);        /* always true */
 
                /* Checking for something other than IPv6; always false */
                return gen_false(cstate);
                /*NOTREACHED*/
-               break;
 
        case DLT_PPP:
        case DLT_PPP_PPPD:
@@ -3215,17 +3729,16 @@ gen_linktype(compiler_state_t *cstate, int proto)
                 * We use Ethernet protocol types inside libpcap;
                 * map them to the corresponding PPP protocol types.
                 */
-               proto = ethertype_to_ppptype(proto);
-               return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+               return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
+                   ethertype_to_ppptype(cstate, ll_proto));
                /*NOTREACHED*/
-               break;
 
        case DLT_PPP_BSDOS:
                /*
                 * We use Ethernet protocol types inside libpcap;
                 * map them to the corresponding PPP protocol types.
                 */
-               switch (proto) {
+               switch (ll_proto) {
 
                case ETHERTYPE_IP:
                        /*
@@ -3240,17 +3753,15 @@ gen_linktype(compiler_state_t *cstate, int proto)
                        return b0;
 
                default:
-                       proto = ethertype_to_ppptype(proto);
                        return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
-                               (bpf_int32)proto);
+                           ethertype_to_ppptype(cstate, ll_proto));
                }
                /*NOTREACHED*/
-               break;
 
        case DLT_NULL:
        case DLT_LOOP:
        case DLT_ENC:
-               switch (proto) {
+               switch (ll_proto) {
 
                case ETHERTYPE_IP:
                        return (gen_loopback_linktype(cstate, AF_INET));
@@ -3325,23 +3836,20 @@ gen_linktype(compiler_state_t *cstate, int proto)
                        return gen_false(cstate);
                }
 
-#ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                /*
                 * af field is host byte order in contrast to the rest of
                 * the packet.
                 */
-               if (proto == ETHERTYPE_IP)
+               if (ll_proto == ETHERTYPE_IP)
                        return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
-                           BPF_B, (bpf_int32)AF_INET));
-               else if (proto == ETHERTYPE_IPV6)
+                           BPF_B, AF_INET));
+               else if (ll_proto == ETHERTYPE_IPV6)
                        return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
-                           BPF_B, (bpf_int32)AF_INET6));
+                           BPF_B, AF_INET6));
                else
                        return gen_false(cstate);
                /*NOTREACHED*/
-               break;
-#endif /* HAVE_NET_PFVAR_H */
 
        case DLT_ARCNET:
        case DLT_ARCNET_LINUX:
@@ -3349,58 +3857,56 @@ gen_linktype(compiler_state_t *cstate, int proto)
                 * XXX should we check for first fragment if the protocol
                 * uses PHDS?
                 */
-               switch (proto) {
+               switch (ll_proto) {
 
                default:
                        return gen_false(cstate);
 
                case ETHERTYPE_IPV6:
                        return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                               (bpf_int32)ARCTYPE_INET6));
+                               ARCTYPE_INET6));
 
                case ETHERTYPE_IP:
                        b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                                    (bpf_int32)ARCTYPE_IP);
+                           ARCTYPE_IP);
                        b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                                    (bpf_int32)ARCTYPE_IP_OLD);
+                           ARCTYPE_IP_OLD);
                        gen_or(b0, b1);
                        return (b1);
 
                case ETHERTYPE_ARP:
                        b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                                    (bpf_int32)ARCTYPE_ARP);
+                           ARCTYPE_ARP);
                        b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                                    (bpf_int32)ARCTYPE_ARP_OLD);
+                           ARCTYPE_ARP_OLD);
                        gen_or(b0, b1);
                        return (b1);
 
                case ETHERTYPE_REVARP:
                        return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                                       (bpf_int32)ARCTYPE_REVARP));
+                           ARCTYPE_REVARP));
 
                case ETHERTYPE_ATALK:
                        return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-                                       (bpf_int32)ARCTYPE_ATALK));
+                           ARCTYPE_ATALK));
                }
                /*NOTREACHED*/
-               break;
 
        case DLT_LTALK:
-               switch (proto) {
+               switch (ll_proto) {
                case ETHERTYPE_ATALK:
                        return gen_true(cstate);
                default:
                        return gen_false(cstate);
                }
                /*NOTREACHED*/
-               break;
 
        case DLT_FRELAY:
                /*
                 * XXX - assumes a 2-byte Frame Relay header with
                 * DLCI and flags.  What if the address is longer?
                 */
-               switch (proto) {
+               switch (ll_proto) {
 
                case ETHERTYPE_IP:
                        /*
@@ -3437,32 +3943,31 @@ gen_linktype(compiler_state_t *cstate, int proto)
                        return gen_false(cstate);
                }
                /*NOTREACHED*/
-               break;
 
        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:
-        case DLT_JUNIPER_MLPPP:
+       case DLT_JUNIPER_MFR:
+       case DLT_JUNIPER_MLFR:
+       case DLT_JUNIPER_MLPPP:
        case DLT_JUNIPER_ATM1:
        case DLT_JUNIPER_ATM2:
        case DLT_JUNIPER_PPPOE:
        case DLT_JUNIPER_PPPOE_ATM:
-        case DLT_JUNIPER_GGSN:
-        case DLT_JUNIPER_ES:
-        case DLT_JUNIPER_MONITOR:
-        case DLT_JUNIPER_SERVICES:
-        case DLT_JUNIPER_ETHER:
-        case DLT_JUNIPER_PPP:
-        case DLT_JUNIPER_FRELAY:
-        case DLT_JUNIPER_CHDLC:
-        case DLT_JUNIPER_VP:
-        case DLT_JUNIPER_ST:
-        case DLT_JUNIPER_ISM:
-        case DLT_JUNIPER_VS:
-        case DLT_JUNIPER_SRX_E2E:
-        case DLT_JUNIPER_FIBRECHANNEL:
+       case DLT_JUNIPER_GGSN:
+       case DLT_JUNIPER_ES:
+       case DLT_JUNIPER_MONITOR:
+       case DLT_JUNIPER_SERVICES:
+       case DLT_JUNIPER_ETHER:
+       case DLT_JUNIPER_PPP:
+       case DLT_JUNIPER_FRELAY:
+       case DLT_JUNIPER_CHDLC:
+       case DLT_JUNIPER_VP:
+       case DLT_JUNIPER_ST:
+       case DLT_JUNIPER_ISM:
+       case DLT_JUNIPER_VS:
+       case DLT_JUNIPER_SRX_E2E:
+       case DLT_JUNIPER_FIBRECHANNEL:
        case DLT_JUNIPER_ATM_CEMIC:
 
                /* just lets verify the magic number for now -
@@ -3478,68 +3983,40 @@ gen_linktype(compiler_state_t *cstate, int proto)
                return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000);
 
        case DLT_IPNET:
-               return gen_ipnet_linktype(cstate, 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:
-               bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented");
-
+       case DLT_IEEE802_15_4_TAP:
        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:
-               bpf_error(cstate, "IPMB link-layer type filtering not implemented");
-
+       case DLT_IPMB_KONTRON:
+       case DLT_I2C_LINUX:
        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:
                /*
@@ -3554,22 +4031,13 @@ gen_linktype(compiler_state_t *cstate, int proto)
                         * it's not, it needs to be handled specially
                         * above.)
                         */
-                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
-               } else {
-                       /*
-                        * No; report an error.
-                        */
-                       description = pcap_datalink_val_to_description(cstate->linktype);
-                       if (description != NULL) {
-                               bpf_error(cstate, "%s link-layer type filtering not implemented",
-                                   description);
-                       } else {
-                               bpf_error(cstate, "DLT %u link-layer type filtering not implemented",
-                                   cstate->linktype);
-                       }
+                       assert_maxval(cstate, "EtherType", ll_proto, UINT16_MAX);
+                       return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+                       /*NOTREACHED */
                }
-               break;
        }
+       bpf_error(cstate, "link-layer type filtering not implemented for %s",
+           pcap_datalink_val_to_description_or_dlt(cstate->linktype));
 }
 
 /*
@@ -3584,22 +4052,22 @@ gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype)
 {
        u_char snapblock[8];
 
-       snapblock[0] = LLCSAP_SNAP;     /* DSAP = SNAP */
-       snapblock[1] = LLCSAP_SNAP;     /* SSAP = SNAP */
-       snapblock[2] = 0x03;            /* control = UI */
-       snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */
-       snapblock[4] = (orgcode >> 8);  /* middle 8 bits of organization code */
-       snapblock[5] = (orgcode >> 0);  /* lower 8 bits of organization code */
-       snapblock[6] = (ptype >> 8);    /* upper 8 bits of protocol type */
-       snapblock[7] = (ptype >> 0);    /* lower 8 bits of protocol type */
+       snapblock[0] = LLCSAP_SNAP;             /* DSAP = SNAP */
+       snapblock[1] = LLCSAP_SNAP;             /* SSAP = SNAP */
+       snapblock[2] = 0x03;                    /* control = UI */
+       snapblock[3] = (u_char)(orgcode >> 16); /* upper 8 bits of organization code */
+       snapblock[4] = (u_char)(orgcode >> 8);  /* middle 8 bits of organization code */
+       snapblock[5] = (u_char)(orgcode >> 0);  /* lower 8 bits of organization code */
+       snapblock[6] = (u_char)(ptype >> 8);    /* upper 8 bits of protocol type */
+       snapblock[7] = (u_char)(ptype >> 0);    /* lower 8 bits of protocol type */
        return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock);
 }
 
 /*
  * Generate code to match frames with an LLC header.
  */
-struct block *
-gen_llc(compiler_state_t *cstate)
+static struct block *
+gen_llc_internal(compiler_state_t *cstate)
 {
        struct block *b0, *b1;
 
@@ -3607,18 +4075,16 @@ gen_llc(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, (bpf_int32)0xFFFF);
-               gen_not(b1);
+               b1 = gen_cmp_ne(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
                gen_and(b0, b1);
                return b1;
 
@@ -3626,8 +4092,7 @@ gen_llc(compiler_state_t *cstate)
                /*
                 * We check for LLC traffic.
                 */
-               b0 = gen_atmtype_abbrev(cstate, A_LLC);
-               return b0;
+               return gen_atmtype_llc(cstate);
 
        case DLT_IEEE802:       /* Token Ring */
                /*
@@ -3660,35 +4125,54 @@ gen_llc(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 linktype %d", cstate->linktype);
-               /* NOTREACHED */
+               fail_kw_on_dlt(cstate, "llc");
+               /*NOTREACHED*/
        }
 }
 
+struct block *
+gen_llc(compiler_state_t *cstate)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       return gen_llc_internal(cstate);
+}
+
 struct block *
 gen_llc_i(compiler_state_t *cstate)
 {
        struct block *b0, *b1;
        struct slist *s;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Check whether this is an LLC frame.
         */
-       b0 = gen_llc(cstate);
+       b0 = gen_llc_internal(cstate);
 
        /*
         * Load the control byte and test the low-order bit; it must
         * 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;
 }
@@ -3698,10 +4182,17 @@ gen_llc_s(compiler_state_t *cstate)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Check whether this is an LLC frame.
         */
-       b0 = gen_llc(cstate);
+       b0 = gen_llc_internal(cstate);
 
        /*
         * Now compare the low-order 2 bit of the control byte against
@@ -3717,10 +4208,17 @@ gen_llc_u(compiler_state_t *cstate)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Check whether this is an LLC frame.
         */
-       b0 = gen_llc(cstate);
+       b0 = gen_llc_internal(cstate);
 
        /*
         * Now compare the low-order 2 bit of the control byte against
@@ -3736,10 +4234,17 @@ gen_llc_s_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Check whether this is an LLC frame.
         */
-       b0 = gen_llc(cstate);
+       b0 = gen_llc_internal(cstate);
 
        /*
         * Now check for an S frame with the appropriate type.
@@ -3754,10 +4259,17 @@ gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Check whether this is an LLC frame.
         */
-       b0 = gen_llc(cstate);
+       b0 = gen_llc_internal(cstate);
 
        /*
         * Now check for a U frame with the appropriate type.
@@ -3780,12 +4292,12 @@ gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
  * protocol ID in a SNAP header.
  */
 static struct block *
-gen_llc_linktype(compiler_state_t *cstate, int proto)
+gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
        /*
         * XXX - handle token-ring variable-length header.
         */
-       switch (proto) {
+       switch (ll_proto) {
 
        case LLCSAP_IP:
        case LLCSAP_ISONS:
@@ -3796,15 +4308,14 @@ gen_llc_linktype(compiler_state_t *cstate, int proto)
                 * DSAP, as we do for other SAP values?
                 */
                return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32)
-                            ((proto << 8) | proto));
+                            ((ll_proto << 8) | ll_proto));
 
        case LLCSAP_IPX:
                /*
                 * XXX - are there ever SNAP frames for IPX on
                 * non-Ethernet 802.x networks?
                 */
-               return gen_cmp(cstate, OR_LLC, 0, BPF_B,
-                   (bpf_int32)LLCSAP_IPX);
+               return gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
 
        case ETHERTYPE_ATALK:
                /*
@@ -3823,13 +4334,15 @@ gen_llc_linktype(compiler_state_t *cstate, int proto)
                 * XXX - we don't have to check for IPX 802.3
                 * here, but should we check for the IPX Ethertype?
                 */
-               if (proto <= ETHERMTU) {
+               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, (bpf_int32)proto);
+                       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
@@ -3843,20 +4356,20 @@ gen_llc_linktype(compiler_state_t *cstate, int proto)
                         * organization code of 0x000000 (encapsulated
                         * Ethernet), we'd do
                         *
-                        *      return gen_snap(cstate, 0x000000, proto);
+                        *      return gen_snap(cstate, 0x000000, ll_proto);
                         *
                         * here; for now, we don't, as per the above.
                         * I don't know whether it's worth the extra CPU
                         * time to do the right check or not.
                         */
-                       return gen_cmp(cstate, OR_LLC, 6, BPF_H, (bpf_int32)proto);
+                       return gen_cmp(cstate, OR_LLC, 6, BPF_H, ll_proto);
                }
        }
 }
 
 static struct block *
 gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
-    int dir, int 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;
@@ -3872,35 +4385,51 @@ 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, proto, src_off, dst_off);
-               b1 = gen_hostop(cstate, addr, mask, Q_DST, 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_OR:
        case Q_DEFAULT:
-               b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
-               b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+       case Q_OR:
+               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:
+       case Q_ADDR2:
+       case Q_ADDR3:
+       case Q_ADDR4:
+       case Q_RA:
+       case Q_TA:
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
+               /*NOTREACHED*/
+
        default:
                abort();
+               /*NOTREACHED*/
        }
-       b0 = gen_linktype(cstate, proto);
-       b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, (bpf_int32)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, int 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;
-       u_int32_t *a, *m;
+       /*
+        * Code below needs to access four separate 32-bit parts of the 128-bit
+        * IPv6 address and mask.  In some OSes this is as simple as using the
+        * s6_addr32 pseudo-member of struct in6_addr, which contains a union of
+        * 8-, 16- and 32-bit arrays.  In other OSes this is not the case, as
+        * far as libpcap sees it.  Hence copy the data before use to avoid
+        * potential unaligned memory access and the associated compiler
+        * warnings (whether genuine or not).
+        */
+       bpf_u_int32 a[4], m[4];
 
        switch (dir) {
 
@@ -3913,211 +4442,59 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
                break;
 
        case Q_AND:
-               b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
-               b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
-               gen_and(b0, b1);
-               return b1;
-
-       case Q_OR:
-       case Q_DEFAULT:
-               b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
-               b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
-               gen_or(b0, b1);
-               return b1;
-
-       default:
-               abort();
-       }
-       /* this order is important */
-       a = (u_int32_t *)addr;
-       m = (u_int32_t *)mask;
-       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, proto);
-       gen_and(b0, b1);
-       return b1;
-}
-#endif
-
-static struct block *
-gen_ehostop(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, 6, 6, eaddr);
-
-       case Q_DST:
-               return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr);
-
-       case Q_AND:
-               b0 = gen_ehostop(cstate, eaddr, Q_SRC);
-               b1 = gen_ehostop(cstate, eaddr, Q_DST);
+               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_ehostop(cstate, eaddr, Q_SRC);
-               b1 = gen_ehostop(cstate, eaddr, Q_DST);
+               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' is only supported on 802.11 with 802.11 headers");
-               break;
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' is only supported on 802.11 with 802.11 headers");
-               break;
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' is only supported on 802.11 with 802.11 headers");
-               break;
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' is only supported on 802.11 with 802.11 headers");
-               break;
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers");
-               break;
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers");
-               break;
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
+               /*NOTREACHED*/
+
+       default:
+               abort();
+               /*NOTREACHED*/
        }
-       abort();
-       /* NOTREACHED */
+       /* this order is important */
+       memcpy(a, addr, sizeof(a));
+       memcpy(m, mask, sizeof(m));
+       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_ehostop, but for DLT_FDDI
+ * Like gen_mac48host(), but for DLT_IEEE802_11 (802.11 wireless LAN) and
+ * various 802.11 + radio headers.
  */
 static struct block *
-gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+gen_wlanhostop(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' is only supported on 802.11");
-               break;
-
-       case Q_ADDR2:
-               bpf_error(cstate, "'addr2' is only supported on 802.11");
-               break;
-
-       case Q_ADDR3:
-               bpf_error(cstate, "'addr3' is only supported on 802.11");
-               break;
-
-       case Q_ADDR4:
-               bpf_error(cstate, "'addr4' is only supported on 802.11");
-               break;
-
-       case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               break;
-
-       case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
-               break;
-       }
-       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' is only supported on 802.11");
-               break;
-
-       case Q_ADDR2:
-               bpf_error(cstate, "'addr2' is only supported on 802.11");
-               break;
-
-       case Q_ADDR3:
-               bpf_error(cstate, "'addr3' is only supported on 802.11");
-               break;
-
-       case Q_ADDR4:
-               bpf_error(cstate, "'addr4' is only supported on 802.11");
-               break;
-
-       case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               break;
-
-       case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
-               break;
-       }
-       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;
+       register struct block *b0, *b1, *b2;
+       register struct slist *s;
 
 #ifdef ENABLE_WLAN_FILTERING_PATCH
        /*
@@ -4157,9 +4534,7 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * 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;
+               b1 = gen_set(cstate, IEEE80211_FC1_DIR_TODS, s);
 
                /*
                 * If To DS is set, the SA is at 24.
@@ -4172,10 +4547,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 SA is at 16.
@@ -4195,19 +4567,14 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                 * 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;
+               b1 = gen_set(cstate, IEEE80211_FC1_DIR_FROMDS, 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);
+               b2 = gen_unset(cstate, IEEE80211_FC1_DIR_FROMDS, s);
 
                /*
                 * If From DS isn't set, the SA is at 10.
@@ -4227,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.
@@ -4242,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.
@@ -4269,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
@@ -4304,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.
@@ -4319,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.
@@ -4341,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.
@@ -4356,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.
@@ -4383,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
@@ -4395,6 +4741,64 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                gen_and(b1, b0);
                return b0;
 
+       case Q_AND:
+               b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
+               b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
+               gen_and(b0, b1);
+               return b1;
+
+       case Q_DEFAULT:
+       case Q_OR:
+               b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
+               b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
+               gen_or(b0, b1);
+               return b1;
+
+       /*
+        * XXX - add BSSID keyword?
+        */
+       case Q_ADDR1:
+               return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr));
+
+       case Q_ADDR2:
+               /*
+                * Not present in CTS or ACK control frames.
+                */
+               b0 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+                       IEEE80211_FC0_TYPE_MASK);
+               b1 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+                       IEEE80211_FC0_SUBTYPE_MASK);
+               b2 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+                       IEEE80211_FC0_SUBTYPE_MASK);
+               gen_and(b1, b2);
+               gen_or(b0, b2);
+               b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+               gen_and(b2, b1);
+               return b1;
+
+       case Q_ADDR3:
+               /*
+                * Not present in control frames.
+                */
+               b0 = gen_mcmp_ne(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+                       IEEE80211_FC0_TYPE_MASK);
+               b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+               gen_and(b0, b1);
+               return b1;
+
+       case Q_ADDR4:
+               /*
+                * Present only if the direction mask has both "From DS"
+                * and "To DS" set.  Neither control frames nor management
+                * frames should have both of those set, so we don't
+                * check the frame type.
+                */
+               b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B,
+                       IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK);
+               b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
+               gen_and(b0, b1);
+               return b1;
+
        case Q_RA:
                /*
                 * Not present in management frames; addr1 in other
@@ -4407,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.
@@ -4431,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);
 
@@ -4449,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
@@ -4465,129 +4862,9 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
                gen_and(b2, b1);
                return b1;
-
-       /*
-        * XXX - add BSSID keyword?
-        */
-       case Q_ADDR1:
-               return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr));
-
-       case Q_ADDR2:
-               /*
-                * Not present in CTS or ACK control frames.
-                */
-               b0 = gen_mcmp(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,
-                       IEEE80211_FC0_SUBTYPE_MASK);
-               gen_not(b1);
-               b2 = gen_mcmp(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);
-               gen_and(b2, b1);
-               return b1;
-
-       case Q_ADDR3:
-               /*
-                * Not present in control frames.
-                */
-               b0 = gen_mcmp(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;
-
-       case Q_ADDR4:
-               /*
-                * Present only if the direction mask has both "From DS"
-                * and "To DS" set.  Neither control frames nor management
-                * frames should have both of those set, so we don't
-                * check the frame type.
-                */
-               b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B,
-                       IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK);
-               b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
-               gen_and(b0, b1);
-               return b1;
-
-       case Q_AND:
-               b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
-               b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
-               gen_and(b0, b1);
-               return b1;
-
-       case Q_DEFAULT:
-       case Q_OR:
-               b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
-               b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
-               gen_or(b0, b1);
-               return b1;
-       }
-       abort();
-       /* 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' is only supported on 802.11");
-               break;
-
-       case Q_ADDR2:
-               bpf_error(cstate, "'addr2' is only supported on 802.11");
-               break;
-
-       case Q_ADDR3:
-               bpf_error(cstate, "'addr3' is only supported on 802.11");
-               break;
-
-       case Q_ADDR4:
-               bpf_error(cstate, "'addr4' is only supported on 802.11");
-               break;
-
-       case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               break;
-
-       case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
-               break;
        }
        abort();
-       /* NOTREACHED */
+       /*NOTREACHED*/
 }
 
 /*
@@ -4634,46 +4911,91 @@ gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir)
                gen_and(b0, b1);
                return b1;
 
-       case Q_OR:
        case Q_DEFAULT:
+       case Q_OR:
                /* Inefficient because we do our Calvinball dance twice */
                b0 = gen_dnhostop(cstate, addr, Q_SRC);
                b1 = gen_dnhostop(cstate, addr, Q_DST);
                gen_or(b0, b1);
                return b1;
 
-       case Q_ISO:
-               bpf_error(cstate, "ISO host filtering not implemented");
+       case Q_ADDR1:
+       case Q_ADDR2:
+       case Q_ADDR3:
+       case Q_ADDR4:
+       case Q_RA:
+       case Q_TA:
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
+               /*NOTREACHED*/
 
        default:
                abort();
+               /*NOTREACHED*/
        }
-       b0 = gen_linktype(cstate, ETHERTYPE_DN);
+       /*
+        * In a DECnet message inside an Ethernet frame the first two bytes
+        * immediately after EtherType are the [litle-endian] DECnet message
+        * length, which is irrelevant in this context.
+        *
+        * "pad = 1" means the third byte equals 0x81, thus it is the PLENGTH
+        * 8-bit bitmap of the optional padding before the packet route header.
+        * The bitmap always has bit 7 set to 1 and in this case has bits 0-6
+        * (TOTAL-PAD-SEQUENCE-LENGTH) set to integer value 1.  The latter
+        * means there aren't any PAD bytes after the bitmap, so the header
+        * begins at the fourth byte.  "pad = 0" means bit 7 of the third byte
+        * is set to 0, thus the header begins at the third byte.
+        *
+        * The header can be in several (as mentioned above) formats, all of
+        * which begin with the FLAGS 8-bit bitmap, which always has bit 7
+        * (PF, "pad field") set to 0 regardless of any padding present before
+        * the header.  "Short header" means bits 0-2 of the bitmap encode the
+        * integer value 2 (SFDP), and "long header" means value 6 (LFDP).
+        *
+        * To test PLENGTH and FLAGS, use multiple-byte constants with the
+        * values and the masks, this maps to the required single bytes of
+        * the message correctly on both big-endian and little-endian hosts.
+        * For the DECnet address use SWAPSHORT(), which always swaps bytes,
+        * because the wire encoding is little-endian and BPF multiple-byte
+        * loads are big-endian.  When the destination address is near enough
+        * to PLENGTH and FLAGS, generate one 32-bit comparison instead of two
+        * smaller ones.
+        */
        /* Check for pad = 1, long header case */
-       tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
-           (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF));
+       tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, 0x8106U, 0xFF07U);
        b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh,
-           BPF_H, (bpf_int32)ntohs((u_short)addr));
+           BPF_H, SWAPSHORT(addr));
        gen_and(tmp, b1);
        /* Check for pad = 0, long header case */
-       tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7);
-       b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+       tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, 0x06U, 0x07U);
+       b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H,
+           SWAPSHORT(addr));
        gen_and(tmp, b2);
        gen_or(b2, b1);
        /* Check for pad = 1, short header case */
-       tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
-           (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF));
-       b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
-       gen_and(tmp, b2);
+       if (dir == Q_DST) {
+               b2 = gen_mcmp(cstate, OR_LINKPL, 2, BPF_W,
+                   0x81020000U | SWAPSHORT(addr),
+                   0xFF07FFFFU);
+       } else {
+               tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, 0x8102U, 0xFF07U);
+               b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H,
+                   SWAPSHORT(addr));
+               gen_and(tmp, b2);
+       }
        gen_or(b2, b1);
        /* Check for pad = 0, short header case */
-       tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7);
-       b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
-       gen_and(tmp, b2);
+       if (dir == Q_DST) {
+               b2 = gen_mcmp(cstate, OR_LINKPL, 2, BPF_W,
+                   0x02000000U | SWAPSHORT(addr) << 8,
+                   0x07FFFF00U);
+       } else {
+               tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, 0x02U, 0x07U);
+               b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H,
+                   SWAPSHORT(addr));
+               gen_and(tmp, b2);
+       }
        gen_or(b2, b1);
 
-       /* Combine with test for cstate->linktype */
-       gen_and(b0, b1);
        return b1;
 }
 
@@ -4683,31 +5005,33 @@ gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir)
  * field in the IP header.
  */
 static struct block *
-gen_mpls_linktype(compiler_state_t *cstate, int proto)
+gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
        struct block *b0, *b1;
 
-        switch (proto) {
+       switch (ll_proto) {
 
-        case Q_IP:
-                /* match the bottom-of-stack bit */
-                b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01);
-                /* match the IPv4 version number */
-                b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0);
-                gen_and(b0, b1);
-                return b1;
+       case ETHERTYPE_IP:
+               /* match the bottom-of-stack bit */
+               b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
+               /* match the IPv4 version number */
+               b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0);
+               gen_and(b0, b1);
+               return b1;
 
-       case Q_IPV6:
-                /* match the bottom-of-stack bit */
-                b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01);
-                /* match the IPv4 version number */
-                b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0);
-                gen_and(b0, b1);
-                return b1;
+       case ETHERTYPE_IPV6:
+               /* match the bottom-of-stack bit */
+               b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
+               /* match the IPv6 version number */
+               b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0);
+               gen_and(b0, b1);
+               return b1;
 
-       default:
-                abort();
-        }
+       default:
+               /* FIXME add other L3 proto IDs */
+               bpf_error(cstate, "unsupported protocol over mpls");
+               /*NOTREACHED*/
+       }
 }
 
 static struct block *
@@ -4715,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) {
 
@@ -4738,103 +5056,93 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
                }
                return b0;
 
+       case Q_LINK:
+               // "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);
-
-       case Q_TCP:
-               bpf_error(cstate, "'tcp' modifier applied to %s", typestr);
+               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:
        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_PIM:
-               bpf_error(cstate, "'pim' modifier applied to %s", typestr);
-
-       case Q_VRRP:
-               bpf_error(cstate, "'vrrp' modifier applied to %s", typestr);
-
-       case Q_CARP:
-               bpf_error(cstate, "'carp' modifier applied to %s", typestr);
-
        case Q_ATALK:
-               bpf_error(cstate, "ATALK host filtering not implemented");
-
-       case Q_AARP:
-               bpf_error(cstate, "AARP host filtering not implemented");
+               break; // invalid qualifier
 
        case Q_DECNET:
-               return gen_dnhostop(cstate, addr, dir);
-
-       case Q_SCA:
-               bpf_error(cstate, "SCA host filtering not implemented");
+               b0 = gen_linktype(cstate, ETHERTYPE_DN);
+               b1 = gen_dnhostop(cstate, addr, dir);
+               gen_and(b0, b1);
+               return b1;
 
        case Q_LAT:
-               bpf_error(cstate, "LAT host filtering not implemented");
-
-       case Q_MOPDL:
-               bpf_error(cstate, "MOPDL host filtering not implemented");
-
+       case Q_SCA:
        case Q_MOPRC:
-               bpf_error(cstate, "MOPRC host filtering not implemented");
-
+       case Q_MOPDL:
        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:
+       case Q_VRRP:
+       case Q_AARP:
        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:
+       case Q_ISIS_L2:
+       case Q_ISIS_IIH:
+       case Q_ISIS_SNP:
+       case Q_ISIS_CSNP:
+       case Q_ISIS_PSNP:
+       case Q_ISIS_LSP:
        case Q_RADIO:
-               bpf_error(cstate, "'radio' modifier applied to %s", typestr);
+       case Q_CARP:
+               break; // invalid qualifier
 
        default:
                abort();
        }
-       /* NOTREACHED */
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto),
+           type == Q_NET ? "ip net" : "ip host");
+       /*NOTREACHED*/
 }
 
 #ifdef INET6
@@ -4842,192 +5150,243 @@ 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 %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_PIM:
-               bpf_error(cstate, "'pim' modifier applied to %s", typestr);
-
-       case Q_VRRP:
-               bpf_error(cstate, "'vrrp' modifier applied to %s", typestr);
-
-       case Q_CARP:
-               bpf_error(cstate, "'carp' modifier applied to %s", typestr);
-
        case Q_ATALK:
-               bpf_error(cstate, "ATALK host filtering not implemented");
-
-       case Q_AARP:
-               bpf_error(cstate, "AARP host filtering not implemented");
-
        case Q_DECNET:
-               bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr);
-
-       case Q_SCA:
-               bpf_error(cstate, "SCA host filtering not implemented");
-
        case Q_LAT:
-               bpf_error(cstate, "LAT host filtering not implemented");
-
-       case Q_MOPDL:
-               bpf_error(cstate, "MOPDL host filtering not implemented");
-
+       case Q_SCA:
        case Q_MOPRC:
-               bpf_error(cstate, "MOPRC host filtering not implemented");
-
-       case Q_IPV6:
-               return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24);
-
+       case Q_MOPDL:
        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:
+       case Q_VRRP:
+       case Q_AARP:
        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:
+       case Q_ISIS_L2:
+       case Q_ISIS_IIH:
+       case Q_ISIS_SNP:
+       case Q_ISIS_CSNP:
+       case Q_ISIS_PSNP:
+       case Q_ISIS_LSP:
        case Q_RADIO:
-               bpf_error(cstate, "'radio' modifier applied to %s", typestr);
+       case Q_CARP:
+               break; // invalid qualifier
 
        default:
                abort();
        }
-       /* NOTREACHED */
+       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, bpf_u_int32 **alist,
-    int proto, int dir)
+gen_gateway(compiler_state_t *cstate, const u_char *eaddr,
+    struct addrinfo *alist, int proto)
 {
        struct block *b0, *b1, *tmp;
-
-       if (dir != 0)
-               bpf_error(cstate, "direction applied to 'gateway'");
+       struct addrinfo *ai;
+       struct sockaddr_in *sin;
 
        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_SUNATM:
+               b0 = gen_mac48host(cstate, eaddr, Q_OR, "gateway");
+               b1 = NULL;
+               for (ai = alist; ai != NULL; ai = ai->ai_next) {
                        /*
-                        * This is LLC-multiplexed traffic; if it were
-                        * LANE, cstate->linktype would have been set to
-                        * DLT_EN10MB.
+                        * Does it have an address?
                         */
-                       bpf_error(cstate,
-                           "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
-                       break;
-               case DLT_IP_OVER_FC:
-                       b0 = gen_ipfchostop(cstate, eaddr, Q_OR);
-                       break;
-               default:
-                       bpf_error(cstate,
-                           "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+                       if (ai->ai_addr != NULL) {
+                               /*
+                                * Yes.  Is it an IPv4 address?
+                                */
+                               if (ai->ai_addr->sa_family == AF_INET) {
+                                       /*
+                                        * Generate an entry for it.
+                                        */
+                                       sin = (struct sockaddr_in *)ai->ai_addr;
+                                       tmp = gen_host(cstate,
+                                           ntohl(sin->sin_addr.s_addr),
+                                           0xffffffff, proto, Q_OR, Q_HOST);
+                                       /*
+                                        * Is it the *first* IPv4 address?
+                                        */
+                                       if (b1 == NULL) {
+                                               /*
+                                                * Yes, so start with it.
+                                                */
+                                               b1 = tmp;
+                                       } else {
+                                               /*
+                                                * No, so OR it into the
+                                                * existing set of
+                                                * addresses.
+                                                */
+                                               gen_or(b1, tmp);
+                                               b1 = tmp;
+                                       }
+                               }
+                       }
                }
-               b1 = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, Q_HOST);
-               while (*alist) {
-                       tmp = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR,
-                           Q_HOST);
-                       gen_or(b1, tmp);
-                       b1 = tmp;
+               if (b1 == NULL) {
+                       /*
+                        * No IPv4 addresses found.
+                        */
+                       return (NULL);
                }
                gen_not(b1);
                gen_and(b0, b1);
                return b1;
        }
-       bpf_error(cstate, "illegal modifier of 'gateway'");
-       /* NOTREACHED */
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "gateway");
+       /*NOTREACHED*/
 }
 #endif
 
-struct block *
-gen_proto_abbrev(compiler_state_t *cstate, int proto)
+static struct block *
+gen_proto_abbrev_internal(compiler_state_t *cstate, int proto)
 {
        struct block *b0;
        struct block *b1;
@@ -5035,251 +5394,228 @@ gen_proto_abbrev(compiler_state_t *cstate, int proto)
        switch (proto) {
 
        case Q_SCTP:
-               b1 = gen_proto(cstate, IPPROTO_SCTP, Q_IP, Q_DEFAULT);
-               b0 = gen_proto(cstate, IPPROTO_SCTP, Q_IPV6, Q_DEFAULT);
-               gen_or(b0, b1);
-               break;
+               return gen_proto(cstate, IPPROTO_SCTP, Q_DEFAULT);
 
        case Q_TCP:
-               b1 = gen_proto(cstate, IPPROTO_TCP, Q_IP, Q_DEFAULT);
-               b0 = gen_proto(cstate, IPPROTO_TCP, Q_IPV6, Q_DEFAULT);
-               gen_or(b0, b1);
-               break;
+               return gen_proto(cstate, IPPROTO_TCP, Q_DEFAULT);
 
        case Q_UDP:
-               b1 = gen_proto(cstate, IPPROTO_UDP, Q_IP, Q_DEFAULT);
-               b0 = gen_proto(cstate, IPPROTO_UDP, Q_IPV6, Q_DEFAULT);
-               gen_or(b0, b1);
-               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_IP, Q_DEFAULT);
-               b0 = gen_proto(cstate, IPPROTO_PIM, Q_IPV6, Q_DEFAULT);
-               gen_or(b0, b1);
-               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_IP, Q_DEFAULT);
-               b0 = gen_proto(cstate, IPPROTO_AH, Q_IPV6, Q_DEFAULT);
-               gen_or(b0, b1);
-               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_IP, Q_DEFAULT);
-               b0 = gen_proto(cstate, IPPROTO_ESP, Q_IPV6, Q_DEFAULT);
-               gen_or(b0, b1);
-               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 *
+gen_proto_abbrev(compiler_state_t *cstate, int proto)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       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);
 }
 
 /*
@@ -5292,61 +5628,65 @@ gen_ipfrag(compiler_state_t *cstate)
  * headers).
  */
 static struct block *
-gen_portatom(compiler_state_t *cstate, int off, bpf_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_int32 v)
+gen_portatom6(compiler_state_t *cstate, int off, uint16_t v)
 {
        return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v);
 }
 
-struct block *
-gen_portop(compiler_state_t *cstate, int port, int proto, int dir)
+static struct block *
+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, (bpf_int32)proto);
-       b0 = gen_ipfrag(cstate);
-       gen_and(tmp, b0);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
-               b1 = gen_portatom(cstate, 0, (bpf_int32)port);
+               b1 = gen_portatom(cstate, 0, port);
                break;
 
        case Q_DST:
-               b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+               b1 = gen_portatom(cstate, 2, port);
+               break;
+
+       case Q_AND:
+               tmp = gen_portatom(cstate, 0, port);
+               b1 = gen_portatom(cstate, 2, port);
+               gen_and(tmp, b1);
                break;
 
-       case Q_OR:
        case Q_DEFAULT:
-               tmp = gen_portatom(cstate, 0, (bpf_int32)port);
-               b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+       case Q_OR:
+               tmp = gen_portatom(cstate, 0, port);
+               b1 = gen_portatom(cstate, 2, port);
                gen_or(tmp, b1);
                break;
 
-       case Q_AND:
-               tmp = gen_portatom(cstate, 0, (bpf_int32)port);
-               b1 = gen_portatom(cstate, 2, (bpf_int32)port);
-               gen_and(tmp, b1);
-               break;
+       case Q_ADDR1:
+       case Q_ADDR2:
+       case Q_ADDR3:
+       case Q_ADDR4:
+       case Q_RA:
+       case Q_TA:
+               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, 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
@@ -5364,292 +5704,220 @@ gen_port(compiler_state_t *cstate, 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, 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, int port, 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, (bpf_int32)proto);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
-               b1 = gen_portatom6(cstate, 0, (bpf_int32)port);
+               b1 = gen_portatom6(cstate, 0, port);
                break;
 
        case Q_DST:
-               b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
-               break;
-
-       case Q_OR:
-       case Q_DEFAULT:
-               tmp = gen_portatom6(cstate, 0, (bpf_int32)port);
-               b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
-               gen_or(tmp, b1);
+               b1 = gen_portatom6(cstate, 2, port);
                break;
 
        case Q_AND:
-               tmp = gen_portatom6(cstate, 0, (bpf_int32)port);
-               b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
+               tmp = gen_portatom6(cstate, 0, port);
+               b1 = gen_portatom6(cstate, 2, port);
                gen_and(tmp, b1);
                break;
 
+       case Q_DEFAULT:
+       case Q_OR:
+               tmp = gen_portatom6(cstate, 0, port);
+               b1 = gen_portatom6(cstate, 2, port);
+               gen_or(tmp, b1);
+               break;
+
        default:
                abort();
        }
-       gen_and(b0, b1);
 
-       return b1;
+       return gen_port6_common(cstate, proto, b1);
 }
 
 static struct block *
-gen_port6(compiler_state_t *cstate, 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, 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, int off, bpf_int32 v1,
-    bpf_int32 v2)
+gen_portrangeatom(compiler_state_t *cstate, u_int off, uint16_t v1,
+    uint16_t v2)
 {
-       struct block *b1, *b2;
+       if (v1 == v2)
+               return gen_portatom(cstate, off, v1);
 
-       if (v1 > v2) {
-               /*
-                * Reverse the order of the ports, so v1 is the lower one.
-                */
-               bpf_int32 vtemp;
-
-               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);
 
        return b2;
 }
 
-struct block *
-gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto,
-    int dir)
+static struct block *
+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, (bpf_int32)proto);
-       b0 = gen_ipfrag(cstate);
-       gen_and(tmp, b0);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
-               b1 = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
+               b1 = gen_portrangeatom(cstate, 0, port1, port2);
                break;
 
        case Q_DST:
-               b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
-               break;
-
-       case Q_OR:
-       case Q_DEFAULT:
-               tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-               b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
-               gen_or(tmp, b1);
+               b1 = gen_portrangeatom(cstate, 2, port1, port2);
                break;
 
        case Q_AND:
-               tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-               b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+               tmp = gen_portrangeatom(cstate, 0, port1, port2);
+               b1 = gen_portrangeatom(cstate, 2, port1, port2);
                gen_and(tmp, b1);
                break;
 
-       default:
-               abort();
-       }
-       gen_and(b0, b1);
-
-       return b1;
-}
-
-static struct block *
-gen_portrange(compiler_state_t *cstate, int port1, int port2, int ip_proto,
-    int dir)
-{
-       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, 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);
+       case Q_DEFAULT:
+       case Q_OR:
+               tmp = gen_portrangeatom(cstate, 0, port1, port2);
+               b1 = gen_portrangeatom(cstate, 2, port1, port2);
                gen_or(tmp, b1);
                break;
 
+       case Q_ADDR1:
+       case Q_ADDR2:
+       case Q_ADDR3:
+       case Q_ADDR4:
+       case Q_RA:
+       case Q_TA:
+               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_portrangeatom6(compiler_state_t *cstate, int off, bpf_int32 v1,
-    bpf_int32 v2)
+gen_portrangeatom6(compiler_state_t *cstate, u_int off, uint16_t v1,
+    uint16_t v2)
 {
-       struct block *b1, *b2;
+       if (v1 == v2)
+               return gen_portatom6(cstate, off, v1);
 
-       if (v1 > v2) {
-               /*
-                * Reverse the order of the ports, so v1 is the lower one.
-                */
-               bpf_int32 vtemp;
-
-               vtemp = v1;
-               v1 = v2;
-               v2 = vtemp;
-       }
+       struct block *b1, *b2;
 
-       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);
 
        return b2;
 }
 
-struct block *
-gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto,
-    int dir)
+static struct block *
+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, (bpf_int32)proto);
+       struct block *b1, *tmp;
 
        switch (dir) {
        case Q_SRC:
-               b1 = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
+               b1 = gen_portrangeatom6(cstate, 0, port1, port2);
                break;
 
        case Q_DST:
-               b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
-               break;
-
-       case Q_OR:
-       case Q_DEFAULT:
-               tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-               b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
-               gen_or(tmp, b1);
+               b1 = gen_portrangeatom6(cstate, 2, port1, port2);
                break;
 
        case Q_AND:
-               tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-               b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+               tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+               b1 = gen_portrangeatom6(cstate, 2, port1, port2);
                gen_and(tmp, b1);
                break;
 
-       default:
-               abort();
-       }
-       gen_and(b0, b1);
-
-       return b1;
-}
-
-static struct block *
-gen_portrange6(compiler_state_t *cstate, int port1, 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, 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);
+       case Q_DEFAULT:
+       case Q_OR:
+               tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+               b1 = gen_portrangeatom6(cstate, 2, port1, port2);
                gen_or(tmp, b1);
                break;
 
        default:
                abort();
        }
-       gen_and(b0, b1);
-       return b1;
+
+       return gen_port6_common(cstate, proto, b1);
 }
 
 static int
@@ -5695,22 +5963,14 @@ lookup_proto(compiler_state_t *cstate, const char *name, int proto)
        return v;
 }
 
-#if 0
-struct stmt *
-gen_joinsp(s, n)
-       struct stmt **s;
-       int n;
-{
-       return NULL;
-}
-#endif
-
+#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, int v, int proto, int dir)
+gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
 {
-#ifdef NO_PROTOCHAIN
-       return gen_proto(cstate, v, proto, dir);
-#else
        struct block *b0, *b;
        struct slist *s[100];
        int fix2, fix3, fix4, fix5;
@@ -5724,14 +5984,15 @@ gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
        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, dir);
-               b = gen_protochain(cstate, v, Q_IPV6, dir);
+               b0 = gen_protochain(cstate, v, Q_IP);
+               b = gen_protochain(cstate, v, Q_IPV6);
                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*/
        }
 
@@ -5749,7 +6010,18 @@ gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
        if (cstate->off_linkpl.is_variable)
                bpf_error(cstate, "'protochain' not supported with variable length headers");
 
-       cstate->no_optimize = 1; /*this code is not compatible with optimzer yet */
+       /*
+        * To quote a comment in optimize.c:
+        *
+        * "These data structures are used in a Cocke and Schwartz style
+        * value numbering scheme.  Since the flowgraph is acyclic,
+        * exit values can be propagated from a node's predecessors
+        * provided it is uniquely defined."
+        *
+        * "Acyclic" means "no backward branches", which means "no
+        * loops", so we have to turn the optimizer off.
+        */
+       cstate->no_optimize = 1;
 
        /*
         * s[0] is a dummy entry to protect other BPF insn from damage
@@ -5919,12 +6191,10 @@ gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
         * 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);
@@ -5984,43 +6254,16 @@ gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
 
        /*
         * 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);
 
        gen_and(b0, b);
        return b;
-#endif
-}
-
-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;
 }
+#endif /* !defined(NO_PROTOCHAIN) */
 
 /*
  * Generate code that checks whether the packet is a packet for protocol
@@ -6030,26 +6273,28 @@ 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, int v, int proto, int dir)
+gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto)
 {
        struct block *b0, *b1;
-#ifndef CHASE_CHAIN
        struct block *b2;
-#endif
-
-       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;
 
+       case Q_LINK:
+               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.
@@ -6066,22 +6311,60 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
                 * So we always check for ETHERTYPE_IP.
                 */
                b0 = gen_linktype(cstate, ETHERTYPE_IP);
-#ifndef CHASE_CHAIN
-               b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)v);
-#else
-               b1 = gen_protochain(cstate, v, Q_IP);
-#endif
+               // 0 <= v <= UINT8_MAX
+               b1 = gen_ip_proto(cstate, (uint8_t)v);
                gen_and(b0, b1);
                return b1;
 
-       case Q_ISO:
-               switch (cstate->linktype) {
+       case Q_ARP:
+       case Q_RARP:
+       case Q_SCTP:
+       case Q_TCP:
+       case Q_UDP:
+       case Q_ICMP:
+       case Q_IGMP:
+       case Q_IGRP:
+       case Q_ATALK:
+       case Q_DECNET:
+       case Q_LAT:
+       case Q_SCA:
+       case Q_MOPRC:
+       case Q_MOPDL:
+               break; // invalid qualifier
 
-               case DLT_FRELAY:
-                       /*
-                        * Frame Relay packets typically have an OSI
-                        * NLPID at the beginning; "gen_linktype(cstate, LLCSAP_ISONS)"
-                        * generates code to check for all the OSI
+       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_ip6_proto(cstate, IPPROTO_FRAGMENT);
+               b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v);
+               gen_and(b2, b1);
+               // 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:
+       case Q_AH:
+       case Q_ESP:
+       case Q_PIM:
+       case Q_VRRP:
+       case Q_AARP:
+               break; // invalid qualifier
+
+       case Q_ISO:
+               assert_maxval(cstate, "ISO protocol", v, UINT8_MAX);
+               switch (cstate->linktype) {
+
+               case DLT_FRELAY:
+                       /*
+                        * Frame Relay packets typically have an OSI
+                        * NLPID at the beginning; "gen_linktype(cstate, LLCSAP_ISONS)"
+                        * generates code to check for all the OSI
                         * NLPIDs, so calling it and then adding a check
                         * for the particular NLPID for which we're
                         * looking is bogus, as we can just check for
@@ -6098,151 +6381,340 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
                         */
                        return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v);
                        /*NOTREACHED*/
-                       break;
 
                case DLT_C_HDLC:
+               case DLT_HDLC:
                        /*
                         * Cisco uses an Ethertype lookalike - for OSI,
                         * it's 0xfefe.
                         */
                        b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS);
                        /* OSI in C-HDLC is stuffed with a fudge byte */
-                       b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, (long)v);
+                       b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, v);
                        gen_and(b0, b1);
                        return b1;
 
                default:
                        b0 = gen_linktype(cstate, LLCSAP_ISONS);
-                       b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, (long)v);
+                       b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, v);
                        gen_and(b0, b1);
                        return b1;
                }
 
+       case Q_ESIS:
+               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, (long)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_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_ATALK:
-               bpf_error(cstate, "atalk encapsulation is not specifiable");
-               /* NOTREACHED */
-
-       case Q_DECNET:
-               bpf_error(cstate, "decnet encapsulation is not specifiable");
-               /* NOTREACHED */
-
-       case Q_SCA:
-               bpf_error(cstate, "sca does not encapsulate another protocol");
-               /* NOTREACHED */
-
-       case Q_LAT:
-               bpf_error(cstate, "lat 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 */
-
-       case Q_LINK:
-               return gen_linktype(cstate, v);
-
-       case Q_UDP:
-               bpf_error(cstate, "'udp proto' is bogus");
-               /* NOTREACHED */
+       case Q_CLNP:
+       case Q_STP:
+       case Q_IPX:
+       case Q_NETBEUI:
+       case Q_ISIS_L1:
+       case Q_ISIS_L2:
+       case Q_ISIS_IIH:
+       case Q_ISIS_SNP:
+       case Q_ISIS_CSNP:
+       case Q_ISIS_PSNP:
+       case Q_ISIS_LSP:
+       case Q_RADIO:
+       case Q_CARP:
+               break; // invalid qualifier
 
-       case Q_TCP:
-               bpf_error(cstate, "'tcp proto' is bogus");
-               /* NOTREACHED */
+       default:
+               abort();
+               /*NOTREACHED*/
+       }
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "proto");
+       /*NOTREACHED*/
+}
 
-       case Q_SCTP:
-               bpf_error(cstate, "'sctp proto' is bogus");
-               /* NOTREACHED */
+/*
+ * Convert a non-numeric name to a port number.
+ */
+static int
+nametoport(compiler_state_t *cstate, const char *name, int ipproto)
+{
+       struct addrinfo hints, *res, *ai;
+       int error;
+       struct sockaddr_in *in4;
+#ifdef INET6
+       struct sockaddr_in6 *in6;
+#endif
+       int port = -1;
 
-       case Q_ICMP:
-               bpf_error(cstate, "'icmp proto' is bogus");
-               /* NOTREACHED */
+       /*
+        * We check for both TCP and UDP in case there are
+        * ambiguous entries.
+        */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = (ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
+       hints.ai_protocol = ipproto;
+       error = getaddrinfo(NULL, name, &hints, &res);
+       if (error != 0) {
+               switch (error) {
+
+               case EAI_NONAME:
+               case EAI_SERVICE:
+                       /*
+                        * No such port.  Just return -1.
+                        */
+                       break;
 
-       case Q_IGMP:
-               bpf_error(cstate, "'igmp proto' is bogus");
-               /* NOTREACHED */
+#ifdef EAI_SYSTEM
+               case EAI_SYSTEM:
+                       /*
+                        * We don't use strerror() because it's not
+                        * guaranteed to be thread-safe on all platforms
+                        * (probably because it might use a non-thread-local
+                        * buffer into which to format an error message
+                        * if the error code isn't one for which it has
+                        * a canned string; three cheers for C string
+                        * handling).
+                        */
+                       bpf_set_error(cstate, "getaddrinfo(\"%s\" fails with system error: %d",
+                           name, errno);
+                       port = -2;      /* a real error */
+                       break;
+#endif
 
-       case Q_IGRP:
-               bpf_error(cstate, "'igrp proto' is bogus");
-               /* NOTREACHED */
+               default:
+                       /*
+                        * This is a real error, not just "there's
+                        * no such service name".
+                        *
+                        * We don't use gai_strerror() because it's not
+                        * guaranteed to be thread-safe on all platforms
+                        * (probably because it might use a non-thread-local
+                        * buffer into which to format an error message
+                        * if the error code isn't one for which it has
+                        * a canned string; three cheers for C string
+                        * handling).
+                        */
+                       bpf_set_error(cstate, "getaddrinfo(\"%s\") fails with error: %d",
+                           name, error);
+                       port = -2;      /* a real error */
+                       break;
+               }
+       } else {
+               /*
+                * OK, we found it.  Did it find anything?
+                */
+               for (ai = res; ai != NULL; ai = ai->ai_next) {
+                       /*
+                        * Does it have an address?
+                        */
+                       if (ai->ai_addr != NULL) {
+                               /*
+                                * Yes.  Get a port number; we're done.
+                                */
+                               if (ai->ai_addr->sa_family == AF_INET) {
+                                       in4 = (struct sockaddr_in *)ai->ai_addr;
+                                       port = ntohs(in4->sin_port);
+                                       break;
+                               }
+#ifdef INET6
+                               if (ai->ai_addr->sa_family == AF_INET6) {
+                                       in6 = (struct sockaddr_in6 *)ai->ai_addr;
+                                       port = ntohs(in6->sin6_port);
+                                       break;
+                               }
+#endif
+                       }
+               }
+               freeaddrinfo(res);
+       }
+       return port;
+}
 
-       case Q_PIM:
-               bpf_error(cstate, "'pim proto' is bogus");
-               /* NOTREACHED */
+/*
+ * Convert a string to a port number.
+ */
+static bpf_u_int32
+stringtoport(compiler_state_t *cstate, const char *string, size_t string_size,
+    int *proto)
+{
+       stoulen_ret ret;
+       char *cpy;
+       bpf_u_int32 val;
+       int tcp_port = -1;
+       int udp_port = -1;
 
-       case Q_VRRP:
-               bpf_error(cstate, "'vrrp proto' is bogus");
-               /* NOTREACHED */
+       /*
+        * See if it's a number.
+        */
+       ret = stoulen(string, string_size, &val, cstate);
+       switch (ret) {
 
-       case Q_CARP:
-               bpf_error(cstate, "'carp proto' is bogus");
-               /* NOTREACHED */
+       case STOULEN_OK:
+               /* Unknown port type - it's just a number. */
+               *proto = PROTO_UNDEF;
+               break;
 
-       case Q_IPV6:
-               b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
-#ifndef CHASE_CHAIN
+       case STOULEN_NOT_OCTAL_NUMBER:
+       case STOULEN_NOT_HEX_NUMBER:
+       case STOULEN_NOT_DECIMAL_NUMBER:
                /*
-                * Also check for a fragment header before the final
-                * header.
+                * Not a valid number; try looking it up as a port.
                 */
-               b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT);
-               b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, (bpf_int32)v);
-               gen_and(b2, b1);
-               b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)v);
-               gen_or(b2, b1);
-#else
-               b1 = gen_protochain(cstate, v, Q_IPV6);
+               cpy = malloc(string_size + 1);  /* +1 for terminating '\0' */
+               memcpy(cpy, string, string_size);
+               cpy[string_size] = '\0';
+               tcp_port = nametoport(cstate, cpy, IPPROTO_TCP);
+               if (tcp_port == -2) {
+                       /*
+                        * We got a hard error; the error string has
+                        * already been set.
+                        */
+                       free(cpy);
+                       longjmp(cstate->top_ctx, 1);
+                       /*NOTREACHED*/
+               }
+               udp_port = nametoport(cstate, cpy, IPPROTO_UDP);
+               if (udp_port == -2) {
+                       /*
+                        * We got a hard error; the error string has
+                        * already been set.
+                        */
+                       free(cpy);
+                       longjmp(cstate->top_ctx, 1);
+                       /*NOTREACHED*/
+               }
+
+               /*
+                * We need to check /etc/services for ambiguous entries.
+                * If we find an ambiguous entry, and it has the
+                * same port number, change the proto to PROTO_UNDEF
+                * so both TCP and UDP will be checked.
+                */
+               if (tcp_port >= 0) {
+                       val = (bpf_u_int32)tcp_port;
+                       *proto = IPPROTO_TCP;
+                       if (udp_port >= 0) {
+                               if (udp_port == tcp_port)
+                                       *proto = PROTO_UNDEF;
+#ifdef notdef
+                               else
+                                       /* Can't handle ambiguous names that refer
+                                          to different port numbers. */
+                                       warning("ambiguous port %s in /etc/services",
+                                               cpy);
 #endif
-               gen_and(b0, b1);
-               return b1;
+                       }
+                       free(cpy);
+                       break;
+               }
+               if (udp_port >= 0) {
+                       val = (bpf_u_int32)udp_port;
+                       *proto = IPPROTO_UDP;
+                       free(cpy);
+                       break;
+               }
+               bpf_set_error(cstate, "'%s' is not a valid port", cpy);
+               free(cpy);
+               longjmp(cstate->top_ctx, 1);
+               /*NOTREACHED*/
+#ifdef _AIX
+               PCAP_UNREACHABLE
+#endif /* _AIX */
 
-       case Q_ICMPV6:
-               bpf_error(cstate, "'icmp6 proto' is bogus");
+       case STOULEN_ERROR:
+               /* Error already set. */
+               longjmp(cstate->top_ctx, 1);
+               /*NOTREACHED*/
+#ifdef _AIX
+               PCAP_UNREACHABLE
+#endif /* _AIX */
 
-       case Q_AH:
-               bpf_error(cstate, "'ah proto' is bogus");
+       default:
+               /* Should not happen */
+               bpf_set_error(cstate, "stoulen returned %d - this should not happen", ret);
+               longjmp(cstate->top_ctx, 1);
+               /*NOTREACHED*/
+       }
+       return (val);
+}
 
-       case Q_ESP:
-               bpf_error(cstate, "'ah proto' is bogus");
+/*
+ * Convert a string in the form PPP-PPP, which correspond to ports, to
+ * a starting and ending port in a port range.
+ */
+static void
+stringtoportrange(compiler_state_t *cstate, const char *string,
+    bpf_u_int32 *port1, bpf_u_int32 *port2, int *proto)
+{
+       char *hyphen_off;
+       const char *first, *second;
+       size_t first_size, second_size;
+       int save_proto;
 
-       case Q_STP:
-               bpf_error(cstate, "'stp proto' is bogus");
+       if ((hyphen_off = strchr(string, '-')) == NULL)
+               bpf_error(cstate, "port range '%s' contains no hyphen", string);
 
-       case Q_IPX:
-               bpf_error(cstate, "'ipx proto' is bogus");
+       /*
+        * Make sure there are no other hyphens.
+        *
+        * XXX - we support named ports, but there are some port names
+        * in /etc/services that include hyphens, so this would rule
+        * that out.
+        */
+       if (strchr(hyphen_off + 1, '-') != NULL)
+               bpf_error(cstate, "port range '%s' contains more than one hyphen",
+                   string);
 
-       case Q_NETBEUI:
-               bpf_error(cstate, "'netbeui proto' is bogus");
+       /*
+        * Get the length of the first port.
+        */
+       first = string;
+       first_size = hyphen_off - string;
+       if (first_size == 0) {
+               /* Range of "-port", which we don't support. */
+               bpf_error(cstate, "port range '%s' has no starting port", string);
+       }
 
-       case Q_RADIO:
-               bpf_error(cstate, "'radio proto' is bogus");
+       /*
+        * Try to convert it to a port.
+        */
+       *port1 = stringtoport(cstate, first, first_size, proto);
+       save_proto = *proto;
 
-       default:
-               abort();
-               /* NOTREACHED */
+       /*
+        * Get the length of the second port.
+        */
+       second = hyphen_off + 1;
+       second_size = strlen(second);
+       if (second_size == 0) {
+               /* Range of "port-", which we don't support. */
+               bpf_error(cstate, "port range '%s' has no ending port", string);
        }
-       /* NOTREACHED */
+
+       /*
+        * Try to convert it to a port.
+        */
+       *port2 = stringtoport(cstate, second, second_size, proto);
+       if (*proto != save_proto)
+               *proto = PROTO_UNDEF;
 }
 
 struct block *
@@ -6251,20 +6723,26 @@ 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;
-#ifndef INET6
-       bpf_u_int32 **alist;
-#else
-       int tproto6;
+       struct addrinfo *res, *res0;
        struct sockaddr_in *sin4;
+#ifdef INET6
+       int tproto6;
        struct sockaddr_in6 *sin6;
-       struct addrinfo *res, *res0;
        struct in6_addr mask128;
 #endif /*INET6*/
        struct block *b, *tmp;
        int port, real_proto;
-       int port1, port2;
+       bpf_u_int32 port1, port2;
+
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
 
        switch (q.addr) {
 
@@ -6283,121 +6761,56 @@ 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) {
-                       unsigned short dn_addr;
-
-                       if (!__pcap_nametodnaddr(name, &dn_addr)) {
-#ifdef DECNETLIB
-                               bpf_error(cstate, "unknown decnet host name '%s'\n", name);
-#else
-                               bpf_error(cstate, "decnet name support not included, '%s' cannot be translated\n",
-                                       name);
-#endif
-                       }
                        /*
-                        * I don't think DECNET hosts can be multihomed, so
-                        * there is no need to build up a list of addresses
+                        * A long time ago on Ultrix libpcap supported
+                        * translation of DECnet host names into DECnet
+                        * addresses, but this feature is history now.
                         */
-                       return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr));
+                       bpf_error(cstate, "invalid DECnet address '%s'", name);
                } else {
-#ifndef INET6
-                       alist = pcap_nametoaddr(name);
-                       if (alist == NULL || *alist == NULL)
-                               bpf_error(cstate, "unknown host '%s'", name);
-                       tproto = proto;
-                       if (cstate->off_linktype.constant_part == OFFSET_NOT_SET &&
-                           tproto == Q_DEFAULT)
-                               tproto = Q_IP;
-                       b = gen_host(cstate, **alist++, 0xffffffff, tproto, dir, q.addr);
-                       while (*alist) {
-                               tmp = gen_host(cstate, **alist++, 0xffffffff,
-                                              tproto, dir, q.addr);
-                               gen_or(b, tmp);
-                               b = tmp;
-                       }
-                       return b;
-#else
+#ifdef INET6
                        memset(&mask128, 0xff, sizeof(mask128));
+#endif
                        res0 = res = pcap_nametoaddrinfo(name);
                        if (res == NULL)
                                bpf_error(cstate, "unknown host '%s'", name);
                        cstate->ai = res;
                        b = tmp = NULL;
-                       tproto = tproto6 = proto;
+                       tproto = proto;
+#ifdef INET6
+                       tproto6 = proto;
+#endif
                        if (cstate->off_linktype.constant_part == OFFSET_NOT_SET &&
                            tproto == Q_DEFAULT) {
                                tproto = Q_IP;
+#ifdef INET6
                                tproto6 = Q_IPV6;
+#endif
                        }
                        for (res = res0; res; res = res->ai_next) {
                                switch (res->ai_family) {
                                case AF_INET:
+#ifdef INET6
                                        if (tproto == Q_IPV6)
                                                continue;
+#endif
 
                                        sin4 = (struct sockaddr_in *)
                                                res->ai_addr;
                                        tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr),
                                                0xffffffff, tproto, dir, q.addr);
                                        break;
+#ifdef INET6
                                case AF_INET6:
                                        if (tproto6 == Q_IP)
                                                continue;
@@ -6407,6 +6820,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                                        tmp = gen_host6(cstate, &sin6->sin6_addr,
                                                &mask128, tproto6, dir, q.addr);
                                        break;
+#endif
                                default:
                                        continue;
                                }
@@ -6423,13 +6837,10 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                                        : " for specified address family");
                        }
                        return b;
-#endif /*INET6*/
                }
 
        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) {
@@ -6465,16 +6876,14 @@ 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'");
-               if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0)
-                       bpf_error(cstate, "unknown port in range '%s'", name);
+               (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)
                                bpf_error(cstate, "port in range '%s' is tcp", name);
@@ -6502,30 +6911,37 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                                /* override PROTO_UNDEF */
                                real_proto = IPPROTO_SCTP;
                }
-               if (port1 < 0)
-                       bpf_error(cstate, "illegal port number %d < 0", port1);
                if (port1 > 65535)
                        bpf_error(cstate, "illegal port number %d > 65535", port1);
-               if (port2 < 0)
-                       bpf_error(cstate, "illegal port number %d < 0", port2);
                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);
-
-               alist = pcap_nametoaddr(name);
-               if (alist == NULL || *alist == NULL)
+               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);
+               cstate->ai = NULL;
+               freeaddrinfo(res);
+               if (b == NULL)
                        bpf_error(cstate, "unknown host '%s'", name);
-               b = gen_gateway(cstate, eaddr, alist, proto, dir);
-               free(eaddr);
                return b;
 #else
                bpf_error(cstate, "'gateway' not supported in this configuration");
@@ -6534,38 +6950,52 @@ 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);
 
+#if !defined(NO_PROTOCHAIN)
        case Q_PROTOCHAIN:
                real_proto = lookup_proto(cstate, name, proto);
                if (real_proto >= 0)
-                       return gen_protochain(cstate, real_proto, proto, dir);
+                       return gen_protochain(cstate, real_proto, proto);
                else
                        bpf_error(cstate, "unknown protocol: %s", name);
+#endif /* !defined(NO_PROTOCHAIN) */
 
        case Q_UNDEF:
                syntax(cstate);
-               /* NOTREACHED */
+               /*NOTREACHED*/
        }
        abort();
-       /* NOTREACHED */
+       /*NOTREACHED*/
 }
 
 struct block *
 gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
-    unsigned int masklen, struct qual q)
+    bpf_u_int32 masklen, struct qual q)
 {
        register int nlen, mlen;
        bpf_u_int32 n, m;
+       uint64_t m64;
+
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
 
-       nlen = __pcap_atoin(s1, &n);
+       nlen = pcapint_atoin(s1, &n);
+       if (nlen < 0)
+               bpf_error(cstate, "invalid IPv4 address '%s'", s1);
        /* Promote short ipaddr */
        n <<= 32 - nlen;
 
        if (s2 != NULL) {
-               mlen = __pcap_atoin(s2, &m);
+               mlen = pcapint_atoin(s2, &m);
+               if (mlen < 0)
+                       bpf_error(cstate, "invalid IPv4 address '%s'", s2);
                /* Promote short ipaddr */
                m <<= 32 - mlen;
                if ((n & ~m) != 0)
@@ -6575,14 +7005,8 @@ gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
                /* Convert mask len to mask */
                if (masklen > 32)
                        bpf_error(cstate, "mask length must be <= 32");
-               if (masklen == 0) {
-                       /*
-                        * X << 32 is not guaranteed by C to be 0; it's
-                        * undefined.
-                        */
-                       m = 0;
-               } else
-                       m = 0xffffffff << (32 - masklen);
+               m64 = UINT64_C(0xffffffff) << (32 - masklen);
+               m = (bpf_u_int32)m64;
                if ((n & ~m) != 0)
                        bpf_error(cstate, "non-network bits set in \"%s/%d\"",
                            s1, masklen);
@@ -6594,29 +7018,63 @@ 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 */
+               /*NOTREACHED*/
        }
-       /* NOTREACHED */
-       return NULL;
+       /*NOTREACHED*/
 }
 
 struct block *
 gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
 {
        bpf_u_int32 mask;
-       int proto = q.proto;
-       int dir = q.dir;
+       int proto;
+       int dir;
        register int vlen;
 
-       if (s == NULL)
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       proto = q.proto;
+       dir = q.dir;
+       if (s == NULL) {
+               /*
+                * v contains a 32-bit unsigned parsed from a string of the
+                * form {N}, which could be decimal, hexadecimal or octal.
+                * Although it would be possible to use the value as a raw
+                * 16-bit DECnet address when the value fits into 16 bits, this
+                * would be a questionable feature: DECnet address wire
+                * encoding is little-endian, so this would not work as
+                * intuitively as the same works for [big-endian] IPv4
+                * addresses (0x01020304 means 1.2.3.4).
+                */
+               if (proto == Q_DECNET)
+                       bpf_error(cstate, "invalid DECnet address '%u'", v);
                vlen = 32;
-       else if (q.proto == Q_DECNET) {
-               vlen = __pcap_atodn(s, &v);
+       } else if (proto == Q_DECNET) {
+               /*
+                * s points to a string of the form {N}.{N}, {N}.{N}.{N} or
+                * {N}.{N}.{N}.{N}, of which only the first potentially stands
+                * for a valid DECnet address.
+                */
+               vlen = pcapint_atodn(s, &v);
                if (vlen == 0)
-                       bpf_error(cstate, "malformed decnet address '%s'", s);
-       } else
-               vlen = __pcap_atoin(s, &v);
+                       bpf_error(cstate, "invalid DECnet address '%s'", s);
+       } else {
+               /*
+                * s points to a string of the form {N}.{N}, {N}.{N}.{N} or
+                * {N}.{N}.{N}.{N}, all of which potentially stand for a valid
+                * IPv4 address.
+                */
+               vlen = pcapint_atoin(s, &v);
+               if (vlen < 0)
+                       bpf_error(cstate, "invalid IPv4 address '%s'", s);
+       }
 
        switch (q.addr) {
 
@@ -6626,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;
@@ -6644,106 +7103,98 @@ 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, (int)v, proto, dir);
-               gen_or(gen_port6(cstate, (int)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, (int)v, (int)v, proto, dir);
-               gen_or(gen_portrange6(cstate, (int)v, (int)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;
            }
 
        case Q_GATEWAY:
                bpf_error(cstate, "'gateway' requires a name");
-               /* NOTREACHED */
+               /*NOTREACHED*/
 
        case Q_PROTO:
-               return gen_proto(cstate, (int)v, proto, dir);
+               return gen_proto(cstate, v, proto);
 
+#if !defined(NO_PROTOCHAIN)
        case Q_PROTOCHAIN:
-               return gen_protochain(cstate, (int)v, proto, dir);
+               return gen_protochain(cstate, v, proto);
+#endif
 
        case Q_UNDEF:
                syntax(cstate);
-               /* NOTREACHED */
+               /*NOTREACHED*/
 
        default:
                abort();
-               /* NOTREACHED */
+               /*NOTREACHED*/
        }
-       /* NOTREACHED */
+       /*NOTREACHED*/
 }
 
 #ifdef INET6
 struct block *
-gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
-    unsigned int masklen, struct qual q)
+gen_mcode6(compiler_state_t *cstate, const char *s, bpf_u_int32 masklen,
+    struct qual q)
 {
        struct addrinfo *res;
        struct in6_addr *addr;
        struct in6_addr mask;
        struct block *b;
-       u_int32_t *a, *m;
+       bpf_u_int32 a[4], m[4]; /* Same as in gen_hostop6(). */
 
-       if (s2)
-               bpf_error(cstate, "no mask %s supported", s2);
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
 
-       res = pcap_nametoaddrinfo(s1);
+       res = pcap_nametoaddrinfo(s);
        if (!res)
-               bpf_error(cstate, "invalid ip6 address %s", s1);
+               bpf_error(cstate, "invalid ip6 address %s", s);
        cstate->ai = res;
        if (res->ai_next)
-               bpf_error(cstate, "%s resolved to multiple address", s1);
+               bpf_error(cstate, "%s resolved to multiple address", s);
        addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
 
-       if (sizeof(mask) * 8 < masklen)
-               bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask) * 8));
+       if (masklen > sizeof(mask.s6_addr) * 8)
+               bpf_error(cstate, "mask length must be <= %zu", sizeof(mask.s6_addr) * 8);
        memset(&mask, 0, sizeof(mask));
-       memset(&mask, 0xff, masklen / 8);
+       memset(&mask.s6_addr, 0xff, masklen / 8);
        if (masklen % 8) {
                mask.s6_addr[masklen / 8] =
                        (0xff << (8 - masklen % 8)) & 0xff;
        }
 
-       a = (u_int32_t *)addr;
-       m = (u_int32_t *)&mask;
+       memcpy(a, addr, sizeof(a));
+       memcpy(m, &mask, sizeof(m));
        if ((a[0] & ~m[0]) || (a[1] & ~m[1])
         || (a[2] & ~m[2]) || (a[3] & ~m[3])) {
-               bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen);
+               bpf_error(cstate, "non-network bits set in \"%s/%d\"", s, masklen);
        }
 
        switch (q.addr) {
@@ -6761,53 +7212,41 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
                return b;
 
        default:
+               // Q_GATEWAY only (see the grammar)
                bpf_error(cstate, "invalid qualifier against IPv6 address");
-               /* NOTREACHED */
+               /*NOTREACHED*/
        }
-       return NULL;
 }
 #endif /*INET6*/
 
 struct block *
-gen_ecode(compiler_state_t *cstate, const u_char *eaddr, struct qual q)
+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.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
 
        if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
-               switch (cstate->linktype) {
-               case DLT_EN10MB:
-               case DLT_NETANALYZER:
-               case DLT_NETANALYZER_TRANSPARENT:
-                       tmp = gen_prevlinkhdr_check(cstate);
-                       b = gen_ehostop(cstate, eaddr, (int)q.dir);
-                       if (tmp != NULL)
-                               gen_and(tmp, b);
-                       return b;
-               case DLT_FDDI:
-                       return gen_fhostop(cstate, eaddr, (int)q.dir);
-               case DLT_IEEE802:
-                       return gen_thostop(cstate, eaddr, (int)q.dir);
-               case DLT_IEEE802_11:
-               case DLT_PRISM_HEADER:
-               case DLT_IEEE802_11_RADIO_AVS:
-               case DLT_IEEE802_11_RADIO:
-               case DLT_PPI:
-                       return gen_wlanhostop(cstate, eaddr, (int)q.dir);
-               case DLT_IP_OVER_FC:
-                       return gen_ipfchostop(cstate, eaddr, (int)q.dir);
-               default:
-                       bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
-                       break;
-               }
+               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");
+               struct block *b = gen_mac48host(cstate, cstate->e, q.dir, context);
+               free(cstate->e);
+               cstate->e = NULL;
+               return (b);
        }
        bpf_error(cstate, "ethernet address used in non-ether expression");
-       /* NOTREACHED */
-       return NULL;
+       /*NOTREACHED*/
 }
 
 void
-sappend(s0, s1)
-       struct slist *s0, *s1;
+sappend(struct slist *s0, struct slist *s1)
 {
        /*
         * This is definitely not the best way to do this, but the
@@ -6845,9 +7284,11 @@ xfer_to_a(compiler_state_t *cstate, struct arth *a)
  * (1, 2, or 4) at that offset into that register, making it the register
  * for "index".
  */
-struct arth *
-gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
+static struct arth *
+gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst,
+    bpf_u_int32 size)
 {
+       int size_code;
        struct slist *s, *tmp;
        struct block *b;
        int regno = alloc_reg(cstate);
@@ -6857,22 +7298,23 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
 
        default:
                bpf_error(cstate, "data size must be 1, 2, or 4");
+               /*NOTREACHED*/
 
        case 1:
-               size = BPF_B;
+               size_code = BPF_B;
                break;
 
        case 2:
-               size = BPF_H;
+               size_code = BPF_H;
                break;
 
        case 4:
-               size = BPF_W;
+               size_code = BPF_W;
                break;
        }
        switch (proto) {
        default:
-               bpf_error(cstate, "unsupported index operation");
+               bpf_error(cstate, "'%s' does not support the index operation", pqkw(proto));
 
        case Q_RADIO:
                /*
@@ -6894,7 +7336,7 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
                /*
                 * Load the item at that offset.
                 */
-               tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+               tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
                sappend(s, tmp);
                sappend(inst->s, s);
                break;
@@ -6936,7 +7378,7 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
                 * variable-length; that header length is what we put
                 * into the X register and then added to the index).
                 */
-               tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+               tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
                tmp->s.k = cstate->off_linkhdr.constant_part;
                sappend(s, tmp);
                sappend(inst->s, s);
@@ -6983,7 +7425,7 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
                 * payload, and the constant part of the offset of the
                 * start of the link-layer payload.
                 */
-               tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+               tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
                tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
                sappend(s, tmp);
                sappend(inst->s, s);
@@ -6992,7 +7434,7 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
                 * Do the computation only if the packet contains
                 * the protocol in question.
                 */
-               b = gen_proto_abbrev(cstate, proto);
+               b = gen_proto_abbrev_internal(cstate, proto);
                if (inst->b)
                        gen_and(inst->b, b);
                inst->b = b;
@@ -7040,7 +7482,7 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
                sappend(s, xfer_to_a(cstate, inst));
                sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
                sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
-               sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size));
+               sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code));
                tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
                sappend(inst->s, s);
 
@@ -7050,15 +7492,61 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
                 * if this is an IP datagram and is the first or
                 * only fragment of that datagram.
                 */
-               gen_and(gen_proto_abbrev(cstate, proto), b = gen_ipfrag(cstate));
+               gen_and(gen_proto_abbrev_internal(cstate, proto), b = gen_ipfrag(cstate));
                if (inst->b)
                        gen_and(inst->b, b);
-               gen_and(gen_proto_abbrev(cstate, Q_IP), b);
+               gen_and(gen_proto_abbrev_internal(cstate, Q_IP), b);
                inst->b = b;
                break;
        case Q_ICMPV6:
-               bpf_error(cstate, "IPv6 upper-layer protocol is not supported by proto[x]");
-               /*NOTREACHED*/
+               /*
+                * Do the computation only if the packet contains
+                * the protocol in question.
+                */
+               b = gen_proto_abbrev_internal(cstate, Q_IPV6);
+               if (inst->b)
+                       gen_and(inst->b, b);
+               inst->b = b;
+
+               /*
+                * Check if we have an icmp6 next header
+                */
+               b = gen_ip6_proto(cstate, 58);
+               if (inst->b)
+                       gen_and(inst->b, b);
+               inst->b = b;
+
+               s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+               /*
+                * If "s" is non-null, it has code to arrange that the
+                * X register contains the variable part of the offset
+                * of the link-layer payload.  Add to it the offset
+                * computed into the register specified by "index",
+                * and move that into the X register.  Otherwise, just
+                * load into the X register the offset computed into
+                * the register specified by "index".
+                */
+               if (s != NULL) {
+                       sappend(s, xfer_to_a(cstate, inst));
+                       sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+                       sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+               } else
+                       s = xfer_to_x(cstate, inst);
+
+               /*
+                * Load the item at the sum of the offset we've put in the
+                * X register, the offset of the start of the network
+                * layer header from the beginning of the link-layer
+                * payload, and the constant part of the offset of the
+                * start of the link-layer payload.
+                */
+               tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+               tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40;
+
+               sappend(s, tmp);
+               sappend(inst->s, s);
+
+               break;
        }
        inst->regno = regno;
        s = new_stmt(cstate, BPF_ST);
@@ -7068,8 +7556,22 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
        return inst;
 }
 
-struct block *
-gen_relation(compiler_state_t *cstate, int code, struct arth *a0,
+struct arth *
+gen_load(compiler_state_t *cstate, int proto, struct arth *inst,
+    bpf_u_int32 size)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       return gen_load_internal(cstate, proto, inst, size);
+}
+
+static struct block *
+gen_relation_internal(compiler_state_t *cstate, int code, struct arth *a0,
     struct arth *a1, int reversed)
 {
        struct slist *s0, *s1, *s2;
@@ -7112,13 +7614,36 @@ gen_relation(compiler_state_t *cstate, int code, struct arth *a0,
        return b;
 }
 
+struct block *
+gen_relation(compiler_state_t *cstate, int code, struct arth *a0,
+    struct arth *a1, int reversed)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       return gen_relation_internal(cstate, code, a0, a1, reversed);
+}
+
 struct arth *
 gen_loadlen(compiler_state_t *cstate)
 {
-       int regno = alloc_reg(cstate);
-       struct arth *a = (struct arth *)newchunk(cstate, sizeof(*a));
+       int regno;
+       struct arth *a;
        struct slist *s;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       regno = alloc_reg(cstate);
+       a = (struct arth *)newchunk(cstate, sizeof(*a));
        s = new_stmt(cstate, BPF_LD|BPF_LEN);
        s->next = new_stmt(cstate, BPF_ST);
        s->next->s.k = regno;
@@ -7128,8 +7653,8 @@ gen_loadlen(compiler_state_t *cstate)
        return a;
 }
 
-struct arth *
-gen_loadi(compiler_state_t *cstate, int val)
+static struct arth *
+gen_loadi_internal(compiler_state_t *cstate, bpf_u_int32 val)
 {
        struct arth *a;
        struct slist *s;
@@ -7150,10 +7675,36 @@ gen_loadi(compiler_state_t *cstate, int val)
 }
 
 struct arth *
-gen_neg(compiler_state_t *cstate, struct arth *a)
+gen_loadi(compiler_state_t *cstate, bpf_u_int32 val)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       return gen_loadi_internal(cstate, val);
+}
+
+/*
+ * The a_arg dance is to avoid annoying whining by compilers that
+ * a might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct arth *
+gen_neg(compiler_state_t *cstate, struct arth *a_arg)
 {
+       struct arth *a = a_arg;
        struct slist *s;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        s = xfer_to_a(cstate, a);
        sappend(a->s, s);
        s = new_stmt(cstate, BPF_ALU|BPF_NEG);
@@ -7166,15 +7717,31 @@ gen_neg(compiler_state_t *cstate, struct arth *a)
        return a;
 }
 
+/*
+ * The a0_arg dance is to avoid annoying whining by compilers that
+ * a0 might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
 struct arth *
-gen_arth(compiler_state_t *cstate, int code, struct arth *a0,
+gen_arth(compiler_state_t *cstate, int code, struct arth *a0_arg,
     struct arth *a1)
 {
+       struct arth *a0 = a0_arg;
        struct slist *s0, *s1, *s2;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Disallow division by, or modulus by, zero; we do this here
         * so that it gets done even if the optimizer is disabled.
+        *
+        * Also disallow shifts by a value greater than 31; we do this
+        * here, for the same reason.
         */
        if (code == BPF_DIV) {
                if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
@@ -7182,6 +7749,9 @@ gen_arth(compiler_state_t *cstate, int code, struct arth *a0,
        } else if (code == BPF_MOD) {
                if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
                        bpf_error(cstate, "modulus by zero");
+       } else if (code == BPF_LSH || code == BPF_RSH) {
+               if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k > 31)
+                       bpf_error(cstate, "shift by more than 31 bits");
        }
        s0 = xfer_to_x(cstate, a1);
        s1 = xfer_to_a(cstate, a0);
@@ -7229,8 +7799,7 @@ alloc_reg(compiler_state_t *cstate)
                }
        }
        bpf_error(cstate, "too many registers needed to evaluate expression");
-       /* NOTREACHED */
-       return 0;
+       /*NOTREACHED*/
 }
 
 /*
@@ -7247,19 +7816,21 @@ 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 *
 gen_greater(compiler_state_t *cstate, int n)
 {
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        return gen_len(cstate, BPF_JGE, n);
 }
 
@@ -7271,6 +7842,13 @@ gen_less(compiler_state_t *cstate, int n)
 {
        struct block *b;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        b = gen_len(cstate, BPF_JGT, n);
        gen_not(b);
 
@@ -7288,25 +7866,32 @@ gen_less(compiler_state_t *cstate, int n)
  * would generate code appropriate to the radio header in question.
  */
 struct block *
-gen_byteop(compiler_state_t *cstate, int op, int idx, int val)
+gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
 {
        struct block *b;
        struct slist *s;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       assert_maxval(cstate, "byte argument", val, UINT8_MAX);
+
        switch (op) {
        default:
                abort();
 
        case '=':
-               return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_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, (bpf_int32)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, (bpf_int32)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);
@@ -7317,15 +7902,15 @@ gen_byteop(compiler_state_t *cstate, int op, int idx, int 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;
 }
 
-static const u_char abroadcast[] = { 0x0 };
-
 struct block *
 gen_broadcast(compiler_state_t *cstate, int proto)
 {
@@ -7333,6 +7918,13 @@ gen_broadcast(compiler_state_t *cstate, int proto)
        struct block *b0, *b1, *b2;
        static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        switch (proto) {
 
        case Q_DEFAULT:
@@ -7340,31 +7932,11 @@ gen_broadcast(compiler_state_t *cstate, int proto)
                switch (cstate->linktype) {
                case DLT_ARCNET:
                case DLT_ARCNET_LINUX:
-                       return gen_ahostop(cstate, abroadcast, 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");
+                       // ARCnet broadcast is [8-bit] destination address 0.
+                       return gen_ahostop(cstate, 0, Q_DST);
                }
-               break;
+               return gen_mac48host(cstate, ebroadcast, Q_DST, "broadcast");
+               /*NOTREACHED*/
 
        case Q_IP:
                /*
@@ -7376,16 +7948,14 @@ gen_broadcast(compiler_state_t *cstate, int proto)
                        bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported");
                b0 = gen_linktype(cstate, ETHERTYPE_IP);
                hostmask = ~cstate->netmask;
-               b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, (bpf_int32)0, hostmask);
-               b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W,
-                             (bpf_int32)(~0 & hostmask), hostmask);
+               b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, 0, hostmask);
+               b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, hostmask, hostmask);
                gen_or(b1, b2);
                gen_and(b0, b2);
                return b2;
        }
-       bpf_error(cstate, "only link-layer/IP broadcast filters supported");
-       /* NOTREACHED */
-       return NULL;
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "broadcast");
+       /*NOTREACHED*/
 }
 
 /*
@@ -7395,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 *
@@ -7412,6 +7978,13 @@ gen_multicast(compiler_state_t *cstate, int proto)
        register struct block *b0, *b1, *b2;
        register struct slist *s;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        switch (proto) {
 
        case Q_DEFAULT:
@@ -7419,8 +7992,8 @@ gen_multicast(compiler_state_t *cstate, int proto)
                switch (cstate->linktype) {
                case DLT_ARCNET:
                case DLT_ARCNET_LINUX:
-                       /* all ARCnet multicasts use the same address */
-                       return gen_ahostop(cstate, abroadcast, Q_DST);
+                       // ARCnet multicast is the same as broadcast.
+                       return gen_ahostop(cstate, 0, Q_DST);
                case DLT_EN10MB:
                case DLT_NETANALYZER:
                case DLT_NETANALYZER_TRANSPARENT:
@@ -7468,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.
@@ -7483,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.
@@ -7505,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.
@@ -7520,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.
@@ -7547,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
@@ -7559,33 +8119,80 @@ 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);
-               b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, (bpf_int32)224);
+               b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, 224);
                gen_and(b0, b1);
                return b1;
 
        case Q_IPV6:
                b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
-               b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, (bpf_int32)255);
+               b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, 255);
                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");
-       /* NOTREACHED */
-       return NULL;
+       bpf_error(cstate, ERRSTR_INVALID_QUAL, pqkw(proto), "multicast");
+       /*NOTREACHED*/
+}
+
+#ifdef __linux__
+/*
+ * This is Linux; we require PF_PACKET support.  If this is a *live* capture,
+ * we can look at special meta-data in the filter expression; otherwise we
+ * can't because it is either a savefile (rfile != NULL) or a pcap_t created
+ * using pcap_open_dead() (rfile == NULL).  Thus check for a flag that
+ * pcap_activate() conditionally sets.
+ */
+static void
+require_basic_bpf_extensions(compiler_state_t *cstate, const char *keyword)
+{
+       if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_BASIC_HANDLING)
+               return;
+       bpf_error(cstate, "%s not supported on %s (not a live capture)",
+           keyword,
+           pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+}
+#endif // __linux__
+
+struct block *
+gen_ifindex(compiler_state_t *cstate, int ifindex)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       /*
+        * Only some data link types support ifindex qualifiers.
+        */
+       switch (cstate->linktype) {
+       case DLT_LINUX_SLL2:
+               /* match packets on this interface */
+               return gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex);
+       default:
+#if defined(__linux__)
+               require_basic_bpf_extensions(cstate, "ifindex");
+               /* match ifindex */
+               return gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W,
+                            ifindex);
+#else /* defined(__linux__) */
+               fail_kw_on_dlt(cstate, "ifindex");
+               /*NOTREACHED*/
+#endif /* defined(__linux__) */
+       }
 }
 
 /*
- * Filter on inbound (dir == 0) or outbound (dir == 1) traffic.
+ * Filter on inbound (outbound == 0) or outbound (outbound == 1) traffic.
  * Outbound traffic is sent by this machine, while inbound traffic is
  * sent by a remote machine (and may include packets destined for a
  * unicast or multicast link-layer address we are not subscribing to).
@@ -7594,291 +8201,240 @@ gen_multicast(compiler_state_t *cstate, int proto)
  * better accomplished using a higher-layer filter.
  */
 struct block *
-gen_inbound(compiler_state_t *cstate, int dir)
+gen_inbound_outbound(compiler_state_t *cstate, const int outbound)
 {
        register struct block *b0;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Only some data link types support inbound/outbound qualifiers.
         */
        switch (cstate->linktype) {
        case DLT_SLIP:
-               b0 = gen_relation(cstate, BPF_JEQ,
-                         gen_load(cstate, Q_LINK, gen_loadi(cstate, 0), 1),
-                         gen_loadi(cstate, 0),
-                         dir);
-               break;
+               return gen_cmp(cstate, OR_LINKHDR, 0, BPF_B,
+                         outbound ? SLIPDIR_OUT : SLIPDIR_IN);
 
        case DLT_IPNET:
-               if (dir) {
-                       /* match outgoing packets */
-                       b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND);
-               } else {
-                       /* match incoming packets */
-                       b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_INBOUND);
-               }
-               break;
+               return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H,
+                   outbound ? IPNET_OUTBOUND : IPNET_INBOUND);
 
        case DLT_LINUX_SLL:
                /* match outgoing packets */
                b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING);
-               if (!dir) {
+               if (! outbound) {
                        /* to filter on inbound traffic, invert the match */
                        gen_not(b0);
                }
-               break;
+               return b0;
+
+       case DLT_LINUX_SLL2:
+               /* match outgoing packets */
+               b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING);
+               if (! outbound) {
+                       /* to filter on inbound traffic, invert the match */
+                       gen_not(b0);
+               }
+               return b0;
 
-#ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
-               b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
-                   (bpf_int32)((dir == 0) ? PF_IN : PF_OUT));
-               break;
-#endif
+               return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
+                   outbound ? PF_OUT : PF_IN);
 
        case DLT_PPP_PPPD:
-               if (dir) {
-                       /* match outgoing packets */
-                       b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT);
-               } else {
-                       /* match incoming packets */
-                       b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, 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:
-        case DLT_JUNIPER_MLPPP:
+       case DLT_JUNIPER_MFR:
+       case DLT_JUNIPER_MLFR:
+       case DLT_JUNIPER_MLPPP:
        case DLT_JUNIPER_ATM1:
        case DLT_JUNIPER_ATM2:
        case DLT_JUNIPER_PPPOE:
        case DLT_JUNIPER_PPPOE_ATM:
-        case DLT_JUNIPER_GGSN:
-        case DLT_JUNIPER_ES:
-        case DLT_JUNIPER_MONITOR:
-        case DLT_JUNIPER_SERVICES:
-        case DLT_JUNIPER_ETHER:
-        case DLT_JUNIPER_PPP:
-        case DLT_JUNIPER_FRELAY:
-        case DLT_JUNIPER_CHDLC:
-        case DLT_JUNIPER_VP:
-        case DLT_JUNIPER_ST:
-        case DLT_JUNIPER_ISM:
-        case DLT_JUNIPER_VS:
-        case DLT_JUNIPER_SRX_E2E:
-        case DLT_JUNIPER_FIBRECHANNEL:
+       case DLT_JUNIPER_GGSN:
+       case DLT_JUNIPER_ES:
+       case DLT_JUNIPER_MONITOR:
+       case DLT_JUNIPER_SERVICES:
+       case DLT_JUNIPER_ETHER:
+       case DLT_JUNIPER_PPP:
+       case DLT_JUNIPER_FRELAY:
+       case DLT_JUNIPER_CHDLC:
+       case DLT_JUNIPER_VP:
+       case DLT_JUNIPER_ST:
+       case DLT_JUNIPER_ISM:
+       case DLT_JUNIPER_VS:
+       case DLT_JUNIPER_SRX_E2E:
+       case DLT_JUNIPER_FIBRECHANNEL:
        case DLT_JUNIPER_ATM_CEMIC:
-
                /* juniper flags (including direction) are stored
                 * the byte after the 3-byte magic number */
-               if (dir) {
-                       /* match outgoing packets */
-                       b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 0, 0x01);
-               } else {
-                       /* match incoming packets */
-                       b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 1, 0x01);
-               }
-               break;
+               return gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, outbound ? 0 : 1, 0x01);
 
        default:
                /*
                 * If we have packet meta-data indicating a direction,
-                * check it, otherwise give up as this link-layer type
-                * has nothing in the packet data.
-                */
-#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
-               /*
-                * This is Linux with PF_PACKET support.
-                * If this is a *live* capture, we can look at
-                * special meta-data in the filter expression;
-                * if it's a savefile, we can't.
-                */
-               if (cstate->bpf_pcap->rfile != NULL) {
-                       /* We have a FILE *, so this is a savefile */
-                       bpf_error(cstate, "inbound/outbound not supported on linktype %d when reading savefiles",
-                           cstate->linktype);
-                       b0 = NULL;
-                       /* NOTREACHED */
-               }
+                * and that metadata can be checked by BPF code, check
+                * it.  Otherwise, give up, as this link-layer type has
+                * nothing in the packet data.
+                *
+                * Currently, the only platform where a BPF filter can
+                * check that metadata is Linux with the in-kernel
+                * BPF interpreter.  If other packet capture mechanisms
+                * and BPF filters also supported this, it would be
+                * nice.  It would be even better if they made that
+                * metadata available so that we could provide it
+                * with newer capture APIs, allowing it to be saved
+                * in pcapng files.
+                */
+#if defined(__linux__)
+               require_basic_bpf_extensions(cstate, outbound ? "outbound" : "inbound");
                /* match outgoing packets */
                b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H,
                             PACKET_OUTGOING);
-               if (!dir) {
+               if (! outbound) {
                        /* to filter on inbound traffic, invert the match */
                        gen_not(b0);
                }
-#else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
-               bpf_error(cstate, "inbound/outbound not supported on linktype %d",
-                   cstate->linktype);
-               b0 = NULL;
-               /* NOTREACHED */
-#endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
+               return b0;
+#else /* defined(__linux__) */
+               fail_kw_on_dlt(cstate, outbound ? "outbound" : "inbound");
+               /*NOTREACHED*/
+#endif /* defined(__linux__) */
        }
-       return (b0);
 }
 
-#ifdef HAVE_NET_PFVAR_H
 /* PF firewall log matched interface */
 struct block *
 gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
 {
-       struct block *b0;
        u_int len, off;
 
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "ifname supported only on PF linktype");
-               /* NOTREACHED */
-       }
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       assert_pflog(cstate, "ifname");
+
        len = sizeof(((struct pfloghdr *)0)->ifname);
        off = offsetof(struct pfloghdr, ifname);
        if (strlen(ifname) >= len) {
                bpf_error(cstate, "ifname interface names can only be %d characters",
                    len-1);
-               /* NOTREACHED */
+               /*NOTREACHED*/
        }
-       b0 = gen_bcmp(cstate, OR_LINKHDR, off, strlen(ifname), (const u_char *)ifname);
-       return (b0);
+       return gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname),
+           (const u_char *)ifname);
 }
 
 /* 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.
+        */
+       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",
                    (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1));
-               /* NOTREACHED */
+               /*NOTREACHED*/
        }
 
-       b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset),
-           strlen(ruleset), (const u_char *)ruleset);
-       return (b0);
+       return gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset),
+           (u_int)strlen(ruleset), (const u_char *)ruleset);
 }
 
 /* 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.
+        */
+       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,
-                (bpf_int32)rnr);
-       return (b0);
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
+                (bpf_u_int32)rnr);
 }
 
 /* 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.
+        */
+       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,
-           (bpf_int32)srnr);
-       return (b0);
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
+           (bpf_u_int32)srnr);
 }
 
 /* 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.
+        */
+       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,
-           (bpf_int32)reason);
-       return (b0);
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
+           (bpf_u_int32)reason);
 }
 
 /* PF firewall log action */
 struct block *
 gen_pf_action(compiler_state_t *cstate, int action)
 {
-       struct block *b0;
-
-       if (cstate->linktype != DLT_PFLOG) {
-               bpf_error(cstate, "action supported only on PF linktype");
-               /* NOTREACHED */
-       }
-
-       b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
-           (bpf_int32)action);
-       return (b0);
-}
-#else /* !HAVE_NET_PFVAR_H */
-struct block *
-gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
-{
-       bpf_error(cstate, "libpcap was compiled without pf support");
-       /* NOTREACHED */
-       return (NULL);
-}
-
-struct block *
-gen_pf_ruleset(compiler_state_t *cstate, char *ruleset)
-{
-       bpf_error(cstate, "libpcap was compiled on a machine without pf support");
-       /* NOTREACHED */
-       return (NULL);
-}
-
-struct block *
-gen_pf_rnr(compiler_state_t *cstate, int rnr)
-{
-       bpf_error(cstate, "libpcap was compiled on a machine without pf support");
-       /* NOTREACHED */
-       return (NULL);
-}
-
-struct block *
-gen_pf_srnr(compiler_state_t *cstate, int srnr)
-{
-       bpf_error(cstate, "libpcap was compiled on a machine without pf support");
-       /* NOTREACHED */
-       return (NULL);
-}
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
 
-struct block *
-gen_pf_reason(compiler_state_t *cstate, int reason)
-{
-       bpf_error(cstate, "libpcap was compiled on a machine without pf support");
-       /* NOTREACHED */
-       return (NULL);
-}
+       assert_pflog(cstate, "action");
 
-struct block *
-gen_pf_action(compiler_state_t *cstate, int action)
-{
-       bpf_error(cstate, "libpcap was compiled on a machine without pf support");
-       /* NOTREACHED */
-       return (NULL);
+       return gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
+           (bpf_u_int32)action);
 }
-#endif /* HAVE_NET_PFVAR_H */
 
 /* IEEE 802.11 wireless header */
 struct block *
-gen_p80211_type(compiler_state_t *cstate, int type, int mask)
+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.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
 
        switch (cstate->linktype) {
 
@@ -7886,22 +8442,24 @@ gen_p80211_type(compiler_state_t *cstate, int type, int 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, (bpf_int32)type,
-                   (bpf_int32)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");
-               /* NOTREACHED */
+               fail_kw_on_dlt(cstate, "type/subtype");
+               /*NOTREACHED*/
        }
-
-       return (b0);
 }
 
 struct block *
-gen_p80211_fcdir(compiler_state_t *cstate, int fcdir)
+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.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
 
        switch (cstate->linktype) {
 
@@ -7909,56 +8467,72 @@ gen_p80211_fcdir(compiler_state_t *cstate, int 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");
-               /* NOTREACHED */
+               fail_kw_on_dlt(cstate, "dir");
+               /*NOTREACHED*/
        }
-
-       b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir,
-               (bpf_u_int32)IEEE80211_FC1_DIR_MASK);
-
-       return (b0);
 }
 
+// Process an ARCnet host address string.
 struct block *
-gen_acode(compiler_state_t *cstate, const u_char *eaddr, struct qual q)
+gen_acode(compiler_state_t *cstate, const char *s, struct qual q)
 {
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        switch (cstate->linktype) {
 
        case DLT_ARCNET:
        case DLT_ARCNET_LINUX:
                if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) &&
-                   q.proto == Q_LINK)
-                       return (gen_ahostop(cstate, eaddr, (int)q.dir));
-               else {
+                   q.proto == Q_LINK) {
+                       uint8_t addr;
+                       /*
+                        * The lexer currently defines the address format in a
+                        * way that makes this error condition never true.
+                        * Let's check it anyway in case this part of the lexer
+                        * changes in future.
+                        */
+                       if (! pcapint_atoan(s, &addr))
+                           bpf_error(cstate, "invalid ARCnet address '%s'", s);
+                       return gen_ahostop(cstate, addr, (int)q.dir);
+               } else
                        bpf_error(cstate, "ARCnet address used in non-arc expression");
-                       /* NOTREACHED */
-               }
-               break;
+               /*NOTREACHED*/
 
        default:
                bpf_error(cstate, "aid supported only on ARCnet");
-               /* NOTREACHED */
+               /*NOTREACHED*/
        }
-       bpf_error(cstate, "ARCnet address used in non-arc expression");
-       /* NOTREACHED */
-       return NULL;
 }
 
+// Compare an ARCnet host address with the given value.
 static struct block *
-gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+gen_ahostop(compiler_state_t *cstate, const uint8_t eaddr, int dir)
 {
        register struct block *b0, *b1;
 
        switch (dir) {
-       /* src comes first, different from Ethernet */
+       /*
+        * ARCnet is different from Ethernet: the source address comes before
+        * the destination address, each is one byte long.  This holds for all
+        * three "buffer formats" in RFC 1201 Section 2.1, see also page 4-10
+        * in the 1983 edition of the "ARCNET Designer's Handbook" published
+        * by Datapoint (document number 61610-01).
+        */
        case Q_SRC:
-               return gen_bcmp(cstate, OR_LINKHDR, 0, 1, eaddr);
+               return gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, eaddr);
 
        case Q_DST:
-               return gen_bcmp(cstate, OR_LINKHDR, 1, 1, eaddr);
+               return gen_cmp(cstate, OR_LINKHDR, 1, BPF_B, eaddr);
 
        case Q_AND:
                b0 = gen_ahostop(cstate, eaddr, Q_SRC);
@@ -7974,31 +8548,16 @@ gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
                return b1;
 
        case Q_ADDR1:
-               bpf_error(cstate, "'addr1' is only supported on 802.11");
-               break;
-
        case Q_ADDR2:
-               bpf_error(cstate, "'addr2' is only supported on 802.11");
-               break;
-
        case Q_ADDR3:
-               bpf_error(cstate, "'addr3' is only supported on 802.11");
-               break;
-
        case Q_ADDR4:
-               bpf_error(cstate, "'addr4' is only supported on 802.11");
-               break;
-
        case Q_RA:
-               bpf_error(cstate, "'ra' is only supported on 802.11");
-               break;
-
        case Q_TA:
-               bpf_error(cstate, "'ta' is only supported on 802.11");
-               break;
+               bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
+               /*NOTREACHED*/
        }
        abort();
-       /* NOTREACHED */
+       /*NOTREACHED*/
 }
 
 static struct block *
@@ -8006,7 +8565,7 @@ gen_vlan_tpid_test(compiler_state_t *cstate)
 {
        struct block *b0, *b1;
 
-       /* check for VLAN, including QinQ */
+       /* check for VLAN, including 802.1ad and QinQ */
        b0 = gen_linktype(cstate, ETHERTYPE_8021Q);
        b1 = gen_linktype(cstate, ETHERTYPE_8021AD);
        gen_or(b0,b1);
@@ -8018,19 +8577,21 @@ gen_vlan_tpid_test(compiler_state_t *cstate)
 }
 
 static struct block *
-gen_vlan_vid_test(compiler_state_t *cstate, int vlan_num)
+gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num)
 {
-       return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff);
+       assert_maxval(cstate, "VLAN tag", vlan_num, 0x0fff);
+       return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff);
 }
 
 static struct block *
-gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num)
+gen_vlan_no_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
+    int has_vlan_tag)
 {
        struct block *b0, *b1;
 
        b0 = gen_vlan_tpid_test(cstate);
 
-       if (vlan_num >= 0) {
+       if (has_vlan_tag) {
                b1 = gen_vlan_vid_test(cstate, vlan_num);
                gen_and(b0, b1);
                b0 = b1;
@@ -8046,10 +8607,11 @@ gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num)
        return b0;
 }
 
-#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
 /* add v to variable part of off */
 static void
-gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, int v, struct slist *s)
+gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off,
+    bpf_u_int32 v, struct slist *s)
 {
        struct slist *s2;
 
@@ -8100,7 +8662,7 @@ gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid)
        unsigned cnt;
 
        s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
-       s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+       s->s.k = (bpf_u_int32)(SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT);
 
        /* true -> next instructions, false -> beginning of b_vid */
        sjeq = new_stmt(cstate, JMP(BPF_JEQ));
@@ -8108,17 +8670,20 @@ gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid)
        sjeq->s.jf = b_vid->stmts;
        sappend(s, sjeq);
 
-       s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
-       s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
+       s2 = new_stmt(cstate, BPF_LD|BPF_H|BPF_ABS);
+       s2->s.k = (bpf_u_int32)(SKF_AD_OFF + SKF_AD_VLAN_TAG);
        sappend(s, s2);
        sjeq->s.jt = s2;
 
-       /* jump to the test in b_vid (bypass loading VID from packet data) */
+       /* Jump to the test in b_vid. We need to jump one instruction before
+        * the end of the b_vid block so that we only skip loading the TCI
+        * from packet data and not the 'and' instruction extracting VID.
+        */
        cnt = 0;
        for (s2 = b_vid->stmts; s2; s2 = s2->next)
                cnt++;
        s2 = new_stmt(cstate, JMP(BPF_JA));
-       s2->s.k = cnt;
+       s2->s.k = cnt - 1;
        sappend(s, s2);
 
        /* insert our statements at the beginning of b_vid */
@@ -8135,23 +8700,22 @@ gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid)
  * update variable part of the offsets
  */
 static struct block *
-gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
+gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
+    int has_vlan_tag)
 {
-        struct block *b0, *b_tpid, *b_vid;
-        struct slist *s;
+       struct block *b0, *b_tpid, *b_vid = NULL;
+       struct slist *s;
 
-        /* generate new filter code based on extracting packet
-         * metadata */
-        s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
-        s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+       /* generate new filter code based on extracting packet
+        * metadata */
+       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
-        * parts of offsets before the the traditional TPID and VID tests so
+        * parts of offsets before the traditional TPID and VID tests so
         * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but
         * we do not want this update to affect those checks. That's why we
         * generate both test blocks first and insert the statements updating
@@ -8160,20 +8724,20 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
         * function but gen_vlan_bpf_extensions() isn't called in that case.
         */
        b_tpid = gen_vlan_tpid_test(cstate);
-       if (vlan_num >= 0)
+       if (has_vlan_tag)
                b_vid = gen_vlan_vid_test(cstate, vlan_num);
 
        gen_vlan_patch_tpid_test(cstate, b_tpid);
        gen_or(b0, b_tpid);
        b0 = b_tpid;
 
-       if (vlan_num >= 0) {
+       if (has_vlan_tag) {
                gen_vlan_patch_vid_test(cstate, b_vid);
                gen_and(b0, b_vid);
                b0 = b_vid;
        }
 
-        return b0;
+       return b0;
 }
 #endif
 
@@ -8181,10 +8745,17 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
  * support IEEE 802.1Q VLAN trunk over ethernet
  */
 struct block *
-gen_vlan(compiler_state_t *cstate, int vlan_num)
+gen_vlan(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag)
 {
        struct  block   *b0;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /* can't check for VLAN-encapsulated packets inside MPLS */
        if (cstate->label_stack_depth > 0)
                bpf_error(cstate, "no VLAN match after MPLS");
@@ -8193,7 +8764,7 @@ gen_vlan(compiler_state_t *cstate, int vlan_num)
         * Check for a VLAN packet, and then change the offsets to point
         * to the type and data fields within the VLAN packet.  Just
         * increment the offsets, so that we can support a hierarchy, e.g.
-        * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within
+        * "vlan 100 && vlan 200" to capture VLAN 200 encapsulated within
         * VLAN 100.
         *
         * XXX - this is a bit of a kludge.  If we were to split the
@@ -8223,9 +8794,14 @@ gen_vlan(compiler_state_t *cstate, int vlan_num)
        switch (cstate->linktype) {
 
        case DLT_EN10MB:
-       case DLT_NETANALYZER:
-       case DLT_NETANALYZER_TRANSPARENT:
-#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
+               /*
+                * Newer version of the Linux kernel pass around
+                * packets in which the VLAN tag has been removed
+                * from the packet data and put into metadata.
+                *
+                * This requires special treatment.
+                */
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
                /* Verify that this is the outer part of the packet and
                 * not encapsulated somehow. */
                if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable &&
@@ -8235,127 +8811,189 @@ gen_vlan(compiler_state_t *cstate, int vlan_num)
                         * Do we need special VLAN handling?
                         */
                        if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING)
-                               b0 = gen_vlan_bpf_extensions(cstate, vlan_num);
+                               b0 = gen_vlan_bpf_extensions(cstate, vlan_num,
+                                   has_vlan_tag);
                        else
-                               b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num);
+                               b0 = gen_vlan_no_bpf_extensions(cstate,
+                                   vlan_num, has_vlan_tag);
                } else
 #endif
-                       b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num);
-                break;
+                       b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num,
+                           has_vlan_tag);
+               break;
 
+       case DLT_NETANALYZER:
+       case DLT_NETANALYZER_TRANSPARENT:
        case DLT_IEEE802_11:
        case DLT_PRISM_HEADER:
        case DLT_IEEE802_11_RADIO_AVS:
        case DLT_IEEE802_11_RADIO:
-               b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num);
+               /*
+                * These are either Ethernet packets with an additional
+                * metadata header (the NetAnalyzer types), or 802.11
+                * packets, possibly with an additional metadata header.
+                *
+                * For the first of those, the VLAN tag is in the normal
+                * place, so the special-case handling above isn't
+                * necessary.
+                *
+                * For the second of those, we don't do the special-case
+                * handling for now.
+                */
+               b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag);
                break;
 
        default:
-               bpf_error(cstate, "no VLAN support for data link type %d",
-                     cstate->linktype);
+               bpf_error(cstate, "no VLAN support for %s",
+                     pcap_datalink_val_to_description_or_dlt(cstate->linktype));
                /*NOTREACHED*/
        }
 
-        cstate->vlan_stack_depth++;
+       cstate->vlan_stack_depth++;
 
        return (b0);
 }
 
 /*
  * support for MPLS
+ *
+ * The label_num_arg dance is to avoid annoying whining by compilers that
+ * label_num might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
  */
-struct block *
-gen_mpls(compiler_state_t *cstate, int label_num)
+static struct block *
+gen_mpls_internal(compiler_state_t *cstate, bpf_u_int32 label_num,
+    int has_label_num)
 {
        struct  block   *b0, *b1;
 
-        if (cstate->label_stack_depth > 0) {
-            /* just match the bottom-of-stack bit clear */
-            b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01);
-        } else {
-            /*
-             * We're not in an MPLS stack yet, so check the link-layer
-             * type against MPLS.
-             */
-            switch (cstate->linktype) {
-
-            case DLT_C_HDLC: /* fall through */
-            case DLT_EN10MB:
-            case DLT_NETANALYZER:
-            case DLT_NETANALYZER_TRANSPARENT:
-                    b0 = gen_linktype(cstate, ETHERTYPE_MPLS);
-                    break;
-
-            case DLT_PPP:
-                    b0 = gen_linktype(cstate, PPP_MPLS_UCAST);
-                    break;
-
-                    /* FIXME add other DLT_s ...
-                     * for Frame-Relay/and ATM this may get messy due to SNAP headers
-                     * leave it for now */
-
-            default:
-                    bpf_error(cstate, "no MPLS support for data link type %d",
-                          cstate->linktype);
-                    b0 = NULL;
-                    /*NOTREACHED*/
-                    break;
-            }
-        }
+       if (cstate->label_stack_depth > 0) {
+               /* just match the bottom-of-stack bit clear */
+               b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01);
+       } else {
+               /*
+                * We're not in an MPLS stack yet, so check the link-layer
+                * type against MPLS.
+                */
+               switch (cstate->linktype) {
+
+               case DLT_C_HDLC: /* fall through */
+               case DLT_HDLC:
+               case DLT_EN10MB:
+               case DLT_NETANALYZER:
+               case DLT_NETANALYZER_TRANSPARENT:
+                       b0 = gen_linktype(cstate, ETHERTYPE_MPLS);
+                       break;
+
+               case DLT_PPP:
+                       b0 = gen_linktype(cstate, PPP_MPLS_UCAST);
+                       break;
+
+                       /* FIXME add other DLT_s ...
+                        * for Frame-Relay/and ATM this may get messy due to SNAP headers
+                        * leave it for now */
+
+               default:
+                       bpf_error(cstate, "no MPLS support for %s",
+                           pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+                       /*NOTREACHED*/
+               }
+       }
 
        /* If a specific MPLS label is requested, check it */
-       if (label_num >= 0) {
+       if (has_label_num) {
+               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, (bpf_int32)label_num,
+               b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num,
                    0xfffff000); /* only compare the first 20 bits */
                gen_and(b0, b1);
                b0 = b1;
        }
 
-        /*
-         * Change the offsets to point to the type and data fields within
-         * the MPLS packet.  Just increment the offsets, so that we
-         * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to
-         * capture packets with an outer label of 100000 and an inner
-         * label of 1024.
-         *
-         * Increment the MPLS stack depth as well; this indicates that
-         * we're checking MPLS-encapsulated headers, to make sure higher
-         * level code generators don't try to match against IP-related
-         * protocols such as Q_ARP, Q_RARP etc.
-         *
-         * XXX - this is a bit of a kludge.  See comments in gen_vlan().
-         */
-        cstate->off_nl_nosnap += 4;
-        cstate->off_nl += 4;
-        cstate->label_stack_depth++;
+       /*
+        * Change the offsets to point to the type and data fields within
+        * the MPLS packet.  Just increment the offsets, so that we
+        * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to
+        * capture packets with an outer label of 100000 and an inner
+        * label of 1024.
+        *
+        * Increment the MPLS stack depth as well; this indicates that
+        * we're checking MPLS-encapsulated headers, to make sure higher
+        * level code generators don't try to match against IP-related
+        * protocols such as Q_ARP, Q_RARP etc.
+        *
+        * XXX - this is a bit of a kludge.  See comments in gen_vlan().
+        */
+       cstate->off_nl_nosnap += 4;
+       cstate->off_nl += 4;
+       cstate->label_stack_depth++;
        return (b0);
 }
 
+struct block *
+gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num, int has_label_num)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       return gen_mpls_internal(cstate, label_num, has_label_num);
+}
+
 /*
  * Support PPPOE discovery and session.
  */
 struct block *
 gen_pppoed(compiler_state_t *cstate)
 {
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /* check for PPPoE discovery */
-       return gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOED);
+       return gen_linktype(cstate, ETHERTYPE_PPPOED);
 }
 
+/*
+ * RFC 2516 Section 4:
+ *
+ * The Ethernet payload for PPPoE is as follows:
+ *
+ *                      1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  VER  | TYPE  |      CODE     |          SESSION_ID           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            LENGTH             |           payload             ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
 struct block *
-gen_pppoes(compiler_state_t *cstate, int sess_num)
+gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
        /*
         * Test against the PPPoE session link-layer type.
         */
-       b0 = gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOES);
+       b0 = gen_linktype(cstate, ETHERTYPE_PPPOES);
 
        /* If a specific session is requested, check PPPoE session id */
-       if (sess_num >= 0) {
-               b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W,
-                   (bpf_int32)sess_num, 0x0000ffff);
+       if (has_sess_num) {
+               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;
        }
@@ -8365,29 +9003,8 @@ gen_pppoes(compiler_state_t *cstate, int sess_num)
         * the PPP packet, and note that this is PPPoE rather than
         * raw PPP.
         *
-        * XXX - this is a bit of a kludge.  If we were to split the
-        * compiler into a parser that parses an expression and
-        * generates an expression tree, and a code generator that
-        * takes an expression tree (which could come from our
-        * parser or from some other parser) and generates BPF code,
-        * we could perhaps make the offsets parameters of routines
-        * and, in the handler for an "AND" node, pass to subnodes
-        * other than the PPPoE node the adjusted offsets.
-        *
-        * This would mean that "pppoes" would, instead of changing the
-        * behavior of *all* tests after it, change only the behavior
-        * of tests ANDed with it.  That would change the documented
-        * semantics of "pppoes", which might break some expressions.
-        * However, it would mean that "(pppoes and ip) or ip" would check
-        * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than
-        * checking only for VLAN-encapsulated IP, so that could still
-        * be considered worth doing; it wouldn't break expressions
-        * that are of the form "pppoes and ..." which I suspect are the
-        * most common expressions involving "pppoes".  "pppoes or ..."
-        * doesn't necessarily do what the user would really want, now,
-        * as all the "or ..." tests would be done assuming PPPoE, even
-        * though the "or" could be viewed as meaning "or, if this isn't
-        * a PPPoE packet...".
+        * XXX - this is a bit of a kludge.  See the comments in
+        * gen_vlan().
         *
         * The "network-layer" protocol is PPPoE, which has a 6-byte
         * PPPoE header, followed by a PPP packet.
@@ -8416,24 +9033,292 @@ gen_pppoes(compiler_state_t *cstate, int 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 *, int, int, int),
-    enum e_offrel offrel, int vni)
+    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;
 
        b0 = gen_portfn(cstate, GENEVE_PORT, IPPROTO_UDP, Q_DST);
 
-       /* Check that we are operating on version 0. Otherwise, we
-        * can't decode the rest of the fields. The version is 2 bits
-        * in the first byte of the Geneve header. */
-       b1 = gen_mcmp(cstate, offrel, 8, BPF_B, (bpf_int32)0, 0xc0);
+       /* Check that we are operating on version 0. Otherwise, we
+        * can't decode the rest of the fields. The version is 2 bits
+        * in the first byte of the Geneve header. */
+       b1 = gen_mcmp(cstate, offrel, 8, BPF_B, 0, 0xc0);
+       gen_and(b0, b1);
+       b0 = b1;
+
+       if (has_vni) {
+               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);
+               b0 = b1;
+       }
+
+       return b0;
+}
+
+/* The IPv4 and IPv6 Geneve checks need to do two things:
+ * - Verify that this actually is Geneve with the right VNI.
+ * - Place the IP header length (plus variable link prefix if
+ *   needed) into register A to be used later to compute
+ *   the inner packet offsets. */
+static struct block *
+gen_geneve4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+       struct block *b0, *b1;
+       struct slist *s, *s1;
+
+       b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni, has_vni);
+
+       /* Load the IP header length into A. */
+       s = gen_loadx_iphdrlen(cstate);
+
+       s1 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+       sappend(s, s1);
+
+       /* 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 = gen_jmp(cstate, BPF_JMP|BPF_JEQ|BPF_X, 0, s);
+
+       gen_and(b0, b1);
+
+       return b1;
+}
+
+static struct block *
+gen_geneve6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+       struct block *b0, *b1;
+       struct slist *s, *s1;
+
+       b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni, has_vni);
+
+       /* Load the IP header length. We need to account for a
+        * variable length link prefix if there is one. */
+       s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+       if (s) {
+               s1 = new_stmt(cstate, BPF_LD|BPF_IMM);
+               s1->s.k = 40;
+               sappend(s, s1);
+
+               s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+               s1->s.k = 0;
+               sappend(s, s1);
+       } else {
+               s = new_stmt(cstate, BPF_LD|BPF_IMM);
+               s->s.k = 40;
+       }
+
+       /* Forcibly append these statements to the true condition
+        * of the protocol check by creating a new block that is
+        * always true and ANDing them. */
+       s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+       sappend(s, s1);
+
+       b1 = gen_jmp(cstate, BPF_JMP|BPF_JEQ|BPF_X, 0, s);
+
+       gen_and(b0, b1);
+
+       return b1;
+}
+
+/* We need to store three values based on the Geneve header::
+ * - The offset of the linktype.
+ * - The offset of the end of the Geneve header.
+ * - The offset of the end of the encapsulated MAC header. */
+static struct slist *
+gen_geneve_offsets(compiler_state_t *cstate)
+{
+       struct slist *s, *s1, *s_proto;
+
+       /* First we need to calculate the offset of the Geneve header
+        * itself. This is composed of the IP header previously calculated
+        * (include any variable link prefix) and stored in A plus the
+        * fixed sized headers (fixed link prefix, MAC length, and UDP
+        * header). */
+       s = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+       s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 8;
+
+       /* Stash this in X since we'll need it later. */
+       s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+       sappend(s, s1);
+
+       /* The EtherType in Geneve is 2 bytes in. Calculate this and
+        * store it. */
+       s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 2;
+       sappend(s, s1);
+
+       cstate->off_linktype.reg = alloc_reg(cstate);
+       cstate->off_linktype.is_variable = 1;
+       cstate->off_linktype.constant_part = 0;
+
+       s1 = new_stmt(cstate, BPF_ST);
+       s1->s.k = cstate->off_linktype.reg;
+       sappend(s, s1);
+
+       /* Load the Geneve option length and mask and shift to get the
+        * number of bytes. It is stored in the first byte of the Geneve
+        * header. */
+       s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+       s1->s.k = 0;
+       sappend(s, s1);
+
+       s1 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+       s1->s.k = 0x3f;
+       sappend(s, s1);
+
+       s1 = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
+       s1->s.k = 4;
+       sappend(s, s1);
+
+       /* Add in the rest of the Geneve base header. */
+       s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 8;
+       sappend(s, s1);
+
+       /* Add the Geneve header length to its offset and store. */
+       s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+       s1->s.k = 0;
+       sappend(s, s1);
+
+       /* Set the encapsulated type as Ethernet. Even though we may
+        * not actually have Ethernet inside there are two reasons this
+        * is useful:
+        * - The linktype field is always in EtherType format regardless
+        *   of whether it is in Geneve or an inner Ethernet frame.
+        * - The only link layer that we have specific support for is
+        *   Ethernet. We will confirm that the packet actually is
+        *   Ethernet at runtime before executing these checks. */
+       PUSH_LINKHDR(cstate, DLT_EN10MB, 1, 0, alloc_reg(cstate));
+
+       s1 = new_stmt(cstate, BPF_ST);
+       s1->s.k = cstate->off_linkhdr.reg;
+       sappend(s, s1);
+
+       /* Calculate whether we have an Ethernet header or just raw IP/
+        * MPLS/etc. If we have Ethernet, advance the end of the MAC offset
+        * and linktype by 14 bytes so that the network header can be found
+        * seamlessly. Otherwise, keep what we've calculated already. */
+
+       /* We have a bare jmp so we can't use the optimizer. */
+       cstate->no_optimize = 1;
+
+       /* Load the EtherType in the Geneve header, 2 bytes in. */
+       s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_H);
+       s1->s.k = 2;
+       sappend(s, s1);
+
+       /* Load X with the end of the Geneve header. */
+       s1 = new_stmt(cstate, BPF_LDX|BPF_MEM);
+       s1->s.k = cstate->off_linkhdr.reg;
+       sappend(s, s1);
+
+       /* Check if the EtherType is Transparent Ethernet Bridging. At the
+        * end of this check, we should have the total length in X. In
+        * the non-Ethernet case, it's already there. */
+       s_proto = new_stmt(cstate, JMP(BPF_JEQ));
+       s_proto->s.k = ETHERTYPE_TEB;
+       sappend(s, s_proto);
+
+       s1 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+       sappend(s, s1);
+       s_proto->s.jt = s1;
+
+       /* Since this is Ethernet, use the EtherType of the payload
+        * directly as the linktype. Overwrite what we already have. */
+       s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 12;
+       sappend(s, s1);
+
+       s1 = new_stmt(cstate, BPF_ST);
+       s1->s.k = cstate->off_linktype.reg;
+       sappend(s, s1);
+
+       /* Advance two bytes further to get the end of the Ethernet
+        * header. */
+       s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 2;
+       sappend(s, s1);
+
+       /* Move the result to X. */
+       s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+       sappend(s, s1);
+
+       /* Store the final result of our linkpl calculation. */
+       cstate->off_linkpl.reg = alloc_reg(cstate);
+       cstate->off_linkpl.is_variable = 1;
+       cstate->off_linkpl.constant_part = 0;
+
+       s1 = new_stmt(cstate, BPF_STX);
+       s1->s.k = cstate->off_linkpl.reg;
+       sappend(s, s1);
+       s_proto->s.jf = s1;
+
+       cstate->off_nl = 0;
+
+       return s;
+}
+
+/* Check to see if this is a Geneve packet. */
+struct block *
+gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+       struct block *b0, *b1;
+       struct slist *s;
+
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       b0 = gen_geneve4(cstate, vni, has_vni);
+       b1 = gen_geneve6(cstate, vni, has_vni);
+
+       gen_or(b0, b1);
+       b0 = b1;
+
+       /* Later filters should act on the payload of the Geneve frame,
+        * update all of the header pointers. Attach this code so that
+        * it gets executed in the event that the Geneve filter matches. */
+       s = gen_geneve_offsets(cstate);
+
+       b1 = gen_true(cstate);
+       sappend(s, b1->stmts);
+       b1->stmts = s;
+
+       gen_and(b0, b1);
+
+       cstate->is_encap = 1;
+
+       return b1;
+}
+
+/* Check that this is VXLAN and the VNI is correct if
+ * 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 *, uint16_t, int, int),
+    enum e_offrel offrel, bpf_u_int32 vni, int has_vni)
+{
+       struct block *b0, *b1;
+
+       b0 = gen_portfn(cstate, VXLAN_PORT, IPPROTO_UDP, Q_DST);
+
+       /* Check that the VXLAN header has the flag bits set
+        * correctly. */
+       b1 = gen_cmp(cstate, offrel, 8, BPF_B, 0x08);
        gen_and(b0, b1);
        b0 = b1;
 
-       if (vni >= 0) {
+       if (has_vni) {
+               assert_maxval(cstate, "VXLAN VNI", vni, 0xffffff);
                vni <<= 8; /* VNI is in the upper 3 bytes */
-               b1 = gen_mcmp(cstate, offrel, 12, BPF_W, (bpf_int32)vni,
-                             0xffffff00);
+               b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00);
                gen_and(b0, b1);
                b0 = b1;
        }
@@ -8441,18 +9326,18 @@ gen_geneve_check(compiler_state_t *cstate,
        return b0;
 }
 
-/* The IPv4 and IPv6 Geneve checks need to do two things:
- * - Verify that this actually is Geneve with the right VNI.
+/* The IPv4 and IPv6 VXLAN checks need to do two things:
+ * - Verify that this actually is VXLAN with the right VNI.
  * - Place the IP header length (plus variable link prefix if
  *   needed) into register A to be used later to compute
  *   the inner packet offsets. */
 static struct block *
-gen_geneve4(compiler_state_t *cstate, int vni)
+gen_vxlan4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
 {
        struct block *b0, *b1;
        struct slist *s, *s1;
 
-       b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni);
+       b0 = gen_vxlan_check(cstate, gen_port, OR_TRAN_IPV4, vni, has_vni);
 
        /* Load the IP header length into A. */
        s = gen_loadx_iphdrlen(cstate);
@@ -8463,9 +9348,7 @@ gen_geneve4(compiler_state_t *cstate, int 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);
 
@@ -8473,12 +9356,12 @@ gen_geneve4(compiler_state_t *cstate, int vni)
 }
 
 static struct block *
-gen_geneve6(compiler_state_t *cstate, int vni)
+gen_vxlan6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
 {
        struct block *b0, *b1;
        struct slist *s, *s1;
 
-       b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni);
+       b0 = gen_vxlan_check(cstate, gen_port6, OR_TRAN_IPV6, vni, has_vni);
 
        /* Load the IP header length. We need to account for a
         * variable length link prefix if there is one. */
@@ -8502,130 +9385,58 @@ gen_geneve6(compiler_state_t *cstate, int 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);
 
        return b1;
 }
 
-/* We need to store three values based on the Geneve header::
+/* We need to store three values based on the VXLAN header:
  * - The offset of the linktype.
- * - The offset of the end of the Geneve header.
+ * - The offset of the end of the VXLAN header.
  * - The offset of the end of the encapsulated MAC header. */
 static struct slist *
-gen_geneve_offsets(compiler_state_t *cstate)
+gen_vxlan_offsets(compiler_state_t *cstate)
 {
-       struct slist *s, *s1, *s_proto;
+       struct slist *s, *s1;
 
-       /* First we need to calculate the offset of the Geneve header
-        * itself. This is composed of the IP header previously calculated
-        * (include any variable link prefix) and stored in A plus the
-        * fixed sized headers (fixed link prefix, MAC length, and UDP
-        * header). */
+       /* Calculate the offset of the VXLAN header itself. This
+        * includes the IP header computed previously (including any
+        * variable link prefix) and stored in A plus the fixed size
+        * headers (fixed link prefix, MAC length, UDP header). */
        s = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
        s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 8;
 
-       /* Stash this in X since we'll need it later. */
-       s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
-       sappend(s, s1);
-
-       /* The EtherType in Geneve is 2 bytes in. Calculate this and
-        * store it. */
-       s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
-       s1->s.k = 2;
-       sappend(s, s1);
-
-       cstate->off_linktype.reg = alloc_reg(cstate);
-       cstate->off_linktype.is_variable = 1;
-       cstate->off_linktype.constant_part = 0;
-
-       s1 = new_stmt(cstate, BPF_ST);
-       s1->s.k = cstate->off_linktype.reg;
-       sappend(s, s1);
-
-       /* Load the Geneve option length and mask and shift to get the
-        * number of bytes. It is stored in the first byte of the Geneve
-        * header. */
-       s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
-       s1->s.k = 0;
-       sappend(s, s1);
-
-       s1 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
-       s1->s.k = 0x3f;
-       sappend(s, s1);
-
-       s1 = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
-       s1->s.k = 4;
-       sappend(s, s1);
-
-       /* Add in the rest of the Geneve base header. */
+       /* Add the VXLAN header length to its offset and store */
        s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
        s1->s.k = 8;
        sappend(s, s1);
 
-       /* Add the Geneve header length to its offset and store. */
-       s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
-       s1->s.k = 0;
-       sappend(s, s1);
-
-       /* Set the encapsulated type as Ethernet. Even though we may
-        * not actually have Ethernet inside there are two reasons this
-        * is useful:
-        * - The linktype field is always in EtherType format regardless
-        *   of whether it is in Geneve or an inner Ethernet frame.
-        * - The only link layer that we have specific support for is
-        *   Ethernet. We will confirm that the packet actually is
-        *   Ethernet at runtime before executing these checks. */
+       /* Push the link header. VXLAN packets always contain Ethernet
+        * frames. */
        PUSH_LINKHDR(cstate, DLT_EN10MB, 1, 0, alloc_reg(cstate));
 
        s1 = new_stmt(cstate, BPF_ST);
        s1->s.k = cstate->off_linkhdr.reg;
        sappend(s, s1);
 
-       /* Calculate whether we have an Ethernet header or just raw IP/
-        * MPLS/etc. If we have Ethernet, advance the end of the MAC offset
-        * and linktype by 14 bytes so that the network header can be found
-        * seamlessly. Otherwise, keep what we've calculated already. */
-
-       /* We have a bare jmp so we can't use the optimizer. */
-       cstate->no_optimize = 1;
-
-       /* Load the EtherType in the Geneve header, 2 bytes in. */
-       s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_H);
-       s1->s.k = 2;
-       sappend(s, s1);
-
-       /* Load X with the end of the Geneve header. */
-       s1 = new_stmt(cstate, BPF_LDX|BPF_MEM);
-       s1->s.k = cstate->off_linkhdr.reg;
-       sappend(s, s1);
-
-       /* Check if the EtherType is Transparent Ethernet Bridging. At the
-        * end of this check, we should have the total length in X. In
-        * the non-Ethernet case, it's already there. */
-       s_proto = new_stmt(cstate, JMP(BPF_JEQ));
-       s_proto->s.k = ETHERTYPE_TEB;
-       sappend(s, s_proto);
-
-       s1 = new_stmt(cstate, BPF_MISC|BPF_TXA);
-       sappend(s, s1);
-       s_proto->s.jt = s1;
-
-       /* Since this is Ethernet, use the EtherType of the payload
-        * directly as the linktype. Overwrite what we already have. */
+       /* As the payload is an Ethernet packet, we can use the
+        * EtherType of the payload directly as the linktype. */
        s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
        s1->s.k = 12;
        sappend(s, s1);
 
+       cstate->off_linktype.reg = alloc_reg(cstate);
+       cstate->off_linktype.is_variable = 1;
+       cstate->off_linktype.constant_part = 0;
+
        s1 = new_stmt(cstate, BPF_ST);
        s1->s.k = cstate->off_linktype.reg;
        sappend(s, s1);
 
-       /* Advance two bytes further to get the end of the Ethernet
-        * header. */
+       /* Two bytes further is the end of the Ethernet header and the
+        * start of the payload. */
        s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
        s1->s.k = 2;
        sappend(s, s1);
@@ -8642,30 +9453,36 @@ gen_geneve_offsets(compiler_state_t *cstate)
        s1 = new_stmt(cstate, BPF_STX);
        s1->s.k = cstate->off_linkpl.reg;
        sappend(s, s1);
-       s_proto->s.jf = s1;
 
        cstate->off_nl = 0;
 
        return s;
 }
 
-/* Check to see if this is a Geneve packet. */
+/* Check to see if this is a VXLAN packet. */
 struct block *
-gen_geneve(compiler_state_t *cstate, int vni)
+gen_vxlan(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
 {
        struct block *b0, *b1;
        struct slist *s;
 
-       b0 = gen_geneve4(cstate, vni);
-       b1 = gen_geneve6(cstate, vni);
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       b0 = gen_vxlan4(cstate, vni, has_vni);
+       b1 = gen_vxlan6(cstate, vni, has_vni);
 
        gen_or(b0, b1);
        b0 = b1;
 
-       /* Later filters should act on the payload of the Geneve frame,
+       /* Later filters should act on the payload of the VXLAN frame,
         * update all of the header pointers. Attach this code so that
-        * it gets executed in the event that the Geneve filter matches. */
-       s = gen_geneve_offsets(cstate);
+        * it gets executed in the event that the VXLAN filter matches. */
+       s = gen_vxlan_offsets(cstate);
 
        b1 = gen_true(cstate);
        sappend(s, b1->stmts);
@@ -8673,7 +9490,7 @@ gen_geneve(compiler_state_t *cstate, int vni)
 
        gen_and(b0, b1);
 
-       cstate->is_geneve = 1;
+       cstate->is_encap = 1;
 
        return b1;
 }
@@ -8681,7 +9498,7 @@ gen_geneve(compiler_state_t *cstate, int vni)
 /* Check that the encapsulated frame has a link layer header
  * for Ethernet filters. */
 static struct block *
-gen_geneve_ll_check(compiler_state_t *cstate)
+gen_encap_ll_check(compiler_state_t *cstate)
 {
        struct block *b0;
        struct slist *s, *s1;
@@ -8699,135 +9516,139 @@ gen_geneve_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;
 }
 
-struct block *
-gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue,
-    bpf_u_int32 jtype, int reverse)
+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 == (u_int)-1)
-                       abort();
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, 0xffffffff, jtype,
-                   reverse, jvalue);
-               break;
+               assert_maxval(cstate, "VPI", jvalue, UINT8_MAX);
+               return gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B,
+                   0xffffffffU, jtype, reverse, jvalue);
 
        case A_VCI:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'vci' supported only on raw ATM");
-               if (cstate->off_vci == (u_int)-1)
-                       abort();
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, 0xffffffff, jtype,
-                   reverse, jvalue);
-               break;
-
-       case A_PROTOTYPE:
-               if (cstate->off_proto == (u_int)-1)
-                       abort();        /* XXX - this isn't on FreeBSD */
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0x0f, jtype,
-                   reverse, jvalue);
-               break;
-
-       case A_MSGTYPE:
-               if (cstate->off_payload == (u_int)-1)
-                       abort();
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B,
-                   0xffffffff, jtype, reverse, jvalue);
-               break;
-
-       case A_CALLREFTYPE:
-               if (!cstate->is_atm)
-                       bpf_error(cstate, "'callref' supported only on raw ATM");
-               if (cstate->off_proto == (u_int)-1)
-                       abort();
-               b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0xffffffff,
-                   jtype, reverse, jvalue);
-               break;
+               assert_maxval(cstate, "VCI", jvalue, UINT16_MAX);
+               return gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H,
+                   0xffffffffU, jtype, reverse, jvalue);
 
        default:
                abort();
        }
+}
+
+static struct block *
+gen_atm_vpi(compiler_state_t *cstate, const uint8_t v)
+{
+       return gen_atmfield_code_internal(cstate, A_VPI, v, BPF_JEQ, 0);
+}
+
+static struct block *
+gen_atm_vci(compiler_state_t *cstate, const uint16_t v)
+{
+       return gen_atmfield_code_internal(cstate, A_VCI, v, BPF_JEQ, 0);
+}
+
+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 *
+gen_atmtype_llc(compiler_state_t *cstate)
+{
+       struct block *b0;
+
+       b0 = gen_atm_prototype(cstate, PT_LLC);
+       cstate->linktype = cstate->prevlinktype;
        return b0;
 }
 
+struct block *
+gen_atmfield_code(compiler_state_t *cstate, int atmfield,
+    bpf_u_int32 jvalue, int jtype, int reverse)
+{
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       return gen_atmfield_code_internal(cstate, atmfield, jvalue, jtype,
+           reverse);
+}
+
 struct block *
 gen_atmtype_abbrev(compiler_state_t *cstate, int type)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       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");
-               b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code(cstate, A_VCI, 1, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 1);
                gen_and(b0, b1);
-               break;
+               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(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code(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(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code(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(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code(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");
-               b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code(cstate, A_VCI, 5, BPF_JEQ, 0);
+               b0 = gen_atm_vpi(cstate, 0);
+               b1 = gen_atm_vci(cstate, 5);
                gen_and(b0, b1);
-               break;
+               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(cstate, A_VPI, 0, BPF_JEQ, 0);
-               b1 = gen_atmfield_code(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(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0);
+               b1 = gen_atm_prototype(cstate, PT_LANE);
 
                /*
                 * Arrange that all subsequent tests assume LANE
@@ -8844,20 +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_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
-               cstate->linktype = cstate->prevlinktype;
-               break;
+               return b1;
 
        default:
                abort();
        }
-       return b1;
 }
 
 /*
@@ -8872,201 +9684,185 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       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, 0x3f, BPF_JEQ, 0, 0);
-               break;
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+                   0x3fU, BPF_JEQ, 0, 0U);
 
        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, 0x3f, BPF_JGT, 1, 2);
-               b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 0);
+               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, 0x3f, BPF_JGT, 0, 2);
-               break;
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+                   0x3fU, BPF_JGT, 0, 2U);
 
        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, 0xff80, BPF_JEQ, 0, 0);
-               break;
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+                   0xff80U, BPF_JEQ, 0, 0U);
 
        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, 0xff80, BPF_JGT, 1, 0x0100);
-               b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0);
+               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, 0xff80, BPF_JGT, 0, 0x0100);
-               break;
+               return gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+                   0xff80U, BPF_JGT, 0, 0x0100U);
 
        default:
                abort();
        }
-       return b0;
 }
 
-struct block *
-gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue,
-    bpf_u_int32 jtype, int reverse)
+/*
+ * These maximum valid values are all-ones, so they double as the bitmasks
+ * before any bitwise shifting.
+ */
+#define MTP2_SIO_MAXVAL UINT8_MAX
+#define MTP3_PC_MAXVAL 0x3fffU
+#define MTP3_SLS_MAXVAL 0xfU
+
+static struct block *
+gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
+    bpf_u_int32 jvalue, int jtype, int reverse)
 {
-       struct block *b0;
-       bpf_u_int32 val1 , val2 , val3;
-       u_int newoff_sio = cstate->off_sio;
-       u_int newoff_opc = cstate->off_opc;
-       u_int newoff_dpc = cstate->off_dpc;
-       u_int newoff_sls = cstate->off_sls;
+       u_int newoff_sio;
+       u_int newoff_opc;
+       u_int newoff_dpc;
+       u_int newoff_sls;
+
+       newoff_sio = cstate->off_sio;
+       newoff_opc = cstate->off_opc;
+       newoff_dpc = cstate->off_dpc;
+       newoff_sls = cstate->off_sls;
+
+       assert_ss7(cstate, ss7kw(mtp3field));
 
        switch (mtp3field) {
 
+       /*
+        * See UTU-T Rec. Q.703, Section 2.2, Figure 3/Q.703.
+        *
+        * SIO is the simplest field: the size is one byte and the offset is a
+        * multiple of bytes, so the only detail to get right is the value of
+        * the [right-to-left] field offset.
+        */
        case MH_SIO:
                newoff_sio += 3; /* offset for MTP2_HSL */
                /* FALLTHROUGH */
 
        case M_SIO:
-               if (cstate->off_sio == (u_int)-1)
-                       bpf_error(cstate, "'sio' supported only on SS7");
-               /* sio coded on 1 byte so max value 255 */
-               if(jvalue > 255)
-                       bpf_error(cstate, "sio value %u too big; max value = 255",
-                           jvalue);
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffff,
-                   (u_int)jtype, reverse, (u_int)jvalue);
-               break;
+               assert_maxval(cstate, ss7kw(mtp3field), jvalue, MTP2_SIO_MAXVAL);
+               // Here the bitmask means "do not apply a bitmask".
+               return gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, UINT32_MAX,
+                   jtype, reverse, jvalue);
 
+       /*
+        * See UTU-T Rec. Q.704, Section 2.2, Figure 3/Q.704.
+        *
+        * SLS, OPC and DPC are more complicated: none of these is sized in a
+        * multiple of 8 bits, MTP3 encoding is little-endian and MTP packet
+        * diagrams are meant to be read right-to-left.  This means in the
+        * diagrams within individual fields and concatenations thereof
+        * bitwise shifts and masks can be noted in the common left-to-right
+        * manner until each final value is ready to be byte-swapped and
+        * handed to gen_ncmp().  See also gen_dnhostop(), which solves a
+        * similar problem in a similar way.
+        *
+        * Offsets of fields within the packet header always have the
+        * right-to-left meaning.  Note that in DLT_MTP2 and possibly other
+        * DLTs the offset does not include the F (Flag) field at the
+        * beginning of each message.
+        *
+        * For example, if the 8-bit SIO field has a 3 byte [RTL] offset, the
+        * 32-bit standard routing header has a 4 byte [RTL] offset and could
+        * be tested entirely using a single BPF_W comparison.  In this case
+        * the 14-bit DPC field [LTR] bitmask would be 0x3FFF, the 14-bit OPC
+        * field [LTR] bitmask would be (0x3FFF << 14) and the 4-bit SLS field
+        * [LTR] bitmask would be (0xF << 28), all of which conveniently
+        * correlates with the [RTL] packet diagram until the byte-swapping is
+        * done before use.
+        *
+        * The code below uses this approach for OPC, which spans 3 bytes.
+        * DPC and SLS use shorter loads, SLS also uses a different offset.
+        */
        case MH_OPC:
-               newoff_opc+=3;
-        case M_OPC:
-               if (cstate->off_opc == (u_int)-1)
-                       bpf_error(cstate, "'opc' supported only on SS7");
-               /* opc coded on 14 bits so max value 16383 */
-               if (jvalue > 16383)
-                       bpf_error(cstate, "opc value %u too big; max value = 16383",
-                           jvalue);
-               /* the following instructions are made to convert jvalue
-                * to the form used to write opc in an ss7 message*/
-               val1 = jvalue & 0x00003c00;
-               val1 = val1 >>10;
-               val2 = jvalue & 0x000003fc;
-               val2 = val2 <<6;
-               val3 = jvalue & 0x00000003;
-               val3 = val3 <<22;
-               jvalue = val1 + val2 + val3;
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0f,
-                   (u_int)jtype, reverse, (u_int)jvalue);
-               break;
+               newoff_opc += 3;
+
+               /* FALLTHROUGH */
+       case M_OPC:
+               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));
 
        case MH_DPC:
                newoff_dpc += 3;
                /* FALLTHROUGH */
 
        case M_DPC:
-               if (cstate->off_dpc == (u_int)-1)
-                       bpf_error(cstate, "'dpc' supported only on SS7");
-               /* dpc coded on 14 bits so max value 16383 */
-               if (jvalue > 16383)
-                       bpf_error(cstate, "dpc value %u too big; max value = 16383",
-                           jvalue);
-               /* the following instructions are made to convert jvalue
-                * to the forme used to write dpc in an ss7 message*/
-               val1 = jvalue & 0x000000ff;
-               val1 = val1 << 24;
-               val2 = jvalue & 0x00003f00;
-               val2 = val2 << 8;
-               jvalue = val1 + val2;
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000,
-                   (u_int)jtype, reverse, (u_int)jvalue);
-               break;
+               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));
 
        case MH_SLS:
-         newoff_sls+=3;
+               newoff_sls += 3;
+               /* FALLTHROUGH */
+
        case M_SLS:
-               if (cstate->off_sls == (u_int)-1)
-                       bpf_error(cstate, "'sls' supported only on SS7");
-               /* sls coded on 4 bits so max value 15 */
-               if (jvalue > 15)
-                        bpf_error(cstate, "sls value %u too big; max value = 15",
-                            jvalue);
-               /* the following instruction is made to convert jvalue
-                * to the forme used to write sls in an ss7 message*/
-               jvalue = jvalue << 4;
-               b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0,
-                   (u_int)jtype,reverse, (u_int)jvalue);
-               break;
+               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);
 
        default:
                abort();
        }
-       return b0;
 }
 
-static struct block *
-gen_msg_abbrev(compiler_state_t *cstate, int type)
+struct block *
+gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
+    bpf_u_int32 jvalue, int jtype, int reverse)
 {
-       struct block *b1;
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       if (setjmp(cstate->top_ctx))
+               return (NULL);
+
+       return gen_mtp3field_code_internal(cstate, mtp3field, jvalue, jtype,
+           reverse);
+}
 
+static struct block *
+gen_msg_abbrev(compiler_state_t *cstate, const uint8_t type)
+{
        /*
         * Q.2931 signalling protocol messages for handling virtual circuits
         * establishment and teardown
         */
-       switch (type) {
-
-       case A_SETUP:
-               b1 = gen_atmfield_code(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0);
-               break;
-
-       case A_CALLPROCEED:
-               b1 = gen_atmfield_code(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0);
-               break;
-
-       case A_CONNECT:
-               b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0);
-               break;
-
-       case A_CONNECTACK:
-               b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0);
-               break;
-
-       case A_RELEASE:
-               b1 = gen_atmfield_code(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0);
-               break;
-
-       case A_RELEASE_DONE:
-               b1 = gen_atmfield_code(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 *
@@ -9074,65 +9870,70 @@ gen_atmmulti_abbrev(compiler_state_t *cstate, int type)
 {
        struct block *b0, *b1;
 
+       /*
+        * Catch errors reported by us and routines below us, and return NULL
+        * on an error.
+        */
+       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");
-               b1 = gen_atmmulti_abbrev(cstate, A_OAMF4);
-               break;
+               /* OAM F4 type */
+               b0 = gen_atm_vci(cstate, 3);
+               b1 = gen_atm_vci(cstate, 4);
+               gen_or(b0, b1);
+               b0 = gen_atm_vpi(cstate, 0);
+               gen_and(b0, b1);
+               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(cstate, A_VCI, 3, BPF_JEQ, 0);
-               b1 = gen_atmfield_code(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(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_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_abbrev(cstate, A_METAC);
                gen_and(b0, b1);
-               break;
+               return b1;
 
        default:
                abort();
        }
-       return b1;
 }