Merge branch 'vendor/LIBPCAP'
[dragonfly.git] / contrib / libpcap / gencode.c
index bd38224..2a0fb51 100644 (file)
@@ -21,7 +21,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.16 2008-09-22 20:16:01 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.309 2008-12-23 20:13:29 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -31,6 +31,14 @@ static const char rcsid[] _U_ =
 #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 */
@@ -39,7 +47,7 @@ static const char rcsid[] _U_ =
  * XXX - why was this included even on UNIX?
  */
 #ifdef __MINGW32__
-#include "IP6_misc.h"
+#include "ip6_misc.h"
 #endif
 
 #ifndef WIN32
@@ -49,6 +57,7 @@ static const char rcsid[] _U_ =
 #endif
 
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #endif /* WIN32 */
 
@@ -73,6 +82,7 @@ static const char rcsid[] _U_ =
 #include "sunatmpos.h"
 #include "ppp.h"
 #include "pcap/sll.h"
+#include "pcap/ipnet.h"
 #include "arcnet.h"
 #ifdef HAVE_NET_PFVAR_H
 #include <sys/socket.h>
@@ -158,6 +168,17 @@ enum e_offrel {
        OR_TRAN_IPV6    /* relative to the transport-layer header, with IPv6 network layer */
 };
 
+#ifdef INET6
+/*
+ * As errors are handled by a longjmp, anything allocated must be freed
+ * in the longjmp handler, so it must be reachable from that handler.
+ * One thing that's allocated is the result of pcap_nametoaddrinfo();
+ * it must be freed with freeaddrinfo().  This variable points to any
+ * addrinfo structure that would need to be freed.
+ */
+static struct addrinfo *ai;
+#endif
+
 /*
  * We divy out chunks of memory rather than call malloc each time so
  * we don't have to worry about leaking memory.  It's probably
@@ -203,6 +224,7 @@ static struct block *gen_uncond(int);
 static inline struct block *gen_true(void);
 static inline struct block *gen_false(void);
 static struct block *gen_ether_linktype(int);
+static struct block *gen_ipnet_linktype(int);
 static struct block *gen_linux_sll_linktype(int);
 static struct slist *gen_load_prism_llprefixlen(void);
 static struct slist *gen_load_avs_llprefixlen(void);
@@ -368,11 +390,35 @@ syntax()
 static bpf_u_int32 netmask;
 static int snaplen;
 int no_optimize;
+#ifdef WIN32
+static int
+pcap_compile_unsafe(pcap_t *p, struct bpf_program *program,
+            const char *buf, int optimize, bpf_u_int32 mask);
 
 int
 pcap_compile(pcap_t *p, struct bpf_program *program,
             const char *buf, int optimize, bpf_u_int32 mask)
 {
+       int result;
+
+       EnterCriticalSection(&g_PcapCompileCriticalSection);
+
+       result = pcap_compile_unsafe(p, program, buf, optimize, mask);
+
+       LeaveCriticalSection(&g_PcapCompileCriticalSection);
+       
+       return result;
+}
+
+static int
+pcap_compile_unsafe(pcap_t *p, struct bpf_program *program,
+            const char *buf, int optimize, bpf_u_int32 mask)
+#else /* WIN32 */
+int
+pcap_compile(pcap_t *p, struct bpf_program *program,
+            const char *buf, int optimize, bpf_u_int32 mask)
+#endif /* WIN32 */
+{
        extern int n_errors;
        const char * volatile xbuf = buf;
        int len;
@@ -383,6 +429,12 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        bpf_pcap = p;
        init_regs();
        if (setjmp(top_ctx)) {
+#ifdef INET6
+               if (ai != NULL) {
+                       freeaddrinfo(ai);
+                       ai = NULL;
+               }
+#endif
                lex_cleanup();
                freechunks();
                return (-1);
@@ -723,7 +775,8 @@ static int reg_off_ll;
  * This is the offset of the beginning of the MAC-layer header from
  * the beginning of the link-layer header.
  * It's usually 0, except for ATM LANE, where it's the offset, relative
- * to the beginning of the raw packet data, of the Ethernet header.
+ * to the beginning of the raw packet data, of the Ethernet header, and
+ * for Ethernet with various additional information.
  */
 static u_int off_mac;
 
@@ -1115,6 +1168,8 @@ init_linktype(p)
                return;
 
        case DLT_RAW:
+       case DLT_IPV4:
+       case DLT_IPV6:
                off_linktype = -1;
                off_macpl = 0;
                off_nl = 0;
@@ -1187,26 +1242,6 @@ init_linktype(p)
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
-       case DLT_LINUX_IRDA:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_DOCSIS:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
        case DLT_SYMANTEC_FIREWALL:
                off_linktype = 6;
                off_macpl = 44;
@@ -1315,6 +1350,16 @@ init_linktype(p)
                off_nl_nosnap = -1;
                return;
 
+       case DLT_JUNIPER_VS:
+       case DLT_JUNIPER_SRX_E2E:
+       case DLT_JUNIPER_FIBRECHANNEL:
+       case DLT_JUNIPER_ATM_CEMIC:
+               off_linktype = 8;
+               off_macpl = -1;
+               off_nl = -1;
+               off_nl_nosnap = -1;
+               return;
+
        case DLT_MTP2:
                off_li = 2;
                off_sio = 3;
@@ -1360,146 +1405,54 @@ init_linktype(p)
                return;
 #endif
 
-       case DLT_LINUX_LAPD:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_USB:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_BLUETOOTH_HCI_H4:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_USB_LINUX:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_CAN20B:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_IEEE802_15_4_LINUX:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_IEEE802_16_MAC_CPS_RADIO:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_IEEE802_15_4:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
-
-       case DLT_SITA:
+       case DLT_AX25_KISS:
                /*
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
-               off_linktype = -1;
+               off_linktype = -1;      /* variable, min 15, max 71 steps of 7 */
                off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
+               off_nl = -1;            /* variable, min 16, max 71 steps of 7 */
+               off_nl_nosnap = -1;     /* no 802.2 LLC */
+               off_mac = 1;            /* step over the kiss length byte */
                return;
 
-       case DLT_RAIF1:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
+       case DLT_IPNET:
+               off_linktype = 1;
+               off_macpl = 24;         /* ipnet header length */
+               off_nl = 0;
                off_nl_nosnap = -1;
                return;
 
-       case DLT_IPMB:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
+       case DLT_NETANALYZER:
+               off_mac = 4;            /* MAC header is past 4-byte pseudo-header */
+               off_linktype = 16;      /* includes 4-byte pseudo-header */
+               off_macpl = 18;         /* pseudo-header+Ethernet header length */
+               off_nl = 0;             /* Ethernet II */
+               off_nl_nosnap = 3;      /* 802.3+802.2 */
                return;
 
-       case DLT_BLUETOOTH_HCI_H4_WITH_PHDR:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
+       case DLT_NETANALYZER_TRANSPARENT:
+               off_mac = 12;           /* MAC header is past 4-byte pseudo-header, preamble, and SFD */
+               off_linktype = 24;      /* includes 4-byte pseudo-header+preamble+SFD */
+               off_macpl = 26;         /* pseudo-header+preamble+SFD+Ethernet header length */
+               off_nl = 0;             /* Ethernet II */
+               off_nl_nosnap = 3;      /* 802.3+802.2 */
                return;
 
-       case DLT_AX25_KISS:
+       default:
                /*
-                * Currently, only raw "link[N:M]" filtering is supported.
+                * For values in the range in which we've assigned new
+                * DLT_ values, only raw "link[N:M]" filtering is supported.
                 */
-               off_linktype = -1;      /* variable, min 15, max 71 steps of 7 */
-               off_macpl = -1;
-               off_nl = -1;            /* variable, min 16, max 71 steps of 7 */
-               off_nl_nosnap = -1;     /* no 802.2 LLC */
-               off_mac = 1;            /* step over the kiss length byte */
-               return;
+               if (linktype >= DLT_MATCHING_MIN &&
+                   linktype <= DLT_MATCHING_MAX) {
+                       off_linktype = -1;
+                       off_macpl = -1;
+                       off_nl = -1;
+                       off_nl_nosnap = -1;
+                       return;
+               }
 
-       case DLT_IEEE802_15_4_NONASK_PHY:
-               /*
-                * Currently, only raw "link[N:M]" filtering is supported.
-                */
-               off_linktype = -1;
-               off_macpl = -1;
-               off_nl = -1;
-               off_nl_nosnap = -1;
-               return;
        }
        bpf_error("unknown data link type %d", linktype);
        /* NOTREACHED */
@@ -1934,6 +1887,33 @@ gen_ether_linktype(proto)
 }
 
 /*
+ * "proto" is an Ethernet type value and for IPNET, if it is not IPv4
+ * or IPv6 then we have an error.
+ */
+static struct block *
+gen_ipnet_linktype(proto)
+       register int proto;
+{
+       switch (proto) {
+
+       case ETHERTYPE_IP:
+               return gen_cmp(OR_LINK, off_linktype, BPF_B,
+                   (bpf_int32)IPH_AF_INET);
+               /* NOTREACHED */
+
+       case ETHERTYPE_IPV6:
+               return gen_cmp(OR_LINK, off_linktype, BPF_B,
+                   (bpf_int32)IPH_AF_INET6);
+               /* NOTREACHED */
+
+       default:
+               break;
+       }
+
+       return gen_false();
+}
+
+/*
  * Generate code to match a particular packet type.
  *
  * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
@@ -2944,6 +2924,8 @@ gen_linktype(proto)
        switch (linktype) {
 
        case DLT_EN10MB:
+       case DLT_NETANALYZER:
+       case DLT_NETANALYZER_TRANSPARENT:
                return gen_ether_linktype(proto);
                /*NOTREACHED*/
                break;
@@ -3074,6 +3056,32 @@ gen_linktype(proto)
                /*NOTREACHED*/
                break;
 
+       case DLT_IPV4:
+               /*
+                * Raw IPv4, so no type field.
+                */
+               if (proto == ETHERTYPE_IP)
+                       return gen_true();              /* always true */
+
+               /* Checking for something other than IPv4; always false */
+               return gen_false();
+               /*NOTREACHED*/
+               break;
+
+       case DLT_IPV6:
+               /*
+                * Raw IPv6, so no type field.
+                */
+#ifdef INET6
+               if (proto == ETHERTYPE_IPV6)
+                       return gen_true();              /* always true */
+#endif
+
+               /* Checking for something other than IPv6; always false */
+               return gen_false();
+               /*NOTREACHED*/
+               break;
+
        case DLT_PPP:
        case DLT_PPP_PPPD:
        case DLT_PPP_SERIAL:
@@ -3321,6 +3329,11 @@ gen_linktype(proto)
         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 -
                 * on ATM we may have up to 6 different encapsulations on the wire
                 * and need a lot of heuristics to figure out that the payload
@@ -3330,6 +3343,9 @@ gen_linktype(proto)
                 */
                return gen_mcmp(OR_LINK, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */
 
+       case DLT_IPNET:
+               return gen_ipnet_linktype(proto);
+
        case DLT_LINUX_IRDA:
                bpf_error("IrDA link-layer type filtering not implemented");
 
@@ -3353,6 +3369,7 @@ gen_linktype(proto)
 
        case DLT_USB:
        case DLT_USB_LINUX:
+       case DLT_USB_LINUX_MMAPPED:
                bpf_error("USB link-layer type filtering not implemented");
 
        case DLT_BLUETOOTH_HCI_H4:
@@ -3360,11 +3377,13 @@ gen_linktype(proto)
                bpf_error("Bluetooth link-layer type filtering not implemented");
 
        case DLT_CAN20B:
-               bpf_error("CAN20B link-layer type filtering not implemented");
+       case DLT_CAN_SOCKETCAN:
+               bpf_error("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("IEEE 802.15.4 link-layer type filtering not implemented");
 
        case DLT_IEEE802_16_MAC_CPS_RADIO:
@@ -3639,6 +3658,30 @@ gen_ehostop(eaddr, dir)
                b1 = gen_ehostop(eaddr, Q_DST);
                gen_or(b0, b1);
                return b1;
+
+       case Q_ADDR1:
+               bpf_error("'addr1' is only supported on 802.11 with 802.11 headers");
+               break;
+
+       case Q_ADDR2:
+               bpf_error("'addr2' is only supported on 802.11 with 802.11 headers");
+               break;
+
+       case Q_ADDR3:
+               bpf_error("'addr3' is only supported on 802.11 with 802.11 headers");
+               break;
+
+       case Q_ADDR4:
+               bpf_error("'addr4' is only supported on 802.11 with 802.11 headers");
+               break;
+
+       case Q_RA:
+               bpf_error("'ra' is only supported on 802.11 with 802.11 headers");
+               break;
+
+       case Q_TA:
+               bpf_error("'ta' is only supported on 802.11 with 802.11 headers");
+               break;
        }
        abort();
        /* NOTREACHED */
@@ -3681,6 +3724,30 @@ gen_fhostop(eaddr, dir)
                b1 = gen_fhostop(eaddr, Q_DST);
                gen_or(b0, b1);
                return b1;
+
+       case Q_ADDR1:
+               bpf_error("'addr1' is only supported on 802.11");
+               break;
+
+       case Q_ADDR2:
+               bpf_error("'addr2' is only supported on 802.11");
+               break;
+
+       case Q_ADDR3:
+               bpf_error("'addr3' is only supported on 802.11");
+               break;
+
+       case Q_ADDR4:
+               bpf_error("'addr4' is only supported on 802.11");
+               break;
+
+       case Q_RA:
+               bpf_error("'ra' is only supported on 802.11");
+               break;
+
+       case Q_TA:
+               bpf_error("'ta' is only supported on 802.11");
+               break;
        }
        abort();
        /* NOTREACHED */
@@ -3715,6 +3782,30 @@ gen_thostop(eaddr, dir)
                b1 = gen_thostop(eaddr, Q_DST);
                gen_or(b0, b1);
                return b1;
+
+       case Q_ADDR1:
+               bpf_error("'addr1' is only supported on 802.11");
+               break;
+
+       case Q_ADDR2:
+               bpf_error("'addr2' is only supported on 802.11");
+               break;
+
+       case Q_ADDR3:
+               bpf_error("'addr3' is only supported on 802.11");
+               break;
+
+       case Q_ADDR4:
+               bpf_error("'addr4' is only supported on 802.11");
+               break;
+
+       case Q_RA:
+               bpf_error("'ra' is only supported on 802.11");
+               break;
+
+       case Q_TA:
+               bpf_error("'ta' is only supported on 802.11");
+               break;
        }
        abort();
        /* NOTREACHED */
@@ -4008,8 +4099,79 @@ gen_wlanhostop(eaddr, dir)
                gen_and(b1, b0);
                return b0;
 
+       case Q_RA:
+               /*
+                * Not present in management frames; addr1 in other
+                * frames.
+                */
+
+               /*
+                * If the high-order bit of the type value is 0, this
+                * is a management frame.
+                * I.e, check "(link[0] & 0x08)".
+                */
+               s = gen_load_a(OR_LINK, 0, BPF_B);
+               b1 = new_block(JMP(BPF_JSET));
+               b1->s.k = 0x08;
+               b1->stmts = s;
+
+               /*
+                * Check addr1.
+                */
+               b0 = gen_bcmp(OR_LINK, 4, 6, eaddr);
+
+               /*
+                * AND that with the check of addr1.
+                */
+               gen_and(b1, b0);
+               return (b0);
+
+       case Q_TA:
+               /*
+                * Not present in management frames; addr2, if present,
+                * in other frames.
+                */
+
+               /*
+                * Not present in CTS or ACK control frames.
+                */
+               b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+                       IEEE80211_FC0_TYPE_MASK);
+               gen_not(b0);
+               b1 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+                       IEEE80211_FC0_SUBTYPE_MASK);
+               gen_not(b1);
+               b2 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+                       IEEE80211_FC0_SUBTYPE_MASK);
+               gen_not(b2);
+               gen_and(b1, b2);
+               gen_or(b0, b2);
+
+               /*
+                * If the high-order bit of the type value is 0, this
+                * is a management frame.
+                * I.e, check "(link[0] & 0x08)".
+                */
+               s = gen_load_a(OR_LINK, 0, BPF_B);
+               b1 = new_block(JMP(BPF_JSET));
+               b1->s.k = 0x08;
+               b1->stmts = s;
+
+               /*
+                * AND that with the check for frames other than
+                * CTS and ACK frames.
+                */
+               gen_and(b1, b2);
+
+               /*
+                * Check addr2.
+                */
+               b1 = gen_bcmp(OR_LINK, 10, 6, eaddr);
+               gen_and(b2, b1);
+               return b1;
+
        /*
-        * XXX - add RA, TA, and BSSID keywords?
+        * XXX - add BSSID keyword?
         */
        case Q_ADDR1:
                return (gen_bcmp(OR_LINK, 4, 6, eaddr));
@@ -4105,6 +4267,30 @@ gen_ipfchostop(eaddr, dir)
                b1 = gen_ipfchostop(eaddr, Q_DST);
                gen_or(b0, b1);
                return b1;
+
+       case Q_ADDR1:
+               bpf_error("'addr1' is only supported on 802.11");
+               break;
+
+       case Q_ADDR2:
+               bpf_error("'addr2' is only supported on 802.11");
+               break;
+
+       case Q_ADDR3:
+               bpf_error("'addr3' is only supported on 802.11");
+               break;
+
+       case Q_ADDR4:
+               bpf_error("'addr4' is only supported on 802.11");
+               break;
+
+       case Q_RA:
+               bpf_error("'ra' is only supported on 802.11");
+               break;
+
+       case Q_TA:
+               bpf_error("'ta' is only supported on 802.11");
+               break;
        }
        abort();
        /* NOTREACHED */
@@ -4298,6 +4484,9 @@ gen_host(addr, mask, proto, dir, type)
        case Q_VRRP:
                bpf_error("'vrrp' modifier applied to %s", typestr);
 
+       case Q_CARP:
+               bpf_error("'carp' modifier applied to %s", typestr);
+
        case Q_ATALK:
                bpf_error("ATALK host filtering not implemented");
 
@@ -4417,6 +4606,9 @@ gen_host6(addr, mask, proto, dir, type)
        case Q_VRRP:
                bpf_error("'vrrp' modifier applied to %s", typestr);
 
+       case Q_CARP:
+               bpf_error("'carp' modifier applied to %s", typestr);
+
        case Q_ATALK:
                bpf_error("ATALK host filtering not implemented");
 
@@ -4501,6 +4693,8 @@ gen_gateway(eaddr, alist, proto, dir)
        case Q_RARP:
                switch (linktype) {
                case DLT_EN10MB:
+               case DLT_NETANALYZER:
+               case DLT_NETANALYZER_TRANSPARENT:
                        b0 = gen_ehostop(eaddr, Q_OR);
                        break;
                case DLT_FDDI:
@@ -4517,29 +4711,30 @@ gen_gateway(eaddr, alist, proto, dir)
                        b0 = gen_wlanhostop(eaddr, Q_OR);
                        break;
                case DLT_SUNATM:
-                       if (is_lane) {
-                               /*
-                                * Check that the packet doesn't begin with an
-                                * LE Control marker.  (We've already generated
-                                * a test for LANE.)
-                                */
-                               b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
-                                   BPF_H, 0xFF00);
-                               gen_not(b1);
+                       if (!is_lane)
+                               bpf_error(
+                                   "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+                       /*
+                        * Check that the packet doesn't begin with an
+                        * LE Control marker.  (We've already generated
+                        * a test for LANE.)
+                        */
+                       b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
+                           BPF_H, 0xFF00);
+                       gen_not(b1);
 
-                               /*
-                                * Now check the MAC address.
-                                */
-                               b0 = gen_ehostop(eaddr, Q_OR);
-                               gen_and(b1, b0);
-                       }
+                       /*
+                        * Now check the MAC address.
+                        */
+                       b0 = gen_ehostop(eaddr, Q_OR);
+                       gen_and(b1, b0);
                        break;
                case DLT_IP_OVER_FC:
                        b0 = gen_ipfchostop(eaddr, Q_OR);
                        break;
                default:
                        bpf_error(
-                           "'gateway' supported only on ethernet/FDDI/token ring/802.11/Fibre Channel");
+                           "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
                }
                b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR, Q_HOST);
                while (*alist) {
@@ -4629,6 +4824,14 @@ gen_proto_abbrev(proto)
                b1 = gen_proto(IPPROTO_VRRP, Q_IP, Q_DEFAULT);
                break;
 
+#ifndef IPPROTO_CARP
+#define IPPROTO_CARP   112
+#endif
+
+       case Q_CARP:
+               b1 = gen_proto(IPPROTO_CARP, Q_IP, Q_DEFAULT);
+               break;
+
        case Q_IP:
                b1 =  gen_linktype(ETHERTYPE_IP);
                break;
@@ -4810,7 +5013,7 @@ gen_ipfrag()
        struct slist *s;
        struct block *b;
 
-       /* not ip frag */
+       /* not IPv4 frag other than the first frag */
        s = gen_load_a(OR_NET, 6, BPF_H);
        b = new_block(JMP(BPF_JSET));
        b->s.k = 0x1fff;
@@ -4853,7 +5056,7 @@ gen_portop(port, proto, dir)
 {
        struct block *b0, *b1, *tmp;
 
-       /* ip proto 'proto' */
+       /* ip proto 'proto' and not a fragment other than the first fragment */
        tmp = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)proto);
        b0 = gen_ipfrag();
        gen_and(tmp, b0);
@@ -4945,6 +5148,7 @@ gen_portop6(port, proto, dir)
        struct block *b0, *b1, *tmp;
 
        /* ip6 proto 'proto' */
+       /* XXX - catch the first fragment of a fragmented packet? */
        b0 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)proto);
 
        switch (dir) {
@@ -5046,7 +5250,7 @@ gen_portrangeop(port1, port2, proto, dir)
 {
        struct block *b0, *b1, *tmp;
 
-       /* ip proto 'proto' */
+       /* ip proto 'proto' and not a fragment other than the first fragment */
        tmp = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)proto);
        b0 = gen_ipfrag();
        gen_and(tmp, b0);
@@ -5150,6 +5354,7 @@ gen_portrangeop6(port1, port2, proto, dir)
        struct block *b0, *b1, *tmp;
 
        /* ip6 proto 'proto' */
+       /* XXX - catch the first fragment of a fragmented packet? */
        b0 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)proto);
 
        switch (dir) {
@@ -5427,12 +5632,9 @@ gen_protochain(v, proto, dir)
 
                /*
                 * in short,
-                * A = P[X];
-                * X = X + (P[X + 1] + 1) * 8;
+                * A = P[X + packet head];
+                * X = X + (P[X + packet head + 1] + 1) * 8;
                 */
-               /* A = X */
-               s[i] = new_stmt(BPF_MISC|BPF_TXA);
-               i++;
                /* A = P[X + packet head] */
                s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
                s[i]->s.k = off_macpl + off_nl;
@@ -5441,19 +5643,9 @@ gen_protochain(v, proto, dir)
                s[i] = new_stmt(BPF_ST);
                s[i]->s.k = reg2;
                i++;
-               /* A = X */
-               s[i] = new_stmt(BPF_MISC|BPF_TXA);
-               i++;
-               /* A += 1 */
-               s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
-               s[i]->s.k = 1;
-               i++;
-               /* X = A */
-               s[i] = new_stmt(BPF_MISC|BPF_TAX);
-               i++;
-               /* A = P[X + packet head]; */
+               /* A = P[X + packet head + 1]; */
                s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
-               s[i]->s.k = off_macpl + off_nl;
+               s[i]->s.k = off_macpl + off_nl + 1;
                i++;
                /* A += 1 */
                s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
@@ -5463,6 +5655,10 @@ gen_protochain(v, proto, dir)
                s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K);
                s[i]->s.k = 8;
                i++;
+               /* A += X */
+               s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_X);
+               s[i]->s.k = 0;
+               i++;
                /* X = A; */
                s[i] = new_stmt(BPF_MISC|BPF_TAX);
                i++;
@@ -5786,6 +5982,10 @@ gen_proto(v, proto, dir)
                bpf_error("'vrrp proto' is bogus");
                /* NOTREACHED */
 
+       case Q_CARP:
+               bpf_error("'carp proto' is bogus");
+               /* NOTREACHED */
+
 #ifdef INET6
        case Q_IPV6:
                b0 = gen_linktype(ETHERTYPE_IPV6);
@@ -5869,6 +6069,8 @@ gen_scode(name, q)
                        switch (linktype) {
 
                        case DLT_EN10MB:
+                       case DLT_NETANALYZER:
+                       case DLT_NETANALYZER_TRANSPARENT:
                                eaddr = pcap_ether_hostton(name);
                                if (eaddr == NULL)
                                        bpf_error(
@@ -5969,6 +6171,7 @@ gen_scode(name, q)
                        res0 = res = pcap_nametoaddrinfo(name);
                        if (res == NULL)
                                bpf_error("unknown host '%s'", name);
+                       ai = res;
                        b = tmp = NULL;
                        tproto = tproto6 = proto;
                        if (off_linktype == -1 && tproto == Q_DEFAULT) {
@@ -6002,6 +6205,7 @@ gen_scode(name, q)
                                        gen_or(b, tmp);
                                b = tmp;
                        }
+                       ai = NULL;
                        freeaddrinfo(res0);
                        if (b == NULL) {
                                bpf_error("unknown host '%s'%s", name,
@@ -6048,6 +6252,10 @@ gen_scode(name, q)
                                /* override PROTO_UNDEF */
                                real_proto = IPPROTO_SCTP;
                }
+               if (port < 0)
+                       bpf_error("illegal port number %d < 0", port);
+               if (port > 65535)
+                       bpf_error("illegal port number %d > 65535", port);
 #ifndef INET6
                return gen_port(port, real_proto, dir);
 #else
@@ -6089,6 +6297,15 @@ gen_scode(name, q)
                                /* override PROTO_UNDEF */
                                real_proto = IPPROTO_SCTP;      
                }
+               if (port1 < 0)
+                       bpf_error("illegal port number %d < 0", port1);
+               if (port1 > 65535)
+                       bpf_error("illegal port number %d > 65535", port1);
+               if (port2 < 0)
+                       bpf_error("illegal port number %d < 0", port2);
+               if (port2 > 65535)
+                       bpf_error("illegal port number %d > 65535", port2);
+
 #ifndef INET6
                return gen_portrange(port1, port2, real_proto, dir);
 #else
@@ -6240,6 +6457,9 @@ gen_ncode(s, v, q)
                else
                        bpf_error("illegal qualifier of 'port'");
 
+               if (v > 65535)
+                       bpf_error("illegal port number %u > 65535", v);
+
 #ifndef INET6
                return gen_port((int)v, proto, dir);
 #else
@@ -6263,6 +6483,9 @@ gen_ncode(s, v, q)
                else
                        bpf_error("illegal qualifier of 'portrange'");
 
+               if (v > 65535)
+                       bpf_error("illegal port number %u > 65535", v);
+
 #ifndef INET6
                return gen_portrange((int)v, (int)v, proto, dir);
 #else
@@ -6314,6 +6537,7 @@ gen_mcode6(s1, s2, masklen, q)
        res = pcap_nametoaddrinfo(s1);
        if (!res)
                bpf_error("invalid ip6 address %s", s1);
+       ai = res;
        if (res->ai_next)
                bpf_error("%s resolved to multiple address", s1);
        addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
@@ -6344,6 +6568,7 @@ gen_mcode6(s1, s2, masklen, q)
 
        case Q_NET:
                b = gen_host6(addr, &mask, q.proto, q.dir, q.addr);
+               ai = NULL;
                freeaddrinfo(res);
                return b;
 
@@ -6365,6 +6590,8 @@ gen_ecode(eaddr, q)
        if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
                switch (linktype) {
                case DLT_EN10MB:
+               case DLT_NETANALYZER:
+               case DLT_NETANALYZER_TRANSPARENT:
                        return gen_ehostop(eaddr, (int)q.dir);
                case DLT_FDDI:
                        return gen_fhostop(eaddr, (int)q.dir);
@@ -6494,7 +6721,7 @@ gen_load(proto, inst, size)
 
                /*
                 * Load into the X register the offset computed into the
-                * register specifed by "index".
+                * register specified by "index".
                 */
                s = xfer_to_x(inst);
 
@@ -6526,7 +6753,7 @@ gen_load(proto, inst, size)
                 * the link-layer header.  Add to it the offset computed
                 * into the register specified by "index", and move that
                 * into the X register.  Otherwise, just load into the X
-                * register the offset computed into the register specifed
+                * register the offset computed into the register specified
                 * by "index".
                 */
                if (s != NULL) {
@@ -6575,7 +6802,7 @@ gen_load(proto, inst, size)
                 * payload.  Add to it the offset computed into the
                 * register specified by "index", and move that into
                 * the X register.  Otherwise, just load into the X
-                * register the offset computed into the register specifed
+                * register the offset computed into the register specified
                 * by "index".
                 */
                if (s != NULL) {
@@ -6620,6 +6847,7 @@ gen_load(proto, inst, size)
        case Q_IGRP:
        case Q_PIM:
        case Q_VRRP:
+       case Q_CARP:
                /*
                 * The offset is relative to the beginning of
                 * the transport-layer header.
@@ -6968,6 +7196,8 @@ gen_broadcast(proto)
                case DLT_ARCNET_LINUX:
                        return gen_ahostop(abroadcast, Q_DST);
                case DLT_EN10MB:
+               case DLT_NETANALYZER:
+               case DLT_NETANALYZER_TRANSPARENT:
                        return gen_ehostop(ebroadcast, Q_DST);
                case DLT_FDDI:
                        return gen_fhostop(ebroadcast, Q_DST);
@@ -7006,6 +7236,13 @@ gen_broadcast(proto)
                break;
 
        case Q_IP:
+               /*
+                * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff)
+                * as an indication that we don't know the netmask, and fail
+                * in that case.
+                */
+               if (netmask == PCAP_NETMASK_UNKNOWN)
+                       bpf_error("netmask not known, so 'ip broadcast' not supported");
                b0 = gen_linktype(ETHERTYPE_IP);
                hostmask = ~netmask;
                b1 = gen_mcmp(OR_NET, 16, BPF_W, (bpf_int32)0, hostmask);
@@ -7056,6 +7293,8 @@ gen_multicast(proto)
                        /* all ARCnet multicasts use the same address */
                        return gen_ahostop(abroadcast, Q_DST);
                case DLT_EN10MB:
+               case DLT_NETANALYZER:
+               case DLT_NETANALYZER_TRANSPARENT:
                        /* ether[0] & 1 != 0 */
                        return gen_mac_multicast(0);
                case DLT_FDDI:
@@ -7253,6 +7492,16 @@ gen_inbound(dir)
                          dir);
                break;
 
+       case DLT_IPNET:
+               if (dir) {
+                       /* match outgoing packets */
+                       b0 = gen_cmp(OR_LINK, 2, BPF_H, IPNET_OUTBOUND);
+               } else {
+                       /* match incoming packets */
+                       b0 = gen_cmp(OR_LINK, 2, BPF_H, IPNET_INBOUND);
+               }
+               break;
+
        case DLT_LINUX_SLL:
                if (dir) {
                        /*
@@ -7309,6 +7558,11 @@ gen_inbound(dir)
         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) {
@@ -7589,6 +7843,30 @@ gen_ahostop(eaddr, dir)
                b1 = gen_ahostop(eaddr, Q_DST);
                gen_or(b0, b1);
                return b1;
+
+       case Q_ADDR1:
+               bpf_error("'addr1' is only supported on 802.11");
+               break;
+
+       case Q_ADDR2:
+               bpf_error("'addr2' is only supported on 802.11");
+               break;
+
+       case Q_ADDR3:
+               bpf_error("'addr3' is only supported on 802.11");
+               break;
+
+       case Q_ADDR4:
+               bpf_error("'addr4' is only supported on 802.11");
+               break;
+
+       case Q_RA:
+               bpf_error("'ra' is only supported on 802.11");
+               break;
+
+       case Q_TA:
+               bpf_error("'ta' is only supported on 802.11");
+               break;
        }
        abort();
        /* NOTREACHED */
@@ -7643,9 +7921,15 @@ gen_vlan(vlan_num)
        switch (linktype) {
 
        case DLT_EN10MB:
-               /* check for VLAN */
+       case DLT_NETANALYZER:
+       case DLT_NETANALYZER_TRANSPARENT:
+               /* check for VLAN, including QinQ */
                b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
                    (bpf_int32)ETHERTYPE_8021Q);
+               b1 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+                   (bpf_int32)ETHERTYPE_8021QINQ);
+               gen_or(b0,b1);
+               b0 = b1;
 
                /* If a specific VLAN is requested, check VLAN id */
                if (vlan_num >= 0) {
@@ -7706,6 +7990,8 @@ gen_mpls(label_num)
                 
             case DLT_C_HDLC: /* fall through */
             case DLT_EN10MB:
+            case DLT_NETANALYZER:
+            case DLT_NETANALYZER_TRANSPARENT:
                     b0 = gen_linktype(ETHERTYPE_MPLS);
                     break;