Update to libpcap-1.0.0.
authorPeter Avalos <pavalos@theshell.com>
Mon, 6 Jul 2009 00:17:07 +0000 (14:17 -1000)
committerPeter Avalos <pavalos@theshell.com>
Mon, 6 Jul 2009 01:29:52 +0000 (15:29 -1000)
84 files changed:
contrib/libpcap/CHANGES
contrib/libpcap/README
contrib/libpcap/README.DELETED
contrib/libpcap/VERSION
contrib/libpcap/atmuni31.h
contrib/libpcap/bpf/net/bpf_filter.c
contrib/libpcap/bpf_dump.c
contrib/libpcap/bpf_image.c
contrib/libpcap/etherent.c
contrib/libpcap/ethertype.h
contrib/libpcap/fad-getad.c
contrib/libpcap/gencode.c
contrib/libpcap/gencode.h
contrib/libpcap/grammar.y
contrib/libpcap/inet.c
contrib/libpcap/nametoaddr.c
contrib/libpcap/optimize.c
contrib/libpcap/pcap-bpf.c
contrib/libpcap/pcap-bpf.h [deleted file]
contrib/libpcap/pcap-filter.manmisc.in [new file with mode: 0644]
contrib/libpcap/pcap-int.h
contrib/libpcap/pcap-linktype.manmisc.in [new file with mode: 0644]
contrib/libpcap/pcap-namedb.h
contrib/libpcap/pcap-savefile.manfile.in [new file with mode: 0644]
contrib/libpcap/pcap.3 [deleted file]
contrib/libpcap/pcap.3pcap.in [new file with mode: 0644]
contrib/libpcap/pcap.c
contrib/libpcap/pcap.h
contrib/libpcap/pcap/namedb.h [copied from contrib/libpcap/pcap-namedb.h with 97% similarity]
contrib/libpcap/pcap/pcap.h [copied from contrib/libpcap/pcap.h with 77% similarity]
contrib/libpcap/pcap/sll.h [moved from contrib/libpcap/sll.h with 94% similarity]
contrib/libpcap/pcap/usb.h [new file with mode: 0644]
contrib/libpcap/pcap_activate.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_breakloop.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_can_set_rfmon.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_close.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_compile.3pcap.in [new file with mode: 0644]
contrib/libpcap/pcap_create.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_datalink.3pcap.in [new file with mode: 0644]
contrib/libpcap/pcap_datalink_name_to_val.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_datalink_val_to_name.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_dump.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_dump_close.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_dump_file.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_dump_flush.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_dump_ftell.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_dump_open.3pcap.in [new file with mode: 0644]
contrib/libpcap/pcap_file.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_fileno.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_findalldevs.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_free_datalinks.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_freealldevs.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_freecode.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_get_selectable_fd.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_geterr.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_inject.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_is_swapped.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_lib_version.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_list_datalinks.3pcap.in [new file with mode: 0644]
contrib/libpcap/pcap_lookupdev.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_lookupnet.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_loop.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_major_version.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_next_ex.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_offline_filter.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_open_dead.3pcap.in [new file with mode: 0644]
contrib/libpcap/pcap_open_live.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_open_offline.3pcap.in [new file with mode: 0644]
contrib/libpcap/pcap_set_buffer_size.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_set_datalink.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_set_promisc.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_set_rfmon.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_set_snaplen.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_set_timeout.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_setdirection.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_setfilter.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_setnonblock.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_snapshot.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_stats.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_statustostr.3pcap [new file with mode: 0644]
contrib/libpcap/pcap_strerror.3pcap [new file with mode: 0644]
contrib/libpcap/pf.h [deleted file]
contrib/libpcap/savefile.c
contrib/libpcap/scanner.l

index 536e1a2..dc4e006 100644 (file)
@@ -1,28 +1,41 @@
-@(#) $Header: /tcpdump/master/libpcap/CHANGES,v 1.59.2.13 2007/09/12 22:40:04 ken Exp $ (LBL)
-
-Mon.   September 10, 2007.  ken@xelerance.com.  Summary for 0.9.8 libpcap release
-       Change build process to put public libpcap headers into pcap subir
-       DLT: Add value for IPMI IPMB packets
-       DLT: Add value for u10 Networks boards
-       Require <net/pfvar.h> for pf definitions - allows reading of pflog formatted 
-        libpcap files on an OS other than where the file was generated
-
-Wed.   July 23, 2007.  mcr@xelerance.com.  Summary for 0.9.7 libpcap release
-
-       FIXED version file to be 0.9.7 instead of 0.9.5.
-       added flags/configuration for cloning bpf device.
-       added DLT_MTP2_WITH_PHDR support (PPI)
-        "fix" the "memory leak" in icode_to_fcode() -- documentation bug
-        Various link-layer types, with a pseudo-header, for SITA http://www.sita.aero/
-       introduces support for the DAG ERF type TYPE_COLOR_MC_HDLC_POS.
-       Basic BPF filtering support for DLT_MTP2_WITH_PHDR is also added.
-        check for IPv4 and IPv6, even for DLT_RAW 
-       add support for DLT_JUNIPER_ISM
-       Pick up changes from NetBSD: many from tron, christos, drochner
-       Allocate DLT_ for 802.15.4 without any header munging, for Mikko Saarnivala.
-       Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header
-
-Wed.   April 25, 2007. ken@xelerance.com.  Summary for 0.9.6 libpcap release
+@(#) $Header: /tcpdump/master/libpcap/CHANGES,v 1.67.2.4 2008-10-28 00:27:42 ken Exp $ (LBL)
+
+Mon.    October 27, 2008.  ken@netfunctional.ca.  Summary for 1.0.0 libpcap release
+       Compile with IPv6 support by default
+       Compile with large file support on by default
+       Add pcap-config script, which deals with -I/-L flags for compiling
+       DLT: Add IPMB
+       DLT: Add LAPD
+       DLT: Add AX25 (AX.25 w/KISS header)
+       DLT: Add JUNIPER_ST
+       802.15.4 support
+       Variable length 802.11 header support
+       X2E data type support 
+       SITA ACN Interface support - see README.sita
+       Support for zerocopy BPF on platforms that support it
+       Better support for dealing with VLAN tagging/stripping on Linux
+       Fix dynamic library support on OSX
+       Return PCAP_ERROR_IFACE_NOT_UP if the interface isn't 'UP', so applications
+        can print better diagnostic information
+       Return PCAP_ERROR_PERM_DENIED if we don't have permission to open a device, so
+        applications can tell the user they need to go play with permissions
+       On Linux, ignore ENETDOWN so we can continue to capture packets if the 
+        interface goes down and comes back up again.
+       On Linux, support new tpacket frame headers (2.6.27+)
+       On Mac OS X, add scripts for changing permissions on /dev/pbf* and launchd plist
+       On Solaris, support 'passive mode' on systems that support it
+       Fixes to autoconf and general build environment
+       Man page reorganization + cleanup
+       Autogenerate VERSION numbers better
+
+Mon.    September 10, 2007.  ken@xelerance.com.  Summary for 0.9.8 libpcap release
+        Change build process to put public libpcap headers into pcap subir
+        DLT: Add value for IPMI IPMB packets
+        DLT: Add value for u10 Networks boards
+        Require <net/pfvar.h> for pf definitions - allows reading of pflog formatted 
+         libpcap files on an OS other than where the file was generated
+
+Wed.   April 25, 2007.  ken@xelerance.com.  Summary for 0.9.6 libpcap release
 
        Put the public libpcap headers into a pcap subdirectory in both the
         source directory and the target include directory, and have include
index 90571a1..ee1a141 100644 (file)
@@ -1,20 +1,22 @@
-@(#) $Header: /tcpdump/master/libpcap/README,v 1.30 2004/10/12 02:02:28 guy Exp $ (LBL)
+@(#) $Header: /tcpdump/master/libpcap/README,v 1.30.4.3 2008-10-17 10:39:20 ken Exp $ (LBL)
 
-LIBPCAP 0.9
-Now maintained by "The Tcpdump Group"
-See            www.tcpdump.org
+LIBPCAP 1.0.0
 
-Please send inquiries/comments/reports to      tcpdump-workers@tcpdump.org
+www.tcpdump.org
+
+Please send inquiries/comments/reports to:
+       tcpdump-workers@lists.tcpdump.org
 
 Anonymous CVS is available via:
        cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master login
        (password "anoncvs")
        cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master checkout libpcap
 
-Version 0.9 of LIBPCAP can be retrieved with the CVS tag "libpcap_0_9rel1":
-       cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master checkout -r libpcap_0_9rel1 libpcap
+Version 1.0.0 of LIBPCAP can be retrieved with the CVS tag "libpcap_1_0":
+       cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master checkout -r libpcap_1_0 libpcap
 
-Please send patches against the master copy to patches@tcpdump.org.
+Please submit patches against the master copy to the libpcap project on
+sourceforge.net.
 
 formerly from  Lawrence Berkeley National Laboratory
                Network Research Group <libpcap@ee.lbl.gov>
@@ -30,8 +32,6 @@ require this functionality, we've created this system-independent API
 to ease in porting and to alleviate the need for several
 system-dependent packet capture modules in each application.
 
-Note well: this interface is new and is likely to change.
-
 For some platforms there are README.{system} files that discuss issues
 with the OS's interface for packet capture on those platforms, such as
 how to enable support for that interface in the OS, if it's not built in
@@ -77,16 +77,28 @@ Linux, in the 2.2 kernel and later kernels, has a "Socket Filter"
 mechanism that accepts BPF filters; see the README.linux file for
 information on configuring that option.
 
+Note to Linux distributions and *BSD systems that include libpcap:
+
+There's now a rule to make a shared library, which should work on Linux 
+and *BSD (and OS X).
+
+It sets the soname of the library to "libpcap.so.1"; this is what it 
+should be, *NOT* libpcap.so.1.0 or libpcap.so.1.0.0 or something such as 
+that.
+
+We've been maintaining binary compatibility between libpcap releases for 
+quite a while; there's no reason to tie a binary linked with libpcap to 
+a particular release of libpcap.
+
 Problems, bugs, questions, desirable enhancements, etc. should be sent
-to the address "tcpdump-workers@tcpdump.org".  Bugs, support requests,
-and feature requests may also be submitted on the SourceForge site for
-libpcap at
+to the address "tcpdump-workers@lists.tcpdump.org".  Bugs, support
+requests, and feature requests may also be submitted on the SourceForge
+site for libpcap at
 
        http://sourceforge.net/projects/libpcap/
 
 Source code contributions, etc. should be sent to the email address
-"patches@tcpdump.org", or submitted as patches on the SourceForge site
-for libpcap.
+submitted as patches on the SourceForge site for libpcap.
 
 Current versions can be found at www.tcpdump.org, or the SourceForge
 site for libpcap.
index 2bb3acd..f6a678a 100644 (file)
@@ -1,11 +1,5 @@
-.#CHANGES.1.59
-.#Makefile.in.1.99.2.1
-.cvsignore
-CHANGES~
 CREDITS
-CVS/
 ChmodBPF/
-FILES
 INSTALL.txt
 Makefile.in
 README.Win32
@@ -15,51 +9,66 @@ README.hpux
 README.linux
 README.macosx
 README.septel
+README.sita
 README.tru64
 SUNOS4/
 TODO
 Win32/
 acconfig.h
 aclocal.m4
-bpf/CVS/
-bpf/net/CVS/
+bpf_filter.c
+chmod_bpf
 config.guess
 config.h.in
 config.sub
 configure
 configure.in
-doc/
+dlpisubs.c
+dlpisubs.h
 fad-gifc.c
 fad-glifc.c
 fad-null.c
+fad-sita.c
 fad-win32.c
-gencode.c.orig
-gencode.c.rej
+filtertest.c
+findalldevstest.c
+ieee80211.h
 install-sh
 lbl/
-libpcap-0.9
 missing/
 mkdep
 msdos/
-net
+net/
+org.tcpdump.chmod_bpf.plist
 packaging/
+pcap/bluetooth.h
+pcap/bpf.h
+pcap/vlan.h
+pcap-bpf.h
+pcap-bt-linux.c
+pcap-bt-linux.h
+pcap-config.1
+pcap-config.in
 pcap-dag.c
 pcap-dag.h
 pcap-dlpi.c
 pcap-dos.c
 pcap-dos.h
 pcap-enet.c
+pcap-libdlpi.c
 pcap-linux.c
 pcap-nit.c
-pcap-nit.h
 pcap-null.c
 pcap-pf.c
-pcap-pf.h
 pcap-septel.c
 pcap-septel.h
+pcap-sita.c
+pcap-sita.h
+pcap-sita.html
 pcap-snit.c
 pcap-snoop.c
 pcap-stdinc.h
+pcap-usb-linux.c
+pcap-usb-linux.h
 pcap-win32.c
-pcap1.h
-wlan_filtering.patch
+runlex.sh
index 877ed68..11242b8 100644 (file)
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- * @(#) $Header: /tcpdump/master/libpcap/atmuni31.h,v 1.1 2002/07/11 09:06:32 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/atmuni31.h,v 1.1.6.2 2007/10/22 19:30:14 guy Exp $ (LBL)
  */
 
 /* Based on UNI3.1 standard by ATM Forum */
 
 /* ATM traffic types based on VPI=0 and (the following VCI */
-#define PPC                    0x05    /* Point-to-point signal msg */
-#define BCC                    0x02    /* Broadcast signal msg */
-#define OAMF4SC                        0x03    /* Segment OAM F4 flow cell */
-#define OAMF4EC                        0x04    /* End-to-end OAM F4 flow cell */
-#define METAC                  0x01    /* Meta signal msg */
-#define ILMIC                  0x10    /* ILMI msg */
+#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 */
index 40df32a..a2733d1 100644 (file)
@@ -40,7 +40,7 @@
 
 #if !(defined(lint) || defined(KERNEL) || defined(_KERNEL))
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/bpf/net/bpf_filter.c,v 1.44 2003/11/15 23:24:07 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/bpf/net/bpf_filter.c,v 1.45.2.1 2008/01/02 04:22:16 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -71,7 +71,7 @@ static const char rcsid[] _U_ =
 
 #endif /* WIN32 */
 
-#include <pcap-bpf.h>
+#include <pcap/bpf.h>
 
 #if !defined(KERNEL) && !defined(_KERNEL)
 #include <stdlib.h>
@@ -200,8 +200,8 @@ m_xhalf(m, k, err)
  */
 u_int
 bpf_filter(pc, p, wirelen, buflen)
-       register struct bpf_insn *pc;
-       register u_char *p;
+       register const struct bpf_insn *pc;
+       register const u_char *p;
        u_int wirelen;
        register u_int buflen;
 {
@@ -512,54 +512,155 @@ bpf_filter(pc, p, wirelen, buflen)
        }
 }
 
-
 /*
  * Return true if the 'fcode' is a valid filter program.
  * The constraints are that each jump be forward and to a valid
- * code.  The code must terminate with either an accept or reject.
- * 'valid' is an array for use by the routine (it must be at least
- * 'len' bytes long).
+ * code, that memory accesses are within valid ranges (to the
+ * extent that this can be checked statically; loads of packet
+ * data have to be, and are, also checked at run time), and that
+ * the code terminates with either an accept or reject.
  *
  * The kernel needs to be able to verify an application's filter code.
  * Otherwise, a bogus program could easily crash the system.
  */
 int
 bpf_validate(f, len)
-       struct bpf_insn *f;
+       const struct bpf_insn *f;
        int len;
 {
-       register int i;
-       register struct bpf_insn *p;
+       u_int i, from;
+       const struct bpf_insn *p;
+
+       if (len < 1)
+               return 0;
+       /*
+        * There's no maximum program length in userland.
+        */
+#if defined(KERNEL) || defined(_KERNEL)
+       if (len > BPF_MAXINSNS)
+               return 0;
+#endif
 
        for (i = 0; i < len; ++i) {
+               p = &f[i];
+               switch (BPF_CLASS(p->code)) {
                /*
-                * Check that that jumps are forward, and within
-                * the code block.
+                * Check that memory operations use valid addresses.
                 */
-               p = &f[i];
-               if (BPF_CLASS(p->code) == BPF_JMP) {
-                       register int from = i + 1;
-
-                       if (BPF_OP(p->code) == BPF_JA) {
-                               if (from + p->k >= (unsigned)len)
+               case BPF_LD:
+               case BPF_LDX:
+                       switch (BPF_MODE(p->code)) {
+                       case BPF_IMM:
+                               break;
+                       case BPF_ABS:
+                       case BPF_IND:
+                       case BPF_MSH:
+                               /*
+                                * There's no maximum packet data size
+                                * in userland.  The runtime packet length
+                                * check suffices.
+                                */
+#if defined(KERNEL) || defined(_KERNEL)
+                               /*
+                                * More strict check with actual packet length
+                                * is done runtime.
+                                */
+                               if (p->k >= bpf_maxbufsize)
                                        return 0;
+#endif
+                               break;
+                       case BPF_MEM:
+                               if (p->k >= BPF_MEMWORDS)
+                                       return 0;
+                               break;
+                       case BPF_LEN:
+                               break;
+                       default:
+                               return 0;
                        }
-                       else if (from + p->jt >= len || from + p->jf >= len)
+                       break;
+               case BPF_ST:
+               case BPF_STX:
+                       if (p->k >= BPF_MEMWORDS)
                                return 0;
-               }
-               /*
-                * Check that memory operations use valid addresses.
-                */
-               if ((BPF_CLASS(p->code) == BPF_ST ||
-                    (BPF_CLASS(p->code) == BPF_LD &&
-                     (p->code & 0xe0) == BPF_MEM)) &&
-                   (p->k >= BPF_MEMWORDS || p->k < 0))
-                       return 0;
-               /*
-                * Check for constant division by 0.
-                */
-               if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
+                       break;
+               case BPF_ALU:
+                       switch (BPF_OP(p->code)) {
+                       case BPF_ADD:
+                       case BPF_SUB:
+                       case BPF_MUL:
+                       case BPF_OR:
+                       case BPF_AND:
+                       case BPF_LSH:
+                       case BPF_RSH:
+                       case BPF_NEG:
+                               break;
+                       case BPF_DIV:
+                               /*
+                                * Check for constant division by 0.
+                                */
+                               if (BPF_RVAL(p->code) == BPF_K && p->k == 0)
+                                       return 0;
+                               break;
+                       default:
+                               return 0;
+                       }
+                       break;
+               case BPF_JMP:
+                       /*
+                        * Check that jumps are within the code block,
+                        * and that unconditional branches don't go
+                        * backwards as a result of an overflow.
+                        * Unconditional branches have a 32-bit offset,
+                        * so they could overflow; we check to make
+                        * sure they don't.  Conditional branches have
+                        * an 8-bit offset, and the from address is <=
+                        * BPF_MAXINSNS, and we assume that BPF_MAXINSNS
+                        * is sufficiently small that adding 255 to it
+                        * won't overflow.
+                        *
+                        * We know that len is <= BPF_MAXINSNS, and we
+                        * assume that BPF_MAXINSNS is < the maximum size
+                        * of a u_int, so that i + 1 doesn't overflow.
+                        *
+                        * For userland, we don't know that the from
+                        * or len are <= BPF_MAXINSNS, but we know that
+                        * from <= len, and, except on a 64-bit system,
+                        * it's unlikely that len, if it truly reflects
+                        * the size of the program we've been handed,
+                        * will be anywhere near the maximum size of
+                        * a u_int.  We also don't check for backward
+                        * branches, as we currently support them in
+                        * userland for the protochain operation.
+                        */
+                       from = i + 1;
+                       switch (BPF_OP(p->code)) {
+                       case BPF_JA:
+#if defined(KERNEL) || defined(_KERNEL)
+                               if (from + p->k < from || from + p->k >= len)
+#else
+                               if (from + p->k >= len)
+#endif
+                                       return 0;
+                               break;
+                       case BPF_JEQ:
+                       case BPF_JGT:
+                       case BPF_JGE:
+                       case BPF_JSET:
+                               if (from + p->jt >= len || from + p->jf >= len)
+                                       return 0;
+                               break;
+                       default:
+                               return 0;
+                       }
+                       break;
+               case BPF_RET:
+                       break;
+               case BPF_MISC:
+                       break;
+               default:
                        return 0;
+               }
        }
        return BPF_CLASS(f[len - 1].code) == BPF_RET;
 }
index 303602e..5c0033d 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/bpf_dump.c,v 1.14 2003/11/15 23:23:57 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/bpf_dump.c,v 1.14.4.1 2008/01/02 04:22:16 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -31,9 +31,9 @@ static const char rcsid[] _U_ =
 #include <stdio.h>
 
 void
-bpf_dump(struct bpf_program *p, int option)
+bpf_dump(const struct bpf_program *p, int option)
 {
-       struct bpf_insn *insn;
+       const struct bpf_insn *insn;
        int i;
        int n = p->bf_len;
 
index 2e76128..91f7cef 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/bpf_image.c,v 1.26.2.1 2007/06/11 09:52:04 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/bpf_image.c,v 1.27.2.1 2008/01/02 04:22:16 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -39,7 +39,7 @@ static const char rcsid[] _U_ =
 
 char *
 bpf_image(p, n)
-       struct bpf_insn *p;
+       const struct bpf_insn *p;
        int n;
 {
        int v;
index 9d29955..27e5502 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/etherent.c,v 1.22 2003/11/15 23:23:57 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/etherent.c,v 1.23 2006/10/04 18:09:22 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -37,7 +37,7 @@ static const char rcsid[] _U_ =
 
 #include "pcap-int.h"
 
-#include <pcap-namedb.h>
+#include <pcap/namedb.h>
 
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
index 2d21c6d..867d33e 100644 (file)
@@ -18,7 +18,7 @@
  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * @(#) $Header: /tcpdump/master/libpcap/ethertype.h,v 1.13.2.1 2005/09/05 09:08:03 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/ethertype.h,v 1.14 2005/09/05 09:06:58 guy Exp $ (LBL)
  */
 
 /*
index 8101165..2ce6d70 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/fad-getad.c,v 1.10.2.2 2007/09/14 00:45:17 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/fad-getad.c,v 1.12 2007/09/14 00:44:55 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
index d2cae21..41057ba 100644 (file)
@@ -21,7 +21,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.53 2007/09/12 19:17:24 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.16 2008-09-22 20:16:01 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -68,10 +68,11 @@ static const char rcsid[] _U_ =
 #include "nlpid.h"
 #include "llc.h"
 #include "gencode.h"
+#include "ieee80211.h"
 #include "atmuni31.h"
 #include "sunatmpos.h"
 #include "ppp.h"
-#include "sll.h"
+#include "pcap/sll.h"
 #include "arcnet.h"
 #ifdef HAVE_NET_PFVAR_H
 #include <sys/socket.h>
@@ -87,7 +88,7 @@ static const char rcsid[] _U_ =
 #include <netdb.h>     /* for "struct addrinfo" */
 #endif /* WIN32 */
 #endif /*INET6*/
-#include <pcap-namedb.h>
+#include <pcap/namedb.h>
 
 #define ETHERMTU       1500
 
@@ -105,8 +106,8 @@ static const char rcsid[] _U_ =
 static jmp_buf top_ctx;
 static pcap_t *bpf_pcap;
 
-#ifdef WIN32
 /* Hack for updating VLAN, MPLS, and PPPoE offsets. */
+#ifdef WIN32
 static u_int   orig_linktype = (u_int)-1, orig_nl = (u_int)-1, label_stack_depth = (u_int)-1;
 #else
 static u_int   orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;
@@ -134,6 +135,7 @@ bpf_error(const char *fmt, ...)
 
 static void init_linktype(pcap_t *);
 
+static void init_regs(void);
 static int alloc_reg(void);
 static void free_reg(int);
 
@@ -145,7 +147,8 @@ static struct block *root;
  */
 enum e_offrel {
        OR_PACKET,      /* relative to the beginning of the packet */
-       OR_LINK,        /* relative to the link-layer header */
+       OR_LINK,        /* relative to the beginning of the link-layer header */
+       OR_MACPL,       /* relative to the end of the MAC-layer header */
        OR_NET,         /* relative to the network-layer header */
        OR_NET_NOSNAP,  /* relative to the network-layer header, with no SNAP header at the link layer */
        OR_TRAN_IPV4,   /* relative to the transport-layer header, with IPv4 network layer */
@@ -190,6 +193,7 @@ static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *);
 static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32,
     bpf_u_int32, bpf_u_int32, int, bpf_int32);
 static struct slist *gen_load_llrel(u_int, u_int);
+static struct slist *gen_load_macplrel(u_int, u_int);
 static struct slist *gen_load_a(enum e_offrel, u_int, u_int);
 static struct slist *gen_loadx_iphdrlen(void);
 static struct block *gen_uncond(int);
@@ -197,12 +201,16 @@ static inline struct block *gen_true(void);
 static inline struct block *gen_false(void);
 static struct block *gen_ether_linktype(int);
 static struct block *gen_linux_sll_linktype(int);
-static void insert_radiotap_load_llprefixlen(struct block *);
-static void insert_ppi_load_llprefixlen(struct block *);
-static void insert_load_llprefixlen(struct block *);
+static struct slist *gen_load_prism_llprefixlen(void);
+static struct slist *gen_load_avs_llprefixlen(void);
+static struct slist *gen_load_radiotap_llprefixlen(void);
+static struct slist *gen_load_ppi_llprefixlen(void);
+static void insert_compute_vloffsets(struct block *);
 static struct slist *gen_llprefixlen(void);
+static struct slist *gen_off_macpl(void);
+static int ethertype_to_ppptype(int);
 static struct block *gen_linktype(int);
-static struct block *gen_snap(bpf_u_int32, bpf_u_int32, u_int);
+static struct block *gen_snap(bpf_u_int32, bpf_u_int32);
 static struct block *gen_llc_linktype(int);
 static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);
 #ifdef INET6
@@ -247,6 +255,7 @@ static struct slist *xfer_to_x(struct arth *);
 static struct slist *xfer_to_a(struct arth *);
 static struct block *gen_mac_multicast(int);
 static struct block *gen_len(int, int);
+static struct block *gen_check_802_11_data_frame(void);
 
 static struct block *gen_ppi_dlt_check(void);
 static struct block *gen_msg_abbrev(int type);
@@ -369,6 +378,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        n_errors = 0;
        root = NULL;
        bpf_pcap = p;
+       init_regs();
        if (setjmp(top_ctx)) {
                lex_cleanup();
                freechunks();
@@ -484,24 +494,11 @@ merge(b0, b1)
        *p = b1;
 }
 
-
 void
 finish_parse(p)
        struct block *p;
 {
        struct block *ppi_dlt_check;
-       
-       ppi_dlt_check = gen_ppi_dlt_check();
-
-       if (ppi_dlt_check != NULL)
-       {
-               gen_and(ppi_dlt_check, p);
-       }
-
-       backpatch(p, gen_retblk(snaplen));
-       p->sense = !p->sense;
-       backpatch(p, gen_retblk(0));
-       root = p->head;
 
        /*
         * Insert before the statements of the first (root) block any
@@ -512,14 +509,30 @@ finish_parse(p)
         * statements of all blocks that use those lengths and that
         * have no predecessors that use them, so that we only compute
         * the lengths if we need them.  There might be even better
-        * approaches than that.  However, as we're currently only
-        * handling variable-length radiotap headers, and as all
-        * filtering expressions other than raw link[M:N] tests
-        * require the length of that header, doing more for that
-        * header length isn't really worth the effort.
+        * approaches than that.
+        *
+        * However, those strategies would be more complicated, and
+        * as we don't generate code to compute a length if the
+        * program has no tests that use the length, and as most
+        * tests will probably use those lengths, we would just
+        * postpone computing the lengths so that it's not done
+        * for tests that fail early, and it's not clear that's
+        * worth the effort.
         */
+       insert_compute_vloffsets(p->head);
+       
+       /*
+        * For DLT_PPI captures, generate a check of the per-packet
+        * DLT value to make sure it's DLT_IEEE802_11.
+        */
+       ppi_dlt_check = gen_ppi_dlt_check();
+       if (ppi_dlt_check != NULL)
+               gen_and(ppi_dlt_check, p);
 
-       insert_load_llprefixlen(root);
+       backpatch(p, gen_retblk(snaplen));
+       p->sense = !p->sense;
+       backpatch(p, gen_retblk(0));
+       root = p->head;
 }
 
 void
@@ -682,13 +695,7 @@ gen_ncmp(offrel, offset, size, mask, jtype, reverse, v)
  * Various code constructs need to know the layout of the data link
  * layer.  These variables give the necessary offsets from the beginning
  * of the packet data.
- *
- * If the link layer has variable_length headers, the offsets are offsets
- * from the end of the link-link-layer header, and "reg_ll_size" is
- * the register number for a register containing the length of the
- * link-layer header.  Otherwise, "reg_ll_size" is -1.
  */
-static int reg_ll_size;
 
 /*
  * This is the offset of the beginning of the link-layer header from
@@ -701,13 +708,49 @@ static int reg_ll_size;
 static u_int off_ll;
 
 /*
- * This is the offset of the beginning of the MAC-layer header.
+ * If there's a variable-length header preceding the link-layer header,
+ * "reg_off_ll" is the register number for a register containing the
+ * length of that header, and therefore the offset of the link-layer
+ * header from the beginning of the raw packet data.  Otherwise,
+ * "reg_off_ll" is -1.
+ */
+static int reg_off_ll;
+
+/*
+ * This is the offset of the beginning of the MAC-layer header from
+ * the beginning of the link-layer header.
  * It's usually 0, except for ATM LANE, where it's the offset, relative
  * to the beginning of the raw packet data, of the Ethernet header.
  */
 static u_int off_mac;
 
 /*
+ * This is the offset of the beginning of the MAC-layer payload,
+ * from the beginning of the raw packet data.
+ *
+ * I.e., it's the sum of the length of the link-layer header (without,
+ * for example, any 802.2 LLC header, so it's the MAC-layer
+ * portion of that header), plus any prefix preceding the
+ * link-layer header.
+ */
+static u_int off_macpl;
+
+/*
+ * This is 1 if the offset of the beginning of the MAC-layer payload
+ * from the beginning of the link-layer header is variable-length.
+ */
+static int off_macpl_is_variable;
+
+/*
+ * If the link layer has variable_length headers, "reg_off_macpl"
+ * is the register number for a register containing the length of the
+ * link-layer header plus the length of any variable-length header
+ * preceding the link-layer header.  Otherwise, "reg_off_macpl"
+ * is -1.
+ */
+static int reg_off_macpl;
+
+/*
  * "off_linktype" is the offset to information in the link-layer header
  * giving the packet type.  This offset is relative to the beginning
  * of the link-layer header (i.e., it doesn't include off_ll).
@@ -730,6 +773,13 @@ static u_int off_mac;
 static u_int off_linktype;
 
 /*
+ * TRUE if "pppoes" appeared in the filter; it causes link-layer type
+ * checks to check the PPP header, assumed to follow a LAN-style link-
+ * layer header and a PPPoE session header.
+ */
+static int is_pppoes = 0;
+
+/*
  * TRUE if the link layer includes an ATM pseudo-header.
  */
 static int is_atm = 0;
@@ -768,8 +818,8 @@ static u_int off_payload;
 
 /*
  * These are offsets to the beginning of the network-layer header.
- * They are relative to the beginning of the link-layer header (i.e.,
- * they don't include off_ll).
+ * They are relative to the beginning of the MAC-layer payload (i.e.,
+ * they don't include off_ll or off_macpl).
  *
  * If the link layer never uses 802.2 LLC:
  *
@@ -816,6 +866,11 @@ init_linktype(p)
        off_payload = -1;
 
        /*
+        * And that we're not doing PPPoE.
+        */
+       is_pppoes = 0;
+
+       /*
         * And assume we're not doing SS7.
         */
        off_li = -1;
@@ -825,34 +880,40 @@ init_linktype(p)
        off_sls = -1;
 
        /*
-        * Also assume it's not 802.11 with a fixed-length radio header.
+        * Also assume it's not 802.11.
         */
        off_ll = 0;
+       off_macpl = 0;
+       off_macpl_is_variable = 0;
 
        orig_linktype = -1;
        orig_nl = -1;
         label_stack_depth = 0;
 
-       reg_ll_size = -1;
+       reg_off_ll = -1;
+       reg_off_macpl = -1;
 
        switch (linktype) {
 
        case DLT_ARCNET:
                off_linktype = 2;
-               off_nl = 6;             /* XXX in reality, variable! */
-               off_nl_nosnap = 6;      /* no 802.2 LLC */
+               off_macpl = 6;
+               off_nl = 0;             /* XXX in reality, variable! */
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_ARCNET_LINUX:
                off_linktype = 4;
-               off_nl = 8;             /* XXX in reality, variable! */
-               off_nl_nosnap = 8;      /* no 802.2 LLC */
+               off_macpl = 8;
+               off_nl = 0;             /* XXX in reality, variable! */
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_EN10MB:
                off_linktype = 12;
-               off_nl = 14;            /* Ethernet II */
-               off_nl_nosnap = 17;     /* 802.3+802.2 */
+               off_macpl = 14;         /* Ethernet header length */
+               off_nl = 0;             /* Ethernet II */
+               off_nl_nosnap = 3;      /* 802.3+802.2 */
                return;
 
        case DLT_SLIP:
@@ -861,29 +922,33 @@ init_linktype(p)
                 * header is hacked into our SLIP driver.
                 */
                off_linktype = -1;
-               off_nl = 16;
-               off_nl_nosnap = 16;     /* no 802.2 LLC */
+               off_macpl = 16;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_SLIP_BSDOS:
                /* XXX this may be the same as the DLT_PPP_BSDOS case */
                off_linktype = -1;
                /* XXX end */
-               off_nl = 24;
-               off_nl_nosnap = 24;     /* no 802.2 LLC */
+               off_macpl = 24;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_NULL:
        case DLT_LOOP:
                off_linktype = 0;
-               off_nl = 4;
-               off_nl_nosnap = 4;      /* no 802.2 LLC */
+               off_macpl = 4;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_ENC:
                off_linktype = 0;
-               off_nl = 12;
-               off_nl_nosnap = 12;     /* no 802.2 LLC */
+               off_macpl = 12;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_PPP:
@@ -891,8 +956,9 @@ init_linktype(p)
        case DLT_C_HDLC:                /* BSD/OS Cisco HDLC */
        case DLT_PPP_SERIAL:            /* NetBSD sync/async serial PPP */
                off_linktype = 2;
-               off_nl = 4;
-               off_nl_nosnap = 4;      /* no 802.2 LLC */
+               off_macpl = 4;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_PPP_ETHER:
@@ -901,14 +967,16 @@ init_linktype(p)
                 * only covers session state.
                 */
                off_linktype = 6;
-               off_nl = 8;
-               off_nl_nosnap = 8;      /* no 802.2 LLC */
+               off_macpl = 8;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_PPP_BSDOS:
                off_linktype = 5;
-               off_nl = 24;
-               off_nl_nosnap = 24;     /* no 802.2 LLC */
+               off_macpl = 24;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_FDDI:
@@ -924,12 +992,12 @@ init_linktype(p)
 #ifdef PCAP_FDDIPAD
                off_linktype += pcap_fddipad;
 #endif
-               off_nl = 21;            /* FDDI+802.2+SNAP */
-               off_nl_nosnap = 16;     /* FDDI+802.2 */
+               off_macpl = 13;         /* FDDI MAC header length */
 #ifdef PCAP_FDDIPAD
-               off_nl += pcap_fddipad;
-               off_nl_nosnap += pcap_fddipad;
+               off_macpl += pcap_fddipad;
 #endif
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_IEEE802:
@@ -957,11 +1025,15 @@ init_linktype(p)
                 * 8 - figure out which byte that is).
                 */
                off_linktype = 14;
-               off_nl = 22;            /* Token Ring+802.2+SNAP */
-               off_nl_nosnap = 17;     /* Token Ring+802.2 */
+               off_macpl = 14;         /* Token Ring MAC header length */
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
                /*
                 * 802.11 doesn't really have a link-level type field.
                 * We set "off_linktype" to the offset of the LLC header.
@@ -970,90 +1042,37 @@ init_linktype(p)
                 * is being used and pick out the encapsulated Ethernet type.
                 * XXX - should we generate code to check for SNAP?
                 *
-                * XXX - the header is actually variable-length.  We
-                * assume a 24-byte link-layer header, as appears in
-                * data frames in networks with no bridges.  If the
-                * fromds and tods 802.11 header bits are both set,
-                * it's actually supposed to be 30 bytes.
-                */
-               off_linktype = 24;
-               off_nl = 32;            /* 802.11+802.2+SNAP */
-               off_nl_nosnap = 27;     /* 802.11+802.2 */
-               return;
-
-       case DLT_PRISM_HEADER:
-               /*
-                * Same as 802.11, but with an additional header before
-                * the 802.11 header, containing a bunch of additional
-                * information including radio-level information.
-                *
-                * The header is 144 bytes long.
-                *
-                * XXX - same variable-length header problem; at least
-                * the Prism header is fixed-length.
+                * We also handle variable-length radio headers here.
+                * The Prism header is in theory variable-length, but in
+                * practice it's always 144 bytes long.  However, some
+                * drivers on Linux use ARPHRD_IEEE80211_PRISM, but
+                * sometimes or always supply an AVS header, so we
+                * have to check whether the radio header is a Prism
+                * header or an AVS header, so, in practice, it's
+                * variable-length.
                 */
-               off_ll = 144;
                off_linktype = 24;
-               off_nl = 32;    /* Prism+802.11+802.2+SNAP */
-               off_nl_nosnap = 27;     /* Prism+802.11+802.2 */
-               return;
-
-       case DLT_IEEE802_11_RADIO_AVS:
-               /*
-                * Same as 802.11, but with an additional header before
-                * the 802.11 header, containing a bunch of additional
-                * information including radio-level information.
-                *
-                * The header is 64 bytes long, at least in its
-                * current incarnation.
-                *
-                * XXX - same variable-length header problem, only
-                * more so; this header is also variable-length,
-                * with the length being the 32-bit big-endian
-                * number at an offset of 4 from the beginning
-                * of the radio header.  We should handle that the
-                * same way we handle the length at the beginning
-                * of the radiotap header.
-                *
-                * XXX - in Linux, do any drivers that supply an AVS
-                * header supply a link-layer type other than
-                * ARPHRD_IEEE80211_PRISM?  If so, we should map that
-                * to DLT_IEEE802_11_RADIO_AVS; if not, or if there are
-                * any drivers that supply an AVS header but supply
-                * an ARPHRD value of ARPHRD_IEEE80211_PRISM, we'll
-                * have to check the header in the generated code to
-                * determine whether it's Prism or AVS.
-                */
-               off_ll = 64;
-               off_linktype = 24;
-               off_nl = 32;            /* Radio+802.11+802.2+SNAP */
-               off_nl_nosnap = 27;     /* Radio+802.11+802.2 */
+               off_macpl = 0;          /* link-layer header is variable-length */
+               off_macpl_is_variable = 1;
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
-               
-               /* 
-                * At the moment we treat PPI as normal Radiotap encoded
-                * packets. The difference is in the function that generates
-                * the code at the beginning to compute the header length.
-                * Since this code generator of PPI supports bare 802.11
-                * encapsulation only (i.e. the encapsulated DLT should be
-                * DLT_IEEE802_11) we generate code to check for this too.
-                */
        case DLT_PPI:
-       case DLT_IEEE802_11_RADIO:
-               /*
-                * Same as 802.11, but with an additional header before
-                * the 802.11 header, containing a bunch of additional
-                * information including radio-level information.
-                *
-                * The radiotap header is variable length, and we
-                * generate code to compute its length and store it
-                * in a register.  These offsets are relative to the
-                * beginning of the 802.11 header.
+               /* 
+                * At the moment we treat PPI the same way that we treat
+                * normal Radiotap encoded packets. The difference is in
+                * the function that generates the code at the beginning
+                * to compute the header length.  Since this code generator
+                * of PPI supports bare 802.11 encapsulation only (i.e.
+                * the encapsulated DLT should be DLT_IEEE802_11) we
+                * generate code to check for this too.
                 */
                off_linktype = 24;
-               off_nl = 32;            /* 802.11+802.2+SNAP */
-               off_nl_nosnap = 27;     /* 802.11+802.2 */
+               off_macpl = 0;          /* link-layer header is variable-length */
+               off_macpl_is_variable = 1;
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_ATM_RFC1483:
@@ -1070,6 +1089,7 @@ init_linktype(p)
                 * PPPo{A,E} and a PPP protocol of IP and....
                 */
                off_linktype = 0;
+               off_macpl = 0;          /* packet begins with LLC header */
                off_nl = 8;             /* 802.2+SNAP */
                off_nl_nosnap = 3;      /* 802.2 */
                return;
@@ -1083,23 +1103,26 @@ init_linktype(p)
                off_vpi = SUNATM_VPI_POS;
                off_vci = SUNATM_VCI_POS;
                off_proto = PROTO_POS;
-               off_mac = -1;   /* LLC-encapsulated, so no MAC-layer header */
+               off_mac = -1;   /* assume LLC-encapsulated, so no MAC-layer header */
                off_payload = SUNATM_PKT_BEGIN_POS;
                off_linktype = off_payload;
-               off_nl = off_payload+8;         /* 802.2+SNAP */
-               off_nl_nosnap = off_payload+3;  /* 802.2 */
+               off_macpl = off_payload;        /* if LLC-encapsulated */
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_RAW:
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 0;
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_LINUX_SLL:     /* fake header for Linux cooked socket */
                off_linktype = 14;
-               off_nl = 16;
-               off_nl_nosnap = 16;     /* no 802.2 LLC */
+               off_macpl = 16;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_LTALK:
@@ -1109,6 +1132,7 @@ init_linktype(p)
                 * "long" DDP packet following.
                 */
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 0;
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
@@ -1125,8 +1149,9 @@ init_linktype(p)
                 * 2625 says SNAP should be used.
                 */
                off_linktype = 16;
-               off_nl = 24;            /* IPFC+802.2+SNAP */
-               off_nl_nosnap = 19;     /* IPFC+802.2 */
+               off_macpl = 16;
+               off_nl = 8;             /* 802.2+SNAP */
+               off_nl_nosnap = 3;      /* 802.2 */
                return;
 
        case DLT_FRELAY:
@@ -1135,6 +1160,7 @@ init_linktype(p)
                 * frames (NLPID of 0x80).
                 */
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 0;
                off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
@@ -1146,14 +1172,16 @@ init_linktype(p)
                  */
        case DLT_MFR:
                off_linktype = -1;
+               off_macpl = 0;
                off_nl = 4;
                off_nl_nosnap = 0;      /* XXX - for now -> no 802.2 LLC */
                return;
 
        case DLT_APPLE_IP_OVER_IEEE1394:
                off_linktype = 16;
-               off_nl = 18;
-               off_nl_nosnap = 18;     /* no 802.2 LLC */
+               off_macpl = 18;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 
        case DLT_LINUX_IRDA:
@@ -1161,6 +1189,7 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1170,21 +1199,24 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
 
        case DLT_SYMANTEC_FIREWALL:
                off_linktype = 6;
-               off_nl = 44;            /* Ethernet II */
-               off_nl_nosnap = 44;     /* XXX - what does it do with 802.3 packets? */
+               off_macpl = 44;
+               off_nl = 0;             /* Ethernet II */
+               off_nl_nosnap = 0;      /* XXX - what does it do with 802.3 packets? */
                return;
 
 #ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                off_linktype = 0;
-               off_nl = PFLOG_HDRLEN;
-               off_nl_nosnap = PFLOG_HDRLEN;   /* no 802.2 LLC */
+               off_macpl = PFLOG_HDRLEN;
+               off_nl = 0;
+               off_nl_nosnap = 0;      /* no 802.2 LLC */
                return;
 #endif
 
@@ -1195,26 +1227,30 @@ init_linktype(p)
         case DLT_JUNIPER_CHDLC:
         case DLT_JUNIPER_FRELAY:
                 off_linktype = 4;
-               off_nl = 4;
+               off_macpl = 4;
+               off_nl = 0;
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                 return;
 
        case DLT_JUNIPER_ATM1:
-               off_linktype = 4; /* in reality variable between 4-8 */
-               off_nl = 4;
-               off_nl_nosnap = 14;
+               off_linktype = 4;       /* in reality variable between 4-8 */
+               off_macpl = 4;  /* in reality variable between 4-8 */
+               off_nl = 0;
+               off_nl_nosnap = 10;
                return;
 
        case DLT_JUNIPER_ATM2:
-               off_linktype = 8; /* in reality variable between 8-12 */
-               off_nl = 8;
-               off_nl_nosnap = 18;
+               off_linktype = 8;       /* in reality variable between 8-12 */
+               off_macpl = 8;  /* in reality variable between 8-12 */
+               off_nl = 0;
+               off_nl_nosnap = 10;
                return;
 
                /* frames captured on a Juniper PPPoE service PIC
                 * contain raw ethernet frames */
        case DLT_JUNIPER_PPPOE:
         case DLT_JUNIPER_ETHER:
+               off_macpl = 14;
                off_linktype = 16;
                off_nl = 18;            /* Ethernet II */
                off_nl_nosnap = 21;     /* 802.3+802.2 */
@@ -1222,36 +1258,56 @@ init_linktype(p)
 
        case DLT_JUNIPER_PPPOE_ATM:
                off_linktype = 4;
-               off_nl = 6;
-               off_nl_nosnap = -1;      /* no 802.2 LLC */
+               off_macpl = 6;
+               off_nl = 0;
+               off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_GGSN:
                off_linktype = 6;
-               off_nl = 12;
-               off_nl_nosnap = -1;      /* no 802.2 LLC */
+               off_macpl = 12;
+               off_nl = 0;
+               off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_ES:
                off_linktype = 6;
-               off_nl = -1;            /* not really a network layer but raw IP adresses */
+               off_macpl = -1;         /* not really a network layer but raw IP addresses */
+               off_nl = -1;            /* not really a network layer but raw IP addresses */
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_MONITOR:
                off_linktype = 12;
-               off_nl = 12;            /* raw IP/IP6 header */
+               off_macpl = 12;
+               off_nl = 0;             /* raw IP/IP6 header */
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_SERVICES:
                off_linktype = 12;
+               off_macpl = -1;         /* L3 proto location dep. on cookie type */
                off_nl = -1;            /* L3 proto location dep. on cookie type */
                off_nl_nosnap = -1;     /* no 802.2 LLC */
                return;
 
        case DLT_JUNIPER_VP:
                off_linktype = 18;
+               off_macpl = -1;
+               off_nl = -1;
+               off_nl_nosnap = -1;
+               return;
+
+       case DLT_JUNIPER_ST:
+               off_linktype = 18;
+               off_macpl = -1;
+               off_nl = -1;
+               off_nl_nosnap = -1;
+               return;
+
+       case DLT_JUNIPER_ISM:
+               off_linktype = 8;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1263,6 +1319,7 @@ init_linktype(p)
                off_dpc = 4;
                off_sls = 7;
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1274,6 +1331,19 @@ init_linktype(p)
                off_dpc = 8;
                off_sls = 11;
                off_linktype = -1;
+               off_macpl = -1;
+               off_nl = -1;
+               off_nl_nosnap = -1;
+               return;
+
+       case DLT_ERF:
+               off_li = 22;
+               off_sio = 23;
+               off_opc = 24;
+               off_dpc = 24;
+               off_sls = 27;
+               off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1281,8 +1351,9 @@ init_linktype(p)
 #ifdef DLT_PFSYNC
        case DLT_PFSYNC:
                off_linktype = -1;
-               off_nl = 4;
-               off_nl_nosnap = 4;
+               off_macpl = 4;
+               off_nl = 0;
+               off_nl_nosnap = 0;
                return;
 #endif
 
@@ -1291,6 +1362,7 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1300,6 +1372,7 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1309,6 +1382,118 @@ init_linktype(p)
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
                off_linktype = -1;
+               off_macpl = -1;
+               off_nl = -1;
+               off_nl_nosnap = -1;
+               return;
+
+       case DLT_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:
+               /*
+                * 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_RAIF1:
+               /*
+                * 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_IPMB:
+               /*
+                * 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_WITH_PHDR:
+               /*
+                * 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_AX25_KISS:
+               /*
+                * Currently, only raw "link[N:M]" filtering is supported.
+                */
+               off_linktype = -1;      /* variable, min 15, max 71 steps of 7 */
+               off_macpl = -1;
+               off_nl = -1;            /* variable, min 16, max 71 steps of 7 */
+               off_nl_nosnap = -1;     /* no 802.2 LLC */
+               off_mac = 1;            /* step over the kiss length byte */
+               return;
+
+       case DLT_IEEE802_15_4_NONASK_PHY:
+               /*
+                * Currently, only raw "link[N:M]" filtering is supported.
+                */
+               off_linktype = -1;
+               off_macpl = -1;
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
@@ -1362,6 +1547,45 @@ gen_load_llrel(offset, size)
        return s;
 }
 
+/*
+ * Load a value relative to the beginning of the MAC-layer payload.
+ */
+static struct slist *
+gen_load_macplrel(offset, size)
+       u_int offset, size;
+{
+       struct slist *s, *s2;
+
+       s = gen_off_macpl();
+
+       /*
+        * If s is non-null, the offset of the MAC-layer payload is
+        * variable, and s points to a list of instructions that
+        * arrange that the X register contains that offset.
+        *
+        * Otherwise, the offset of the MAC-layer payload is constant,
+        * and is in off_macpl.
+        */
+       if (s != NULL) {
+               /*
+                * The offset of the MAC-layer payload is in the X
+                * register.  Do an indirect load, to use the X register
+                * as an offset.
+                */
+               s2 = new_stmt(BPF_LD|BPF_IND|size);
+               s2->s.k = offset;
+               sappend(s, s2);
+       } else {
+               /*
+                * The offset of the MAC-layer payload is constant,
+                * and is in off_macpl; load the value at that offset
+                * plus the specified offset.
+                */
+               s = new_stmt(BPF_LD|BPF_ABS|size);
+               s->s.k = off_macpl + offset;
+       }
+       return s;
+}
 
 /*
  * Load a value relative to the beginning of the specified header.
@@ -1384,12 +1608,16 @@ gen_load_a(offrel, offset, size)
                s = gen_load_llrel(offset, size);
                break;
 
+       case OR_MACPL:
+               s = gen_load_macplrel(offset, size);
+               break;
+
        case OR_NET:
-               s = gen_load_llrel(off_nl + offset, size);
+               s = gen_load_macplrel(off_nl + offset, size);
                break;
 
        case OR_NET_NOSNAP:
-               s = gen_load_llrel(off_nl_nosnap + offset, size);
+               s = gen_load_macplrel(off_nl_nosnap + offset, size);
                break;
 
        case OR_TRAN_IPV4:
@@ -1402,21 +1630,22 @@ gen_load_a(offrel, offset, size)
                s = gen_loadx_iphdrlen();
 
                /*
-                * Load the item at {offset of the link-layer header} +
-                * {offset, relative to the start of the link-layer
-                * header, of the IPv4 header} + {length of the IPv4 header} +
+                * Load the item at {offset of the MAC-layer payload} +
+                * {offset, relative to the start of the MAC-layer
+                * paylod, of the IPv4 header} + {length of the IPv4 header} +
                 * {specified offset}.
                 *
-                * (If the link-layer is variable-length, it's included
-                * in the value in the X register, and off_ll is 0.)
+                * (If the offset of the MAC-layer payload is variable,
+                * it's included in the value in the X register, and
+                * off_macpl is 0.)
                 */
                s2 = new_stmt(BPF_LD|BPF_IND|size);
-               s2->s.k = off_ll + off_nl + offset;
+               s2->s.k = off_macpl + off_nl + offset;
                sappend(s, s2);
                break;
 
        case OR_TRAN_IPV6:
-               s = gen_load_llrel(off_nl + 40 + offset, size);
+               s = gen_load_macplrel(off_nl + 40 + offset, size);
                break;
 
        default:
@@ -1436,12 +1665,15 @@ gen_loadx_iphdrlen()
 {
        struct slist *s, *s2;
 
-       s = gen_llprefixlen();
+       s = gen_off_macpl();
        if (s != NULL) {
                /*
                 * There's a variable-length prefix preceding the
-                * link-layer header.  "s" points to a list of statements
-                * that put the length of that prefix into the X register.
+                * link-layer header, or the link-layer header is itself
+                * variable-length.  "s" points to a list of statements
+                * that put the offset of the MAC-layer payload into
+                * the X register.
+                *
                 * The 4*([k]&0xf) addressing mode can't be used, as we
                 * don't have a constant offset, so we have to load the
                 * value in question into the A register and add to it
@@ -1459,22 +1691,24 @@ gen_loadx_iphdrlen()
 
                /*
                 * The A register now contains the length of the
-                * IP header.  We need to add to it the length
-                * of the prefix preceding the link-layer
-                * header, which is still in the X register, and
-                * move the result into the X register.
+                * IP header.  We need to add to it the offset of
+                * the MAC-layer payload, which is still in the X
+                * register, and move the result into the X register.
                 */
                sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
                sappend(s, new_stmt(BPF_MISC|BPF_TAX));
        } else {
                /*
                 * There is no variable-length header preceding the
-                * link-layer header; add in off_ll, which, if there's
-                * a fixed-length header preceding the link-layer header,
-                * is the length of that header.
+                * link-layer header, and the link-layer header is
+                * fixed-length; load the length of the IPv4 header,
+                * which is at an offset of off_nl from the beginning
+                * of the MAC-layer payload, and thus at an offset
+                * of off_mac_pl + off_nl from the beginning of the
+                * raw packet data.
                 */
                s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
-               s->s.k = off_ll + off_nl;
+               s->s.k = off_macpl + off_nl;
        }
        return s;
 }
@@ -1548,7 +1782,7 @@ gen_ether_linktype(proto)
                 */
                b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
                gen_not(b0);
-               b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32)
+               b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)
                             ((proto << 8) | proto));
                gen_and(b0, b1);
                return b1;
@@ -1586,17 +1820,15 @@ gen_ether_linktype(proto)
                 * This generates code to check both for the
                 * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
                 */
-               b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
-                   (bpf_int32)LLCSAP_IPX);
-               b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H,
-                   (bpf_int32)0xFFFF);
+               b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
+               b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)0xFFFF);
                gen_or(b0, b1);
 
                /*
                 * Now we add code to check for SNAP frames with
                 * ETHERTYPE_IPX, i.e. Ethernet_SNAP.
                 */
-               b0 = gen_snap(0x000000, ETHERTYPE_IPX, 14);
+               b0 = gen_snap(0x000000, ETHERTYPE_IPX);
                gen_or(b0, b1);
 
                /*
@@ -1651,9 +1883,9 @@ gen_ether_linktype(proto)
                 * type of ETHERTYPE_AARP (Appletalk ARP).
                 */
                if (proto == ETHERTYPE_ATALK)
-                       b1 = gen_snap(0x080007, ETHERTYPE_ATALK, 14);
+                       b1 = gen_snap(0x080007, ETHERTYPE_ATALK);
                else    /* proto == ETHERTYPE_AARP */
-                       b1 = gen_snap(0x000000, ETHERTYPE_AARP, 14);
+                       b1 = gen_snap(0x000000, ETHERTYPE_AARP);
                gen_and(b0, b1);
 
                /*
@@ -1730,7 +1962,7 @@ gen_linux_sll_linktype(proto)
                 * (i.e., other SAP values)?
                 */
                b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);
-               b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32)
+               b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)
                             ((proto << 8) | proto));
                gen_and(b0, b1);
                return b1;
@@ -1761,10 +1993,8 @@ gen_linux_sll_linktype(proto)
                 * then put a check for LINUX_SLL_P_802_2 frames
                 * before it.
                 */
-               b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
-                   (bpf_int32)LLCSAP_IPX);
-               b1 = gen_snap(0x000000, ETHERTYPE_IPX,
-                   off_linktype + 2);
+               b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
+               b1 = gen_snap(0x000000, ETHERTYPE_IPX);
                gen_or(b0, b1);
                b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);
                gen_and(b0, b1);
@@ -1812,11 +2042,9 @@ gen_linux_sll_linktype(proto)
                 * type of ETHERTYPE_AARP (Appletalk ARP).
                 */
                if (proto == ETHERTYPE_ATALK)
-                       b1 = gen_snap(0x080007, ETHERTYPE_ATALK,
-                           off_linktype + 2);
+                       b1 = gen_snap(0x080007, ETHERTYPE_ATALK);
                else    /* proto == ETHERTYPE_AARP */
-                       b1 = gen_snap(0x000000, ETHERTYPE_AARP,
-                           off_linktype + 2);
+                       b1 = gen_snap(0x000000, ETHERTYPE_AARP);
                gen_and(b0, b1);
 
                /*
@@ -1840,7 +2068,7 @@ gen_linux_sll_linktype(proto)
                         */
                        b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
                            LINUX_SLL_P_802_2);
-                       b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
+                       b1 = gen_cmp(OR_LINK, off_macpl, BPF_B,
                             (bpf_int32)proto);
                        gen_and(b0, b1);
                        return b1;
@@ -1860,18 +2088,169 @@ gen_linux_sll_linktype(proto)
        }
 }
 
-static void
-insert_radiotap_load_llprefixlen(b)
-       struct block *b;
+static struct slist *
+gen_load_prism_llprefixlen()
 {
        struct slist *s1, *s2;
+       struct slist *sjeq_avs_cookie;
+       struct slist *sjcommon;
+
+       /*
+        * This code is not compatible with the optimizer, as
+        * we are generating jmp instructions within a normal
+        * slist of instructions
+        */
+       no_optimize = 1;
 
        /*
-        * Prepend to the statements in this block code to load the
-        * length of the radiotap header into the register assigned
-        * to hold that length, if one has been assigned.
+        * Generate code to load the length of the radio header into
+        * the register assigned to hold that length, if one has been
+        * assigned.  (If one hasn't been assigned, no code we've
+        * generated uses that prefix, so we don't need to generate any
+        * code to load it.)
+        *
+        * Some Linux drivers use ARPHRD_IEEE80211_PRISM but sometimes
+        * or always use the AVS header rather than the Prism header.
+        * We load a 4-byte big-endian value at the beginning of the
+        * raw packet data, and see whether, when masked with 0xFFFFF000,
+        * it's equal to 0x80211000.  If so, that indicates that it's
+        * an AVS header (the masked-out bits are the version number).
+        * Otherwise, it's a Prism header.
+        *
+        * XXX - the Prism header is also, in theory, variable-length,
+        * but no known software generates headers that aren't 144
+        * bytes long.
         */
-       if (reg_ll_size != -1) {
+       if (reg_off_ll != -1) {
+               /*
+                * Load the cookie.
+                */
+               s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+               s1->s.k = 0;
+
+               /*
+                * AND it with 0xFFFFF000.
+                */
+               s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+               s2->s.k = 0xFFFFF000;
+               sappend(s1, s2);
+
+               /*
+                * Compare with 0x80211000.
+                */
+               sjeq_avs_cookie = new_stmt(JMP(BPF_JEQ));
+               sjeq_avs_cookie->s.k = 0x80211000;
+               sappend(s1, sjeq_avs_cookie);
+
+               /*
+                * If it's AVS:
+                *
+                * The 4 bytes at an offset of 4 from the beginning of
+                * the AVS header are the length of the AVS header.
+                * That field is big-endian.
+                */
+               s2 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+               s2->s.k = 4;
+               sappend(s1, s2);
+               sjeq_avs_cookie->s.jt = s2;
+
+               /*
+                * Now jump to the code to allocate a register
+                * into which to save the header length and
+                * store the length there.  (The "jump always"
+                * instruction needs to have the k field set;
+                * it's added to the PC, so, as we're jumping
+                * over a single instruction, it should be 1.)
+                */
+               sjcommon = new_stmt(JMP(BPF_JA));
+               sjcommon->s.k = 1;
+               sappend(s1, sjcommon);
+
+               /*
+                * Now for the code that handles the Prism header.
+                * Just load the length of the Prism header (144)
+                * into the A register.  Have the test for an AVS
+                * header branch here if we don't have an AVS header.
+                */
+               s2 = new_stmt(BPF_LD|BPF_W|BPF_IMM);
+               s2->s.k = 144;
+               sappend(s1, s2);
+               sjeq_avs_cookie->s.jf = s2;
+
+               /*
+                * Now allocate a register to hold that value and store
+                * it.  The code for the AVS header will jump here after
+                * loading the length of the AVS header.
+                */
+               s2 = new_stmt(BPF_ST);
+               s2->s.k = reg_off_ll;
+               sappend(s1, s2);
+               sjcommon->s.jf = s2;
+
+               /*
+                * Now move it into the X register.
+                */
+               s2 = new_stmt(BPF_MISC|BPF_TAX);
+               sappend(s1, s2);
+
+               return (s1);
+       } else
+               return (NULL);
+}
+
+static struct slist *
+gen_load_avs_llprefixlen()
+{
+       struct slist *s1, *s2;
+
+       /*
+        * Generate code to load the length of the AVS header into
+        * the register assigned to hold that length, if one has been
+        * assigned.  (If one hasn't been assigned, no code we've
+        * generated uses that prefix, so we don't need to generate any
+        * code to load it.)
+        */
+       if (reg_off_ll != -1) {
+               /*
+                * The 4 bytes at an offset of 4 from the beginning of
+                * the AVS header are the length of the AVS header.
+                * That field is big-endian.
+                */
+               s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+               s1->s.k = 4;
+
+               /*
+                * Now allocate a register to hold that value and store
+                * it.
+                */
+               s2 = new_stmt(BPF_ST);
+               s2->s.k = reg_off_ll;
+               sappend(s1, s2);
+
+               /*
+                * Now move it into the X register.
+                */
+               s2 = new_stmt(BPF_MISC|BPF_TAX);
+               sappend(s1, s2);
+
+               return (s1);
+       } else
+               return (NULL);
+}
+
+static struct slist *
+gen_load_radiotap_llprefixlen()
+{
+       struct slist *s1, *s2;
+
+       /*
+        * Generate code to load the length of the radiotap header into
+        * the register assigned to hold that length, if one has been
+        * assigned.  (If one hasn't been assigned, no code we've
+        * generated uses that prefix, so we don't need to generate any
+        * code to load it.)
+        */
+       if (reg_off_ll != -1) {
                /*
                 * The 2 bytes at offsets of 2 and 3 from the beginning
                 * of the radiotap header are the length of the radiotap
@@ -1906,7 +2285,7 @@ insert_radiotap_load_llprefixlen(b)
                 * it.
                 */
                s2 = new_stmt(BPF_ST);
-               s2->s.k = reg_ll_size;
+               s2->s.k = reg_off_ll;
                sappend(s1, s2);
 
                /*
@@ -1915,13 +2294,9 @@ insert_radiotap_load_llprefixlen(b)
                s2 = new_stmt(BPF_MISC|BPF_TAX);
                sappend(s1, s2);
 
-               /*
-                * Now append all the existing statements in this
-                * block to these statements.
-                */
-               sappend(s1, b->stmts);
-               b->stmts = s1;
-       }
+               return (s1);
+       } else
+               return (NULL);
 }
 
 /* 
@@ -1930,21 +2305,21 @@ insert_radiotap_load_llprefixlen(b)
  * the code at the beginning to compute the header length.
  * Since this code generator of PPI supports bare 802.11
  * encapsulation only (i.e. the encapsulated DLT should be
- * DLT_IEEE802_11) we generate code to check for this too.
+ * DLT_IEEE802_11) we generate code to check for this too;
+ * that's done in finish_parse().
  */
-static void
-insert_ppi_load_llprefixlen(b)
-       struct block *b;
+static struct slist *
+gen_load_ppi_llprefixlen()
 {
        struct slist *s1, *s2;
        
        /*
-        * Prepend to the statements in this block code to load the
-        * length of the radiotap header into the register assigned
-        * to hold that length, if one has been assigned.
+        * Generate code to load the length of the radiotap header
+        * into the register assigned to hold that length, if one has
+        * been assigned.
         */
-       if (reg_ll_size != -1) {
-           /*
+       if (reg_off_ll != -1) {
+               /*
                 * The 2 bytes at offsets of 2 and 3 from the beginning
                 * of the radiotap header are the length of the radiotap
                 * header; unfortunately, it's little-endian, so we have
@@ -1978,7 +2353,7 @@ insert_ppi_load_llprefixlen(b)
                 * it.
                 */
                s2 = new_stmt(BPF_ST);
-               s2->s.k = reg_ll_size;
+               s2->s.k = reg_off_ll;
                sappend(s1, s2);
 
                /*
@@ -1987,16 +2362,295 @@ insert_ppi_load_llprefixlen(b)
                s2 = new_stmt(BPF_MISC|BPF_TAX);
                sappend(s1, s2);
 
+               return (s1);
+       } else
+               return (NULL);
+}
+
+/*
+ * Load a value relative to the beginning of the link-layer header after the 802.11
+ * header, i.e. LLC_SNAP.
+ * The link-layer header doesn't necessarily begin at the beginning
+ * of the packet data; there might be a variable-length prefix containing
+ * radio information.
+ */
+static struct slist *
+gen_load_802_11_header_len(struct slist *s, struct slist *snext)
+{
+       struct slist *s2;
+       struct slist *sjset_data_frame_1;
+       struct slist *sjset_data_frame_2;
+       struct slist *sjset_qos;
+       struct slist *sjset_radiotap_flags;
+       struct slist *sjset_radiotap_tsft;
+       struct slist *sjset_tsft_datapad, *sjset_notsft_datapad;
+       struct slist *s_roundup;
+
+       if (reg_off_macpl == -1) {
+               /*
+                * No register has been assigned to the offset of
+                * the MAC-layer payload, which means nobody needs
+                * it; don't bother computing it - just return
+                * what we already have.
+                */
+               return (s);
+       }
+
+       /*
+        * This code is not compatible with the optimizer, as
+        * we are generating jmp instructions within a normal
+        * slist of instructions
+        */
+       no_optimize = 1;
+       
+       /*
+        * If "s" is non-null, it has code to arrange that the X register
+        * contains the length of the prefix preceding the link-layer
+        * header.
+        *
+        * Otherwise, the length of the prefix preceding the link-layer
+        * header is "off_ll".
+        */
+       if (s == NULL) {
+               /*
+                * There is no variable-length header preceding the
+                * link-layer header.
+                *
+                * Load the length of the fixed-length prefix preceding
+                * the link-layer header (if any) into the X register,
+                * and store it in the reg_off_macpl register.
+                * That length is off_ll.
+                */
+               s = new_stmt(BPF_LDX|BPF_IMM);
+               s->s.k = off_ll;
+       }
+
+       /*
+        * The X register contains the offset of the beginning of the
+        * link-layer header; add 24, which is the minimum length
+        * of the MAC header for a data frame, to that, and store it
+        * in reg_off_macpl, and then load the Frame Control field,
+        * which is at the offset in the X register, with an indexed load.
+        */
+       s2 = new_stmt(BPF_MISC|BPF_TXA);
+       sappend(s, s2);
+       s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
+       s2->s.k = 24;
+       sappend(s, s2);
+       s2 = new_stmt(BPF_ST);
+       s2->s.k = reg_off_macpl;
+       sappend(s, s2);
+
+       s2 = new_stmt(BPF_LD|BPF_IND|BPF_B);
+       s2->s.k = 0;
+       sappend(s, s2);
+
+       /*
+        * Check the Frame Control field to see if this is a data frame;
+        * a data frame has the 0x08 bit (b3) in that field set and the
+        * 0x04 bit (b2) clear.
+        */
+       sjset_data_frame_1 = new_stmt(JMP(BPF_JSET));
+       sjset_data_frame_1->s.k = 0x08;
+       sappend(s, sjset_data_frame_1);
+               
+       /*
+        * If b3 is set, test b2, otherwise go to the first statement of
+        * the rest of the program.
+        */
+       sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(JMP(BPF_JSET));
+       sjset_data_frame_2->s.k = 0x04;
+       sappend(s, sjset_data_frame_2);
+       sjset_data_frame_1->s.jf = snext;
+
+       /*
+        * If b2 is not set, this is a data frame; test the QoS bit.
+        * Otherwise, go to the first statement of the rest of the
+        * program.
+        */
+       sjset_data_frame_2->s.jt = snext;
+       sjset_data_frame_2->s.jf = sjset_qos = new_stmt(JMP(BPF_JSET));
+       sjset_qos->s.k = 0x80;  /* QoS bit */
+       sappend(s, sjset_qos);
+               
+       /*
+        * If it's set, add 2 to reg_off_macpl, to skip the QoS
+        * field.
+        * Otherwise, go to the first statement of the rest of the
+        * program.
+        */
+       sjset_qos->s.jt = s2 = new_stmt(BPF_LD|BPF_MEM);
+       s2->s.k = reg_off_macpl;
+       sappend(s, s2);
+       s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM);
+       s2->s.k = 2;
+       sappend(s, s2);
+       s2 = new_stmt(BPF_ST);
+       s2->s.k = reg_off_macpl;
+       sappend(s, s2);
+
+       /*
+        * If we have a radiotap header, look at it to see whether
+        * there's Atheros padding between the MAC-layer header
+        * and the payload.
+        *
+        * Note: all of the fields in the radiotap header are
+        * little-endian, so we byte-swap all of the values
+        * we test against, as they will be loaded as big-endian
+        * values.
+        */
+       if (linktype == DLT_IEEE802_11_RADIO) {
                /*
-                * Now append all the existing statements in this
-                * block to these statements.
+                * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set
+                * in the presence flag?
                 */
-               sappend(s1, b->stmts);
-               b->stmts = s1;
+               sjset_qos->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_W);
+               s2->s.k = 4;
+               sappend(s, s2);
+
+               sjset_radiotap_flags = new_stmt(JMP(BPF_JSET));
+               sjset_radiotap_flags->s.k = SWAPLONG(0x00000002);
+               sappend(s, sjset_radiotap_flags);
 
+               /*
+                * If not, skip all of this.
+                */
+               sjset_radiotap_flags->s.jf = snext;
+
+               /*
+                * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set?
+                */
+               sjset_radiotap_tsft = sjset_radiotap_flags->s.jt =
+                   new_stmt(JMP(BPF_JSET));
+               sjset_radiotap_tsft->s.k = SWAPLONG(0x00000001);
+               sappend(s, sjset_radiotap_tsft);
+
+               /*
+                * If IEEE80211_RADIOTAP_TSFT is set, the flags field is
+                * at an offset of 16 from the beginning of the raw packet
+                * data (8 bytes for the radiotap header and 8 bytes for
+                * the TSFT field).
+                *
+                * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+                * is set.
+                */
+               sjset_radiotap_tsft->s.jt = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B);
+               s2->s.k = 16;
+               sappend(s, s2);
+
+               sjset_tsft_datapad = new_stmt(JMP(BPF_JSET));
+               sjset_tsft_datapad->s.k = 0x20;
+               sappend(s, sjset_tsft_datapad);
+
+               /*
+                * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is
+                * at an offset of 8 from the beginning of the raw packet
+                * data (8 bytes for the radiotap header).
+                *
+                * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+                * is set.
+                */
+               sjset_radiotap_tsft->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B);
+               s2->s.k = 8;
+               sappend(s, s2);
+
+               sjset_notsft_datapad = new_stmt(JMP(BPF_JSET));
+               sjset_notsft_datapad->s.k = 0x20;
+               sappend(s, sjset_notsft_datapad);
+
+               /*
+                * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is
+                * set, round the length of the 802.11 header to
+                * a multiple of 4.  Do that by adding 3 and then
+                * dividing by and multiplying by 4, which we do by
+                * ANDing with ~3.
+                */
+               s_roundup = new_stmt(BPF_LD|BPF_MEM);
+               s_roundup->s.k = reg_off_macpl;
+               sappend(s, s_roundup);
+               s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM);
+               s2->s.k = 3;
+               sappend(s, s2);
+               s2 = new_stmt(BPF_ALU|BPF_AND|BPF_IMM);
+               s2->s.k = ~3;
+               sappend(s, s2);
+               s2 = new_stmt(BPF_ST);
+               s2->s.k = reg_off_macpl;
+               sappend(s, s2);
+
+               sjset_tsft_datapad->s.jt = s_roundup;
+               sjset_tsft_datapad->s.jf = snext;
+               sjset_notsft_datapad->s.jt = s_roundup;
+               sjset_notsft_datapad->s.jf = snext;
+       } else
+               sjset_qos->s.jf = snext;
+
+       return s;
+}
+
+static void
+insert_compute_vloffsets(b)
+       struct block *b;
+{
+       struct slist *s;
+
+       /*
+        * For link-layer types that have a variable-length header
+        * preceding the link-layer header, generate code to load
+        * the offset of the link-layer header into the register
+        * assigned to that offset, if any.
+        */
+       switch (linktype) {
+
+       case DLT_PRISM_HEADER:
+               s = gen_load_prism_llprefixlen();
+               break;
+
+       case DLT_IEEE802_11_RADIO_AVS:
+               s = gen_load_avs_llprefixlen();
+               break;
+
+       case DLT_IEEE802_11_RADIO:
+               s = gen_load_radiotap_llprefixlen();
+               break;
+
+       case DLT_PPI:
+               s = gen_load_ppi_llprefixlen();
+               break;
+
+       default:
+               s = NULL;
+               break;
+       }
+
+       /*
+        * For link-layer types that have a variable-length link-layer
+        * header, generate code to load the offset of the MAC-layer
+        * payload into the register assigned to that offset, if any.
+        */
+       switch (linktype) {
+
+       case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
+       case DLT_PPI:
+               s = gen_load_802_11_header_len(s, b->stmts);
+               break;
+       }
+
+       /*
+        * If we have any offset-loading code, append all the
+        * existing statements in the block to those statements,
+        * and make the resulting list the list of statements
+        * for the block.
+        */
+       if (s != NULL) {
+               sappend(s, b->stmts);
+               b->stmts = s;
        }
 }
-       
+
 static struct block *
 gen_ppi_dlt_check(void)
 {
@@ -2023,42 +2677,61 @@ gen_ppi_dlt_check(void)
        return b;
 }
 
-static void
-insert_load_llprefixlen(b)
-       struct block *b;
+static struct slist *
+gen_prism_llprefixlen(void)
 {
-       switch (linktype) {
+       struct slist *s;
+
+       if (reg_off_ll == -1) {
+               /*
+                * We haven't yet assigned a register for the length
+                * of the radio header; allocate one.
+                */
+               reg_off_ll = alloc_reg();
+       }
 
-       /* 
-        * At the moment we treat PPI as normal Radiotap encoded
-        * packets. The difference is in the function that generates
-        * the code at the beginning to compute the header length.
-        * Since this code generator of PPI supports bare 802.11
-        * encapsulation only (i.e. the encapsulated DLT should be
-        * DLT_IEEE802_11) we generate code to check for this too.
+       /*
+        * Load the register containing the radio length
+        * into the X register.
         */
-       case DLT_PPI:
-               insert_ppi_load_llprefixlen(b);
-               break;
+       s = new_stmt(BPF_LDX|BPF_MEM);
+       s->s.k = reg_off_ll;
+       return s;
+}
 
-       case DLT_IEEE802_11_RADIO:
-               insert_radiotap_load_llprefixlen(b);
-               break;
+static struct slist *
+gen_avs_llprefixlen(void)
+{
+       struct slist *s;
+
+       if (reg_off_ll == -1) {
+               /*
+                * We haven't yet assigned a register for the length
+                * of the AVS header; allocate one.
+                */
+               reg_off_ll = alloc_reg();
        }
-}
 
+       /*
+        * Load the register containing the AVS length
+        * into the X register.
+        */
+       s = new_stmt(BPF_LDX|BPF_MEM);
+       s->s.k = reg_off_ll;
+       return s;
+}
 
 static struct slist *
 gen_radiotap_llprefixlen(void)
 {
        struct slist *s;
 
-       if (reg_ll_size == -1) {
+       if (reg_off_ll == -1) {
                /*
                 * We haven't yet assigned a register for the length
                 * of the radiotap header; allocate one.
                 */
-               reg_ll_size = alloc_reg();
+               reg_off_ll = alloc_reg();
        }
 
        /*
@@ -2066,7 +2739,7 @@ gen_radiotap_llprefixlen(void)
         * into the X register.
         */
        s = new_stmt(BPF_LDX|BPF_MEM);
-       s->s.k = reg_ll_size;
+       s->s.k = reg_off_ll;
        return s;
 }
 
@@ -2083,25 +2756,23 @@ gen_ppi_llprefixlen(void)
 {
        struct slist *s;
 
-       if (reg_ll_size == -1) {
+       if (reg_off_ll == -1) {
                /*
                 * We haven't yet assigned a register for the length
                 * of the radiotap header; allocate one.
                 */
-               reg_ll_size = alloc_reg();
+               reg_off_ll = alloc_reg();
        }
 
        /*
-        * Load the register containing the radiotap length
+        * Load the register containing the PPI length
         * into the X register.
         */
        s = new_stmt(BPF_LDX|BPF_MEM);
-       s->s.k = reg_ll_size;
+       s->s.k = reg_off_ll;
        return s;
 }
 
-
-
 /*
  * Generate code to compute the link-layer header length, if necessary,
  * putting it into the X register, and to return either a pointer to a
@@ -2113,19 +2784,110 @@ gen_llprefixlen(void)
 {
        switch (linktype) {
 
-       case DLT_PPI:
-               return gen_ppi_llprefixlen();
+       case DLT_PRISM_HEADER:
+               return gen_prism_llprefixlen();
+
+       case DLT_IEEE802_11_RADIO_AVS:
+               return gen_avs_llprefixlen();
 
-       
        case DLT_IEEE802_11_RADIO:
                return gen_radiotap_llprefixlen();
 
+       case DLT_PPI:
+               return gen_ppi_llprefixlen();
+
        default:
                return NULL;
        }
 }
 
 /*
+ * Generate code to load the register containing the offset of the
+ * MAC-layer payload into the X register; if no register for that offset
+ * has been allocated, allocate it first.
+ */
+static struct slist *
+gen_off_macpl(void)
+{
+       struct slist *s;
+
+       if (off_macpl_is_variable) {
+               if (reg_off_macpl == -1) {
+                       /*
+                        * We haven't yet assigned a register for the offset
+                        * of the MAC-layer payload; allocate one.
+                        */
+                       reg_off_macpl = alloc_reg();
+               }
+
+               /*
+                * Load the register containing the offset of the MAC-layer
+                * payload into the X register.
+                */
+               s = new_stmt(BPF_LDX|BPF_MEM);
+               s->s.k = reg_off_macpl;
+               return s;
+       } else {
+               /*
+                * That offset isn't variable, so we don't need to
+                * generate any code.
+                */
+               return NULL;
+       }
+}
+
+/*
+ * Map an Ethernet type to the equivalent PPP type.
+ */
+static int
+ethertype_to_ppptype(proto)
+       int proto;
+{
+       switch (proto) {
+
+       case ETHERTYPE_IP:
+               proto = PPP_IP;
+               break;
+
+#ifdef INET6
+       case ETHERTYPE_IPV6:
+               proto = PPP_IPV6;
+               break;
+#endif
+
+       case ETHERTYPE_DN:
+               proto = PPP_DECNET;
+               break;
+
+       case ETHERTYPE_ATALK:
+               proto = PPP_APPLE;
+               break;
+
+       case ETHERTYPE_NS:
+               proto = PPP_NS;
+               break;
+
+       case LLCSAP_ISONS:
+               proto = PPP_OSI;
+               break;
+
+       case LLCSAP_8021D:
+               /*
+                * I'm assuming the "Bridging PDU"s that go
+                * over PPP are Spanning Tree Protocol
+                * Bridging PDUs.
+                */
+               proto = PPP_BRPDU;
+               break;
+
+       case LLCSAP_IPX:
+               proto = PPP_IPX;
+               break;
+       }
+       return (proto);
+}
+
+/*
  * Generate code to match a particular packet type by matching the
  * link-layer type field or fields in the 802.2 LLC header.
  *
@@ -2143,12 +2905,12 @@ gen_linktype(proto)
                switch (proto) {
                case ETHERTYPE_IP:
                case PPP_IP:
-               /* FIXME add other L3 proto IDs */
+                       /* FIXME add other L3 proto IDs */
                        return gen_mpls_linktype(Q_IP); 
 
                case ETHERTYPE_IPV6:
                case PPP_IPV6:
-               /* FIXME add other L3 proto IDs */
+                       /* FIXME add other L3 proto IDs */
                        return gen_mpls_linktype(Q_IPV6); 
 
                default:
@@ -2157,6 +2919,25 @@ gen_linktype(proto)
                }
        }
 
+       /*
+        * Are we testing PPPoE packets?
+        */
+       if (is_pppoes) {
+               /*
+                * The PPPoE session header is part of the
+                * MAC-layer payload, so all references
+                * should be relative to the beginning of
+                * that payload.
+                */
+
+               /*
+                * We use Ethernet protocol types inside libpcap;
+                * map them to the corresponding PPP protocol types.
+                */
+               proto = ethertype_to_ppptype(proto);
+               return gen_cmp(OR_MACPL, off_linktype, BPF_H, (bpf_int32)proto);
+       }
+
        switch (linktype) {
 
        case DLT_EN10MB:
@@ -2179,13 +2960,41 @@ gen_linktype(proto)
                }
                break;
 
-       case DLT_PPI:
-       case DLT_FDDI:
-       case DLT_IEEE802:
        case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
        case DLT_IEEE802_11_RADIO_AVS:
        case DLT_IEEE802_11_RADIO:
-       case DLT_PRISM_HEADER:
+       case DLT_PPI:
+               /*
+                * Check that we have a data frame.
+                */
+               b0 = gen_check_802_11_data_frame();
+
+               /*
+                * Now check for the specified link-layer type.
+                */
+               b1 = gen_llc_linktype(proto);
+               gen_and(b0, b1);
+               return b1;
+               /*NOTREACHED*/
+               break;
+
+       case DLT_FDDI:
+               /*
+                * XXX - check for asynchronous frames, as per RFC 1103.
+                */
+               return gen_llc_linktype(proto);
+               /*NOTREACHED*/
+               break;
+
+       case DLT_IEEE802:
+               /*
+                * XXX - check for LLC PDUs, as per IEEE 802.5.
+                */
+               return gen_llc_linktype(proto);
+               /*NOTREACHED*/
+               break;
+
        case DLT_ATM_RFC1483:
        case DLT_ATM_CLIP:
        case DLT_IP_OVER_FC:
@@ -2270,47 +3079,9 @@ gen_linktype(proto)
                 * We use Ethernet protocol types inside libpcap;
                 * map them to the corresponding PPP protocol types.
                 */
-               switch (proto) {
-
-               case ETHERTYPE_IP:
-                       proto = PPP_IP;
-                       break;
-
-#ifdef INET6
-               case ETHERTYPE_IPV6:
-                       proto = PPP_IPV6;
-                       break;
-#endif
-
-               case ETHERTYPE_DN:
-                       proto = PPP_DECNET;
-                       break;
-
-               case ETHERTYPE_ATALK:
-                       proto = PPP_APPLE;
-                       break;
-
-               case ETHERTYPE_NS:
-                       proto = PPP_NS;
-                       break;
-
-               case LLCSAP_ISONS:
-                       proto = PPP_OSI;
-                       break;
-
-               case LLCSAP_8021D:
-                       /*
-                        * I'm assuming the "Bridging PDU"s that go
-                        * over PPP are Spanning Tree Protocol
-                        * Bridging PDUs.
-                        */
-                       proto = PPP_BRPDU;
-                       break;
-
-               case LLCSAP_IPX:
-                       proto = PPP_IPX;
-                       break;
-               }
+               proto = ethertype_to_ppptype(proto);
+               return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
+               /*NOTREACHED*/
                break;
 
        case DLT_PPP_BSDOS:
@@ -2321,6 +3092,10 @@ gen_linktype(proto)
                switch (proto) {
 
                case ETHERTYPE_IP:
+                       /*
+                        * Also check for Van Jacobson-compressed IP.
+                        * XXX - do this for other forms of PPP?
+                        */
                        b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_IP);
                        b1 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_VJC);
                        gen_or(b0, b1);
@@ -2328,42 +3103,12 @@ gen_linktype(proto)
                        gen_or(b1, b0);
                        return b0;
 
-#ifdef INET6
-               case ETHERTYPE_IPV6:
-                       proto = PPP_IPV6;
-                       /* more to go? */
-                       break;
-#endif
-
-               case ETHERTYPE_DN:
-                       proto = PPP_DECNET;
-                       break;
-
-               case ETHERTYPE_ATALK:
-                       proto = PPP_APPLE;
-                       break;
-
-               case ETHERTYPE_NS:
-                       proto = PPP_NS;
-                       break;
-
-               case LLCSAP_ISONS:
-                       proto = PPP_OSI;
-                       break;
-
-               case LLCSAP_8021D:
-                       /*
-                        * I'm assuming the "Bridging PDU"s that go
-                        * over PPP are Spanning Tree Protocol
-                        * Bridging PDUs.
-                        */
-                       proto = PPP_BRPDU;
-                       break;
-
-               case LLCSAP_IPX:
-                       proto = PPP_IPX;
-                       break;
+               default:
+                       proto = ethertype_to_ppptype(proto);
+                       return gen_cmp(OR_LINK, off_linktype, BPF_H,
+                               (bpf_int32)proto);
                }
+               /*NOTREACHED*/
                break;
 
        case DLT_NULL:
@@ -2552,6 +3297,9 @@ gen_linktype(proto)
                /*NOTREACHED*/
                break;
 
+       case DLT_MFR:
+               bpf_error("Multi-link Frame Relay link-layer type filtering not implemented");
+
         case DLT_JUNIPER_MFR:
         case DLT_JUNIPER_MLFR:
         case DLT_JUNIPER_MLPPP:
@@ -2568,6 +3316,8 @@ gen_linktype(proto)
         case DLT_JUNIPER_FRELAY:
         case DLT_JUNIPER_CHDLC:
         case DLT_JUNIPER_VP:
+        case DLT_JUNIPER_ST:
+        case DLT_JUNIPER_ISM:
                /* 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
@@ -2583,8 +3333,51 @@ gen_linktype(proto)
        case DLT_DOCSIS:
                bpf_error("DOCSIS link-layer type filtering not implemented");
 
+       case DLT_MTP2:
+       case DLT_MTP2_WITH_PHDR:
+               bpf_error("MTP2 link-layer type filtering not implemented");
+
+       case DLT_ERF:
+               bpf_error("ERF link-layer type filtering not implemented");
+
+#ifdef DLT_PFSYNC
+       case DLT_PFSYNC:
+               bpf_error("PFSYNC link-layer type filtering not implemented");
+#endif
+
        case DLT_LINUX_LAPD:
                bpf_error("LAPD link-layer type filtering not implemented");
+
+       case DLT_USB:
+       case DLT_USB_LINUX:
+               bpf_error("USB link-layer type filtering not implemented");
+
+       case DLT_BLUETOOTH_HCI_H4:
+       case DLT_BLUETOOTH_HCI_H4_WITH_PHDR:
+               bpf_error("Bluetooth link-layer type filtering not implemented");
+
+       case DLT_CAN20B:
+               bpf_error("CAN20B link-layer type filtering not implemented");
+
+       case DLT_IEEE802_15_4:
+       case DLT_IEEE802_15_4_LINUX:
+       case DLT_IEEE802_15_4_NONASK_PHY:
+               bpf_error("IEEE 802.15.4 link-layer type filtering not implemented");
+
+       case DLT_IEEE802_16_MAC_CPS_RADIO:
+               bpf_error("IEEE 802.16 link-layer type filtering not implemented");
+
+       case DLT_SITA:
+               bpf_error("SITA link-layer type filtering not implemented");
+
+       case DLT_RAIF1:
+               bpf_error("RAIF1 link-layer type filtering not implemented");
+
+       case DLT_IPMB:
+               bpf_error("IPMB link-layer type filtering not implemented");
+
+       case DLT_AX25_KISS:
+               bpf_error("AX.25 link-layer type filtering not implemented");
        }
 
        /*
@@ -2602,12 +3395,7 @@ gen_linktype(proto)
 
        /*
         * Any type not handled above should always have an Ethernet
-        * type at an offset of "off_linktype".  (PPP is partially
-        * handled above - the protocol type is mapped from the
-        * Ethernet and LLC types we use internally to the corresponding
-        * PPP type - but the PPP type is always specified by a value
-        * at "off_linktype", so we don't have to do the code generation
-        * above.)
+        * type at an offset of "off_linktype".
         */
        return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
 }
@@ -2620,10 +3408,9 @@ gen_linktype(proto)
  * code and protocol type in the SNAP header.
  */
 static struct block *
-gen_snap(orgcode, ptype, offset)
+gen_snap(orgcode, ptype)
        bpf_u_int32 orgcode;
        bpf_u_int32 ptype;
-       u_int offset;
 {
        u_char snapblock[8];
 
@@ -2635,7 +3422,7 @@ gen_snap(orgcode, ptype, offset)
        snapblock[5] = (orgcode >> 0);  /* lower 8 bits of organization code */
        snapblock[6] = (ptype >> 8);    /* upper 8 bits of protocol type */
        snapblock[7] = (ptype >> 0);    /* lower 8 bits of protocol type */
-       return gen_bcmp(OR_LINK, offset, 8, snapblock);
+       return gen_bcmp(OR_MACPL, 0, 8, snapblock);
 }
 
 /*
@@ -2668,7 +3455,7 @@ gen_llc_linktype(proto)
                 * DSAP, as we do for other types <= ETHERMTU
                 * (i.e., other SAP values)?
                 */
-               return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_u_int32)
+               return gen_cmp(OR_MACPL, 0, BPF_H, (bpf_u_int32)
                             ((proto << 8) | proto));
 
        case LLCSAP_IPX:
@@ -2676,7 +3463,7 @@ gen_llc_linktype(proto)
                 * XXX - are there ever SNAP frames for IPX on
                 * non-Ethernet 802.x networks?
                 */
-               return gen_cmp(OR_LINK, off_linktype, BPF_B,
+               return gen_cmp(OR_MACPL, 0, BPF_B,
                    (bpf_int32)LLCSAP_IPX);
 
        case ETHERTYPE_ATALK:
@@ -2689,7 +3476,7 @@ gen_llc_linktype(proto)
                 * XXX - check for an organization code of
                 * encapsulated Ethernet as well?
                 */
-               return gen_snap(0x080007, ETHERTYPE_ATALK, off_linktype);
+               return gen_snap(0x080007, ETHERTYPE_ATALK);
 
        default:
                /*
@@ -2701,8 +3488,7 @@ gen_llc_linktype(proto)
                         * This is an LLC SAP value, so check
                         * the DSAP.
                         */
-                       return gen_cmp(OR_LINK, off_linktype, BPF_B,
-                           (bpf_int32)proto);
+                       return gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)proto);
                } else {
                        /*
                         * This is an Ethernet type; we assume that it's
@@ -2717,15 +3503,13 @@ gen_llc_linktype(proto)
                         * organization code of 0x000000 (encapsulated
                         * Ethernet), we'd do
                         *
-                        *      return gen_snap(0x000000, proto,
-                        *          off_linktype);
+                        *      return gen_snap(0x000000, proto);
                         *
                         * here; for now, we don't, as per the above.
                         * I don't know whether it's worth the extra CPU
                         * time to do the right check or not.
                         */
-                       return gen_cmp(OR_LINK, off_linktype+6, BPF_H,
-                           (bpf_int32)proto);
+                       return gen_cmp(OR_MACPL, 6, BPF_H, (bpf_int32)proto);
                }
        }
 }
@@ -2934,7 +3718,8 @@ gen_thostop(eaddr, dir)
 }
 
 /*
- * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN)
+ * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and
+ * various 802.11 + radio headers.
  */
 static struct block *
 gen_wlanhostop(eaddr, dir)
@@ -2944,6 +3729,16 @@ gen_wlanhostop(eaddr, dir)
        register struct block *b0, *b1, *b2;
        register struct slist *s;
 
+#ifdef ENABLE_WLAN_FILTERING_PATCH
+       /*
+        * TODO GV 20070613
+        * We need to disable the optimizer because the optimizer is buggy
+        * and wipes out some LD instructions generated by the below
+        * code to validate the Frame Control bits
+        */
+       no_optimize = 1;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
+
        switch (dir) {
        case Q_SRC:
                /*
@@ -3041,7 +3836,7 @@ gen_wlanhostop(eaddr, dir)
                 * Now check for a data frame.
                 * I.e, check "link[0] & 0x08".
                 */
-               gen_load_a(OR_LINK, 0, BPF_B);
+               s = gen_load_a(OR_LINK, 0, BPF_B);
                b1 = new_block(JMP(BPF_JSET));
                b1->s.k = 0x08;
                b1->stmts = s;
@@ -3210,6 +4005,55 @@ gen_wlanhostop(eaddr, dir)
                gen_and(b1, b0);
                return b0;
 
+       /*
+        * XXX - add RA, TA, and BSSID keywords?
+        */
+       case Q_ADDR1:
+               return (gen_bcmp(OR_LINK, 4, 6, eaddr));
+
+       case Q_ADDR2:
+               /*
+                * Not present in CTS or ACK control frames.
+                */
+               b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+                       IEEE80211_FC0_TYPE_MASK);
+               gen_not(b0);
+               b1 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+                       IEEE80211_FC0_SUBTYPE_MASK);
+               gen_not(b1);
+               b2 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+                       IEEE80211_FC0_SUBTYPE_MASK);
+               gen_not(b2);
+               gen_and(b1, b2);
+               gen_or(b0, b2);
+               b1 = gen_bcmp(OR_LINK, 10, 6, eaddr);
+               gen_and(b2, b1);
+               return b1;
+
+       case Q_ADDR3:
+               /*
+                * Not present in control frames.
+                */
+               b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+                       IEEE80211_FC0_TYPE_MASK);
+               gen_not(b0);
+               b1 = gen_bcmp(OR_LINK, 16, 6, eaddr);
+               gen_and(b0, b1);
+               return b1;
+
+       case Q_ADDR4:
+               /*
+                * Present only if the direction mask has both "From DS"
+                * and "To DS" set.  Neither control frames nor management
+                * frames should have both of those set, so we don't
+                * check the frame type.
+                */
+               b0 = gen_mcmp(OR_LINK, 1, BPF_B,
+                       IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK);
+               b1 = gen_bcmp(OR_LINK, 24, 6, eaddr);
+               gen_and(b0, b1);
+               return b1;
+
        case Q_AND:
                b0 = gen_wlanhostop(eaddr, Q_SRC);
                b1 = gen_wlanhostop(eaddr, Q_DST);
@@ -3652,48 +4496,48 @@ gen_gateway(eaddr, alist, proto, dir)
        case Q_IP:
        case Q_ARP:
        case Q_RARP:
-                switch (linktype) {
-                case DLT_EN10MB:
-                    b0 = gen_ehostop(eaddr, Q_OR);
-                    break;
-                case DLT_FDDI:
-                    b0 = gen_fhostop(eaddr, Q_OR);
-                    break;
+               switch (linktype) {
+               case DLT_EN10MB:
+                       b0 = gen_ehostop(eaddr, Q_OR);
+                       break;
+               case DLT_FDDI:
+                       b0 = gen_fhostop(eaddr, Q_OR);
+                       break;
                case DLT_IEEE802:
-                    b0 = gen_thostop(eaddr, Q_OR);
-                    break;
+                       b0 = gen_thostop(eaddr, Q_OR);
+                       break;
                case DLT_IEEE802_11:
+               case DLT_PRISM_HEADER:
                case DLT_IEEE802_11_RADIO_AVS:
-               case DLT_PPI:
                case DLT_IEEE802_11_RADIO:
-               case DLT_PRISM_HEADER:
-                    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);
+               case DLT_PPI:
+                       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);
 
-                       /*
-                        * Now check the MAC address.
-                        */
-                       b0 = gen_ehostop(eaddr, Q_OR);
-                       gen_and(b1, b0);
-                    }
-                    break;
+                               /*
+                                * 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(
+                       b0 = gen_ipfchostop(eaddr, Q_OR);
+                       break;
+               default:
+                       bpf_error(
                            "'gateway' supported only on ethernet/FDDI/token ring/802.11/Fibre Channel");
-                }
+               }
                b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR, Q_HOST);
                while (*alist) {
                        tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR,
@@ -4458,7 +5302,8 @@ gen_protochain(v, proto, dir)
        }
 
        /*
-        * We don't handle variable-length radiotap here headers yet.
+        * We don't handle variable-length prefixes before the link-layer
+        * header, or variable-length link-layer headers, here yet.
         * We might want to add BPF instructions to do the protochain
         * work, to simplify that and, on platforms that have a BPF
         * interpreter with the new instructions, let the filtering
@@ -4467,11 +5312,15 @@ gen_protochain(v, proto, dir)
         * branches, and backward branch support is unlikely to appear
         * in kernel BPF engines.)
         */
-       if (linktype == DLT_IEEE802_11_RADIO)
-               bpf_error("'protochain' not supported with radiotap headers");
+       switch (linktype) {
 
-       if (linktype == DLT_PPI)
-               bpf_error("'protochain' not supported with PPI headers");
+       case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
+       case DLT_PPI:
+               bpf_error("'protochain' not supported with 802.11");
+       }
 
        no_optimize = 1; /*this code is not compatible with optimzer yet */
 
@@ -4490,11 +5339,11 @@ gen_protochain(v, proto, dir)
 
                /* A = ip->ip_p */
                s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
-               s[i]->s.k = off_ll + off_nl + 9;
+               s[i]->s.k = off_macpl + off_nl + 9;
                i++;
                /* X = ip->ip_hl << 2 */
                s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
-               s[i]->s.k = off_ll + off_nl;
+               s[i]->s.k = off_macpl + off_nl;
                i++;
                break;
 #ifdef INET6
@@ -4503,7 +5352,7 @@ gen_protochain(v, proto, dir)
 
                /* A = ip6->ip_nxt */
                s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
-               s[i]->s.k = off_ll + off_nl + 6;
+               s[i]->s.k = off_macpl + off_nl + 6;
                i++;
                /* X = sizeof(struct ip6_hdr) */
                s[i] = new_stmt(BPF_LDX|BPF_IMM);
@@ -4583,7 +5432,7 @@ gen_protochain(v, proto, dir)
                i++;
                /* A = P[X + packet head] */
                s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
-               s[i]->s.k = off_ll + off_nl;
+               s[i]->s.k = off_macpl + off_nl;
                i++;
                /* MEM[reg2] = A */
                s[i] = new_stmt(BPF_ST);
@@ -4601,7 +5450,7 @@ gen_protochain(v, proto, dir)
                i++;
                /* A = P[X + packet head]; */
                s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
-               s[i]->s.k = off_ll + off_nl;
+               s[i]->s.k = off_macpl + off_nl;
                i++;
                /* A += 1 */
                s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
@@ -4660,7 +5509,7 @@ gen_protochain(v, proto, dir)
        i++;
        /* A = P[X + packet head]; */
        s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
-       s[i]->s.k = off_ll + off_nl;
+       s[i]->s.k = off_macpl + off_nl;
        i++;
        /* MEM[reg2] = A */
        s[i] = new_stmt(BPF_ST);
@@ -4678,7 +5527,7 @@ gen_protochain(v, proto, dir)
        i++;
        /* A = P[X + packet head] */
        s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
-       s[i]->s.k = off_ll + off_nl;
+       s[i]->s.k = off_macpl + off_nl;
        i++;
        /* A += 2 */
        s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
@@ -4732,6 +5581,31 @@ gen_protochain(v, proto, dir)
 #endif
 }
 
+static struct block *
+gen_check_802_11_data_frame()
+{
+       struct slist *s;
+       struct block *b0, *b1;
+
+       /*
+        * A data frame has the 0x08 bit (b3) in the frame control field set
+        * and the 0x04 bit (b2) clear.
+        */
+       s = gen_load_a(OR_LINK, 0, BPF_B);
+       b0 = new_block(JMP(BPF_JSET));
+       b0->s.k = 0x08;
+       b0->stmts = s;
+       
+       s = gen_load_a(OR_LINK, 0, BPF_B);
+       b1 = new_block(JMP(BPF_JSET));
+       b1->s.k = 0x04;
+       b1->stmts = s;
+       gen_not(b1);
+
+       gen_and(b1, b0);
+
+       return b0;
+}
 
 /*
  * Generate code that checks whether the packet is a packet for protocol
@@ -5019,9 +5893,9 @@ gen_scode(name, q)
                                return b;
 
                        case DLT_IEEE802_11:
+                       case DLT_PRISM_HEADER:
                        case DLT_IEEE802_11_RADIO_AVS:
                        case DLT_IEEE802_11_RADIO:
-                       case DLT_PRISM_HEADER:
                        case DLT_PPI:
                                eaddr = pcap_ether_hostton(name);
                                if (eaddr == NULL)
@@ -5250,7 +6124,6 @@ gen_scode(name, q)
                else
                        bpf_error("unknown protocol: %s", name);
 
-
        case Q_UNDEF:
                syntax();
                /* NOTREACHED */
@@ -5487,44 +6360,44 @@ gen_ecode(eaddr, q)
        struct block *b, *tmp;
 
        if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
-            switch (linktype) {
-            case DLT_EN10MB:
-                return gen_ehostop(eaddr, (int)q.dir);
-            case DLT_FDDI:
-                return gen_fhostop(eaddr, (int)q.dir);
-            case DLT_IEEE802:
-                return gen_thostop(eaddr, (int)q.dir);
-                       case DLT_IEEE802_11:
-                       case DLT_IEEE802_11_RADIO_AVS:
-                       case DLT_IEEE802_11_RADIO:
-                       case DLT_PRISM_HEADER:
-                       case DLT_PPI:
-                               return gen_wlanhostop(eaddr, (int)q.dir);
-                       case DLT_SUNATM:
-                               if (is_lane) {
-                                       /*
-                                        * Check that the packet doesn't begin with an
-                                        * LE Control marker.  (We've already generated
-                                        * a test for LANE.)
-                                        */
-                                       tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
-                                               0xFF00);
-                                       gen_not(tmp);
-
-                                       /*
-                                        * Now check the MAC address.
-                                        */
-                                       b = gen_ehostop(eaddr, (int)q.dir);
-                                       gen_and(tmp, b);
-                                       return b;
-                               }
-                               break;
-                       case DLT_IP_OVER_FC:
-                return gen_ipfchostop(eaddr, (int)q.dir);
-            default:
-                               bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
-                break;
-            }
+               switch (linktype) {
+               case DLT_EN10MB:
+                       return gen_ehostop(eaddr, (int)q.dir);
+               case DLT_FDDI:
+                       return gen_fhostop(eaddr, (int)q.dir);
+               case DLT_IEEE802:
+                       return gen_thostop(eaddr, (int)q.dir);
+               case DLT_IEEE802_11:
+               case DLT_PRISM_HEADER:
+               case DLT_IEEE802_11_RADIO_AVS:
+               case DLT_IEEE802_11_RADIO:
+               case DLT_PPI:
+                       return gen_wlanhostop(eaddr, (int)q.dir);
+               case DLT_SUNATM:
+                       if (is_lane) {
+                               /*
+                                * Check that the packet doesn't begin with an
+                                * LE Control marker.  (We've already generated
+                                * a test for LANE.)
+                                */
+                               tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
+                                       0xFF00);
+                               gen_not(tmp);
+
+                               /*
+                                * Now check the MAC address.
+                                */
+                               b = gen_ehostop(eaddr, (int)q.dir);
+                               gen_and(tmp, b);
+                               return b;
+                       }
+                       break;
+               case DLT_IP_OVER_FC:
+                       return gen_ipfchostop(eaddr, (int)q.dir);
+               default:
+                       bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+                       break;
+               }
        }
        bpf_error("ethernet address used in non-ether expression");
        /* NOTREACHED */
@@ -5691,14 +6564,14 @@ gen_load(proto, inst, size)
                 * XXX - are there any cases where we want
                 * off_nl_nosnap?
                 */
-               s = gen_llprefixlen();
+               s = gen_off_macpl();
 
                /*
                 * If "s" is non-null, it has code to arrange that the
-                * X register contains the length of the prefix preceding
-                * the link-layer header.  Add to it the offset computed
-                * into the register specified by "index", and move that
-                * into the X register.  Otherwise, just load into the X
+                * X register contains the offset of the MAC-layer
+                * payload.  Add to it the offset computed into the
+                * register specified by "index", and move that into
+                * the X register.  Otherwise, just load into the X
                 * register the offset computed into the register specifed
                 * by "index".
                 */
@@ -5712,13 +6585,17 @@ gen_load(proto, inst, size)
                /*
                 * Load the item at the sum of the offset we've put in the
                 * X register, the offset of the start of the network
-                * layer header, and the offset of the start of the link
-                * layer header (which is 0 if the radio header is
-                * variable-length; that header length is what we put
-                * into the X register and then added to the index).
+                * layer header from the beginning of the MAC-layer
+                * payload, and the purported offset of the start of the
+                * MAC-layer payload (which might be 0 if there's a
+                * variable-length prefix before the link-layer header
+                * or the link-layer header itself is variable-length;
+                * the variable-length offset of the start of the
+                * MAC-layer payload is what we put into the X register
+                * and then added to the index).
                 */
                tmp = new_stmt(BPF_LD|BPF_IND|size);
-               tmp->s.k = off_ll + off_nl;
+               tmp->s.k = off_macpl + off_nl;
                sappend(s, tmp);
                sappend(inst->s, s);
 
@@ -5759,22 +6636,24 @@ gen_load(proto, inst, size)
                /*
                 * The X register now contains the sum of the length
                 * of any variable-length header preceding the link-layer
-                * header and the length of the network-layer header.
+                * header, any variable-length link-layer header, and the
+                * length of the network-layer header.
+                *
                 * Load into the A register the offset relative to
                 * the beginning of the transport layer header,
                 * add the X register to that, move that to the
                 * X register, and load with an offset from the
                 * X register equal to the offset of the network
                 * layer header relative to the beginning of
-                * the link-layer header plus the length of any
-                * fixed-length header preceding the link-layer
-                * header.
+                * the MAC-layer payload plus the fixed-length
+                * portion of the offset of the MAC-layer payload
+                * from the beginning of the raw packet data.
                 */
                sappend(s, xfer_to_a(inst));
                sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
                sappend(s, new_stmt(BPF_MISC|BPF_TAX));
                sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size));
-               tmp->s.k = off_ll + off_nl;
+               tmp->s.k = off_macpl + off_nl;
                sappend(inst->s, s);
 
                /*
@@ -5941,6 +6820,16 @@ static int regused[BPF_MEMWORDS];
 static int curreg;
 
 /*
+ * Initialize the table of used registers and the current register.
+ */
+static void
+init_regs()
+{
+       curreg = 0;
+       memset(regused, 0, sizeof regused);
+}
+
+/*
  * Return the next free register.
  */
 static int
@@ -6071,46 +6960,46 @@ gen_broadcast(proto)
 
        case Q_DEFAULT:
        case Q_LINK:
-                switch (linktype) {
-                case DLT_ARCNET:
-                case DLT_ARCNET_LINUX:
-                    return gen_ahostop(abroadcast, Q_DST);
-                case DLT_EN10MB:    
-                    return gen_ehostop(ebroadcast, Q_DST);
-                case DLT_FDDI:
-                    return gen_fhostop(ebroadcast, Q_DST);
-                case DLT_IEEE802:
-                    return gen_thostop(ebroadcast, Q_DST);
-                case DLT_IEEE802_11:
-                case DLT_IEEE802_11_RADIO_AVS:
-                case DLT_IEEE802_11_RADIO:
-                               case DLT_PPI:
-                case DLT_PRISM_HEADER:
-                    return gen_wlanhostop(ebroadcast, Q_DST);
-                case DLT_IP_OVER_FC:
-                    return gen_ipfchostop(ebroadcast, Q_DST);
-                case DLT_SUNATM:
-                    if (is_lane) {
-                       /*
-                        * Check that the packet doesn't begin with an
-                        * LE Control marker.  (We've already generated
-                        * a test for LANE.)
-                        */
-                       b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
-                           0xFF00);
-                       gen_not(b1);
+               switch (linktype) {
+               case DLT_ARCNET:
+               case DLT_ARCNET_LINUX:
+                       return gen_ahostop(abroadcast, Q_DST);
+               case DLT_EN10MB:
+                       return gen_ehostop(ebroadcast, Q_DST);
+               case DLT_FDDI:
+                       return gen_fhostop(ebroadcast, Q_DST);
+               case DLT_IEEE802:
+                       return gen_thostop(ebroadcast, Q_DST);
+               case DLT_IEEE802_11:
+               case DLT_PRISM_HEADER:
+               case DLT_IEEE802_11_RADIO_AVS:
+               case DLT_IEEE802_11_RADIO:
+               case DLT_PPI:
+                       return gen_wlanhostop(ebroadcast, Q_DST);
+               case DLT_IP_OVER_FC:
+                       return gen_ipfchostop(ebroadcast, Q_DST);
+               case DLT_SUNATM:
+                       if (is_lane) {
+                               /*
+                                * Check that the packet doesn't begin with an
+                                * LE Control marker.  (We've already generated
+                                * 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(ebroadcast, Q_DST);
-                       gen_and(b1, b0);
-                       return b0;
-                    }
-                    break;
-                default:
-                    bpf_error("not a broadcast link");
-                }
+                               /*
+                                * Now check the MAC address.
+                                */
+                               b0 = gen_ehostop(ebroadcast, Q_DST);
+                               gen_and(b1, b0);
+                               return b0;
+                       }
+                       break;
+               default:
+                       bpf_error("not a broadcast link");
+               }
                break;
 
        case Q_IP:
@@ -6158,167 +7047,167 @@ gen_multicast(proto)
 
        case Q_DEFAULT:
        case Q_LINK:
-                switch (linktype) {
-                case DLT_ARCNET:
-                case DLT_ARCNET_LINUX:
-                    /* all ARCnet multicasts use the same address */
-                    return gen_ahostop(abroadcast, Q_DST);
-                case  DLT_EN10MB:
-                    /* ether[0] & 1 != 0 */
-                    return gen_mac_multicast(0);
-                case DLT_FDDI:
-                    /*
-                     * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
-                     *
-                     * XXX - was that referring to bit-order issues?
-                     */
-                    /* fddi[1] & 1 != 0 */
-                    return gen_mac_multicast(1);
-                case DLT_IEEE802:
-                    /* tr[2] & 1 != 0 */
-                    return gen_mac_multicast(2);
-                case DLT_IEEE802_11:
-                case DLT_IEEE802_11_RADIO_AVS:
-                               case DLT_PPI:
-                case DLT_IEEE802_11_RADIO:
-                case DLT_PRISM_HEADER:
-                    /*
-                     * Oh, yuk.
-                     *
-                     * For control frames, there is no DA.
-                     *
-                     * For management frames, DA is at an
-                     * offset of 4 from the beginning of
-                     * the packet.
-                     *
-                     * For data frames, DA is at an offset
-                     * of 4 from the beginning of the packet
-                     * if To DS is clear and at an offset of
-                     * 16 from the beginning of the packet
-                     * if To DS is set.
-                     */
-                    
-                    /*
-                     * Generate the tests to be done for data frames.
-                     *
-                     * First, check for To DS set, i.e. "link[1] & 0x01".
-                     */
-                    s = gen_load_a(OR_LINK, 1, BPF_B);
-                    b1 = new_block(JMP(BPF_JSET));
-                    b1->s.k = 0x01;    /* To DS */
-                    b1->stmts = s;
-                    
-                    /*
-                     * If To DS is set, the DA is at 16.
-                     */
-                    b0 = gen_mac_multicast(16);
-                    gen_and(b1, b0);
-                    
-                    /*
-                     * Now, check for To DS not set, i.e. check
-                     * "!(link[1] & 0x01)".
-                     */
-                    s = gen_load_a(OR_LINK, 1, BPF_B);
-                    b2 = new_block(JMP(BPF_JSET));
-                    b2->s.k = 0x01;    /* To DS */
-                    b2->stmts = s;
-                    gen_not(b2);
-                    
-                    /*
-                     * If To DS is not set, the DA is at 4.
-                     */
-                    b1 = gen_mac_multicast(4);
-                    gen_and(b2, b1);
-                    
-                    /*
-                     * Now OR together the last two checks.  That gives
-                     * the complete set of checks for data frames.
-                     */
-                    gen_or(b1, b0);
-                    
-                    /*
-                     * Now check for a data frame.
-                     * I.e, check "link[0] & 0x08".
-                     */
-                    s = gen_load_a(OR_LINK, 0, BPF_B);
-                    b1 = new_block(JMP(BPF_JSET));
-                    b1->s.k = 0x08;
-                    b1->stmts = s;
-                    
-                    /*
-                     * AND that with the checks done for data frames.
-                     */
-                    gen_and(b1, b0);
-                    
-                    /*
-                     * If the high-order bit of the type value is 0, this
-                     * is a management frame.
-                     * I.e, check "!(link[0] & 0x08)".
-                     */
-                    s = gen_load_a(OR_LINK, 0, BPF_B);
-                    b2 = new_block(JMP(BPF_JSET));
-                    b2->s.k = 0x08;
-                    b2->stmts = s;
-                    gen_not(b2);
-                    
-                    /*
-                     * For management frames, the DA is at 4.
-                     */
-                    b1 = gen_mac_multicast(4);
-                    gen_and(b2, b1);
-                    
-                    /*
-                     * OR that with the checks done for data frames.
-                     * That gives the checks done for management and
-                     * data frames.
-                     */
-                    gen_or(b1, b0);
-                    
-                    /*
-                     * If the low-order bit of the type value is 1,
-                     * this is either a control frame or a frame
-                     * with a reserved type, and thus not a
-                     * frame with an SA.
-                     *
-                     * I.e., check "!(link[0] & 0x04)".
-                     */
-                    s = gen_load_a(OR_LINK, 0, BPF_B);
-                    b1 = new_block(JMP(BPF_JSET));
-                    b1->s.k = 0x04;
-                    b1->stmts = s;
-                    gen_not(b1);
-                    
-                    /*
-                     * AND that with the checks for data and management
-                     * frames.
-                     */
-                    gen_and(b1, b0);
-                    return b0;
-                case DLT_IP_OVER_FC:
-                    b0 = gen_mac_multicast(2);
-                    return b0;
-                case DLT_SUNATM:
-                    if (is_lane) {
+               switch (linktype) {
+               case DLT_ARCNET:
+               case DLT_ARCNET_LINUX:
+                       /* all ARCnet multicasts use the same address */
+                       return gen_ahostop(abroadcast, Q_DST);
+               case DLT_EN10MB:
+                       /* ether[0] & 1 != 0 */
+                       return gen_mac_multicast(0);
+               case DLT_FDDI:
                        /*
-                        * Check that the packet doesn't begin with an
-                        * LE Control marker.  (We've already generated
-                        * a test for LANE.)
+                        * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
+                        *
+                        * XXX - was that referring to bit-order issues?
                         */
-                       b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
-                           0xFF00);
+                       /* fddi[1] & 1 != 0 */
+                       return gen_mac_multicast(1);
+               case DLT_IEEE802:
+                       /* tr[2] & 1 != 0 */
+                       return gen_mac_multicast(2);
+               case DLT_IEEE802_11:
+               case DLT_PRISM_HEADER:
+               case DLT_IEEE802_11_RADIO_AVS:
+               case DLT_IEEE802_11_RADIO:
+               case DLT_PPI:
+                       /*
+                        * Oh, yuk.
+                        *
+                        *      For control frames, there is no DA.
+                        *
+                        *      For management frames, DA is at an
+                        *      offset of 4 from the beginning of
+                        *      the packet.
+                        *
+                        *      For data frames, DA is at an offset
+                        *      of 4 from the beginning of the packet
+                        *      if To DS is clear and at an offset of
+                        *      16 from the beginning of the packet
+                        *      if To DS is set.
+                        */
+
+                       /*
+                        * Generate the tests to be done for data frames.
+                        *
+                        * First, check for To DS set, i.e. "link[1] & 0x01".
+                        */
+                       s = gen_load_a(OR_LINK, 1, BPF_B);
+                       b1 = new_block(JMP(BPF_JSET));
+                       b1->s.k = 0x01; /* To DS */
+                       b1->stmts = s;
+
+                       /*
+                        * If To DS is set, the DA is at 16.
+                        */
+                       b0 = gen_mac_multicast(16);
+                       gen_and(b1, b0);
+
+                       /*
+                        * Now, check for To DS not set, i.e. check
+                        * "!(link[1] & 0x01)".
+                        */
+                       s = gen_load_a(OR_LINK, 1, BPF_B);
+                       b2 = new_block(JMP(BPF_JSET));
+                       b2->s.k = 0x01; /* To DS */
+                       b2->stmts = s;
+                       gen_not(b2);
+
+                       /*
+                        * If To DS is not set, the DA is at 4.
+                        */
+                       b1 = gen_mac_multicast(4);
+                       gen_and(b2, b1);
+
+                       /*
+                        * Now OR together the last two checks.  That gives
+                        * the complete set of checks for data frames.
+                        */
+                       gen_or(b1, b0);
+
+                       /*
+                        * Now check for a data frame.
+                        * I.e, check "link[0] & 0x08".
+                        */
+                       s = gen_load_a(OR_LINK, 0, BPF_B);
+                       b1 = new_block(JMP(BPF_JSET));
+                       b1->s.k = 0x08;
+                       b1->stmts = s;
+
+                       /*
+                        * AND that with the checks done for data frames.
+                        */
+                       gen_and(b1, b0);
+
+                       /*
+                        * If the high-order bit of the type value is 0, this
+                        * is a management frame.
+                        * I.e, check "!(link[0] & 0x08)".
+                        */
+                       s = gen_load_a(OR_LINK, 0, BPF_B);
+                       b2 = new_block(JMP(BPF_JSET));
+                       b2->s.k = 0x08;
+                       b2->stmts = s;
+                       gen_not(b2);
+
+                       /*
+                        * For management frames, the DA is at 4.
+                        */
+                       b1 = gen_mac_multicast(4);
+                       gen_and(b2, b1);
+
+                       /*
+                        * OR that with the checks done for data frames.
+                        * That gives the checks done for management and
+                        * data frames.
+                        */
+                       gen_or(b1, b0);
+
+                       /*
+                        * If the low-order bit of the type value is 1,
+                        * this is either a control frame or a frame
+                        * with a reserved type, and thus not a
+                        * frame with an SA.
+                        *
+                        * I.e., check "!(link[0] & 0x04)".
+                        */
+                       s = gen_load_a(OR_LINK, 0, BPF_B);
+                       b1 = new_block(JMP(BPF_JSET));
+                       b1->s.k = 0x04;
+                       b1->stmts = s;
                        gen_not(b1);
 
-                       /* ether[off_mac] & 1 != 0 */
-                       b0 = gen_mac_multicast(off_mac);
+                       /*
+                        * AND that with the checks for data and management
+                        * frames.
+                        */
                        gen_and(b1, b0);
                        return b0;
-                    }
-                    break;
-                default:
-                    break;
-                }
-                /* Link not known to support multicasts */
-                break;
+               case DLT_IP_OVER_FC:
+                       b0 = gen_mac_multicast(2);
+                       return b0;
+               case DLT_SUNATM:
+                       if (is_lane) {
+                               /*
+                                * Check that the packet doesn't begin with an
+                                * LE Control marker.  (We've already generated
+                                * a test for LANE.)
+                                */
+                               b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
+                                   BPF_H, 0xFF00);
+                               gen_not(b1);
+
+                               /* ether[off_mac] & 1 != 0 */
+                               b0 = gen_mac_multicast(off_mac);
+                               gen_and(b1, b0);
+                               return b0;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               /* Link not known to support multicasts */
+               break;
 
        case Q_IP:
                b0 = gen_linktype(ETHERTYPE_IP);
@@ -6415,6 +7304,8 @@ gen_inbound(dir)
         case DLT_JUNIPER_FRELAY:
         case DLT_JUNIPER_CHDLC:
         case DLT_JUNIPER_VP:
+        case DLT_JUNIPER_ST:
+        case DLT_JUNIPER_ISM:
                /* juniper flags (including direction) are stored
                 * the byte after the 3-byte magic number */
                if (dir) {
@@ -6424,7 +7315,7 @@ gen_inbound(dir)
                        /* match incoming packets */
                        b0 = gen_mcmp(OR_LINK, 3, BPF_B, 1, 0x01);
                }
-           break;
+               break;
 
        default:
                bpf_error("inbound/outbound not supported on linktype %d",
@@ -6443,13 +7334,12 @@ gen_pf_ifname(const char *ifname)
        struct block *b0;
        u_int len, off;
 
-       if (linktype == DLT_PFLOG) {
-               len = sizeof(((struct pfloghdr *)0)->ifname);
-               off = offsetof(struct pfloghdr, ifname);
-       } else {
-               bpf_error("ifname not supported on linktype 0x%x", linktype);
+       if (linktype != DLT_PFLOG) {
+               bpf_error("ifname supported only on PF linktype");
                /* NOTREACHED */
        }
+       len = sizeof(((struct pfloghdr *)0)->ifname);
+       off = offsetof(struct pfloghdr, ifname);
        if (strlen(ifname) >= len) {
                bpf_error("ifname interface names can only be %d characters",
                    len-1);
@@ -6466,14 +7356,16 @@ gen_pf_ruleset(char *ruleset)
        struct block *b0;
 
        if (linktype != DLT_PFLOG) {
-               bpf_error("ruleset not supported on linktype 0x%x", linktype);
+               bpf_error("ruleset supported only on PF linktype");
                /* NOTREACHED */
        }
+
        if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) {
                bpf_error("ruleset names can only be %ld characters",
                    (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1));
                /* NOTREACHED */
        }
+
        b0 = gen_bcmp(OR_LINK, offsetof(struct pfloghdr, ruleset),
            strlen(ruleset), (const u_char *)ruleset);
        return (b0);
@@ -6485,14 +7377,13 @@ gen_pf_rnr(int rnr)
 {
        struct block *b0;
 
-       if (linktype == DLT_PFLOG) {
-               b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, rulenr), BPF_W,
-                        (bpf_int32)rnr);
-       } else {
-               bpf_error("rnr not supported on linktype 0x%x", linktype);
+       if (linktype != DLT_PFLOG) {
+               bpf_error("rnr supported only on PF linktype");
                /* NOTREACHED */
        }
 
+       b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, rulenr), BPF_W,
+                (bpf_int32)rnr);
        return (b0);
 }
 
@@ -6503,7 +7394,7 @@ gen_pf_srnr(int srnr)
        struct block *b0;
 
        if (linktype != DLT_PFLOG) {
-               bpf_error("srnr not supported on linktype 0x%x", linktype);
+               bpf_error("srnr supported only on PF linktype");
                /* NOTREACHED */
        }
 
@@ -6518,14 +7409,13 @@ gen_pf_reason(int reason)
 {
        struct block *b0;
 
-       if (linktype == DLT_PFLOG) {
-               b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, reason), BPF_B,
-                   (bpf_int32)reason);
-       } else {
-               bpf_error("reason not supported on linktype 0x%x", linktype);
+       if (linktype != DLT_PFLOG) {
+               bpf_error("reason supported only on PF linktype");
                /* NOTREACHED */
        }
 
+       b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, reason), BPF_B,
+           (bpf_int32)reason);
        return (b0);
 }
 
@@ -6535,14 +7425,13 @@ gen_pf_action(int action)
 {
        struct block *b0;
 
-       if (linktype == DLT_PFLOG) {
-               b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, action), BPF_B,
-                   (bpf_int32)action);
-       } else {
-               bpf_error("action not supported on linktype 0x%x", linktype);
+       if (linktype != DLT_PFLOG) {
+               bpf_error("action supported only on PF linktype");
                /* NOTREACHED */
        }
 
+       b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, action), BPF_B,
+           (bpf_int32)action);
        return (b0);
 }
 #else /* !HAVE_NET_PFVAR_H */
@@ -6595,14 +7484,75 @@ gen_pf_action(int action)
 }
 #endif /* HAVE_NET_PFVAR_H */
 
+/* IEEE 802.11 wireless header */
+struct block *
+gen_p80211_type(int type, int mask)
+{
+       struct block *b0;
+
+       switch (linktype) {
+
+       case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
+               b0 = gen_mcmp(OR_LINK, 0, BPF_B, (bpf_int32)type,
+                   (bpf_int32)mask);
+               break;
+
+       default:
+               bpf_error("802.11 link-layer types supported only on 802.11");
+               /* NOTREACHED */
+       }
+
+       return (b0);
+}
+
+struct block *
+gen_p80211_fcdir(int fcdir)
+{
+       struct block *b0;
+
+       switch (linktype) {
+
+       case DLT_IEEE802_11:
+       case DLT_PRISM_HEADER:
+       case DLT_IEEE802_11_RADIO_AVS:
+       case DLT_IEEE802_11_RADIO:
+               break;
+
+       default:
+               bpf_error("frame direction supported only with 802.11 headers");
+               /* NOTREACHED */
+       }
+
+       b0 = gen_mcmp(OR_LINK, 1, BPF_B, (bpf_int32)fcdir,
+               (bpf_u_int32)IEEE80211_FC1_DIR_MASK);
+
+       return (b0);
+}
+
 struct block *
 gen_acode(eaddr, q)
        register const u_char *eaddr;
        struct qual q;
 {
-       if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
-               if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX)
-                       return gen_ahostop(eaddr, (int)q.dir);
+       switch (linktype) {
+
+       case DLT_ARCNET:
+       case DLT_ARCNET_LINUX:
+               if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) &&
+                   q.proto == Q_LINK)
+                       return (gen_ahostop(eaddr, (int)q.dir));
+               else {
+                       bpf_error("ARCnet address used in non-arc expression");
+                       /* NOTREACHED */
+               }
+               break;
+
+       default:
+               bpf_error("aid supported only on ARCnet");
+               /* NOTREACHED */
        }
        bpf_error("ARCnet address used in non-arc expression");
        /* NOTREACHED */
@@ -6655,10 +7605,11 @@ gen_vlan(vlan_num)
                bpf_error("no VLAN match after MPLS");
 
        /*
-        * Change the offsets to point to the type and data fields within
-        * the VLAN packet.  Just increment the offsets, so that we
-        * can support a hierarchy, e.g. "vlan 300 && vlan 200" to
-        * capture VLAN 200 encapsulated within VLAN 100.
+        * Check for a VLAN packet, and then change the offsets to point
+        * to the type and data fields within the VLAN packet.  Just
+        * increment the offsets, so that we can support a hierarchy, e.g.
+        * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within
+        * VLAN 100.
         *
         * XXX - this is a bit of a kludge.  If we were to split the
         * compiler into a parser that parses an expression and
@@ -6684,15 +7635,29 @@ gen_vlan(vlan_num)
         * be done assuming a VLAN, even though the "or" could be viewed
         * as meaning "or, if this isn't a VLAN packet...".
         */
-       orig_linktype = off_linktype;   /* save original values */
        orig_nl = off_nl;
 
        switch (linktype) {
 
        case DLT_EN10MB:
+               /* check for VLAN */
+               b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+                   (bpf_int32)ETHERTYPE_8021Q);
+
+               /* If a specific VLAN is requested, check VLAN id */
+               if (vlan_num >= 0) {
+                       b1 = gen_mcmp(OR_MACPL, 0, BPF_H,
+                           (bpf_int32)vlan_num, 0x0fff);
+                       gen_and(b0, b1);
+                       b0 = b1;
+               }
+
+               off_macpl += 4;
                off_linktype += 4;
+#if 0
                off_nl_nosnap += 4;
                off_nl += 4;
+#endif
                break;
 
        default:
@@ -6701,17 +7666,6 @@ gen_vlan(vlan_num)
                /*NOTREACHED*/
        }
 
-       /* check for VLAN */
-       b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q);
-
-       /* If a specific VLAN is requested, check VLAN id */
-       if (vlan_num >= 0) {
-               b1 = gen_mcmp(OR_LINK, orig_nl, BPF_H, (bpf_int32)vlan_num,
-                   0x0fff);
-               gen_and(b0, b1);
-               b0 = b1;
-       }
-
        return (b0);
 }
 
@@ -6737,7 +7691,7 @@ gen_mpls(label_num)
 
         if (label_stack_depth > 0) {
             /* just match the bottom-of-stack bit clear */
-            b0 = gen_mcmp(OR_LINK, orig_nl-2, BPF_B, 0, 0x01);
+            b0 = gen_mcmp(OR_MACPL, orig_nl-2, BPF_B, 0, 0x01);
         } else {
             /*
              * Indicate that we're checking MPLS-encapsulated headers,
@@ -6772,7 +7726,7 @@ gen_mpls(label_num)
        /* If a specific MPLS label is requested, check it */
        if (label_num >= 0) {
                label_num = label_num << 12; /* label is shifted 12 bits on the wire */
-               b1 = gen_mcmp(OR_LINK, orig_nl, BPF_W, (bpf_int32)label_num,
+               b1 = gen_mcmp(OR_MACPL, orig_nl, BPF_W, (bpf_int32)label_num,
                    0xfffff000); /* only compare the first 20 bits */
                gen_and(b0, b1);
                b0 = b1;
@@ -6806,7 +7760,8 @@ gen_pppoes()
 
        /*
         * Change the offsets to point to the type and data fields within
-        * the PPP packet.
+        * the PPP packet, and note that this is PPPoE rather than
+        * raw PPP.
         *
         * XXX - this is a bit of a kludge.  If we were to split the
         * compiler into a parser that parses an expression and
@@ -6834,24 +7789,28 @@ gen_pppoes()
         */
        orig_linktype = off_linktype;   /* save original values */
        orig_nl = off_nl;
+       is_pppoes = 1;
 
        /*
         * The "network-layer" protocol is PPPoE, which has a 6-byte
-        * PPPoE header, followed by PPP payload, so we set the
-        * offsets to the network layer offset plus 6 bytes for
-        * the PPPoE header plus the values appropriate for PPP when
-        * encapsulated in Ethernet (which means there's no HDLC
-        * encapsulation).
+        * PPPoE header, followed by a PPP packet.
+        *
+        * There is no HDLC encapsulation for the PPP packet (it's
+        * encapsulated in PPPoES instead), so the link-layer type
+        * starts at the first byte of the PPP packet.  For PPPoE,
+        * that offset is relative to the beginning of the total
+        * link-layer payload, including any 802.2 LLC header, so
+        * it's 6 bytes past off_nl.
         */
-       off_linktype = orig_nl + 6;
-       off_nl = orig_nl + 6 + 2;
-       off_nl_nosnap = orig_nl + 6 + 2;
+       off_linktype = off_nl + 6;
 
        /*
-        * Set the link-layer type to PPP, as all subsequent tests will
-        * be on the encapsulated PPP header.
+        * The network-layer offsets are relative to the beginning
+        * of the MAC-layer payload; that's past the 6-byte
+        * PPPoE header and the 2-byte PPP header.
         */
-       linktype = DLT_PPP;
+       off_nl = 6+2;
+       off_nl_nosnap = 6+2;
 
        return b0;
 }
@@ -6997,8 +7956,9 @@ gen_atmtype_abbrev(type)
                is_lane = 1;
                off_mac = off_payload + 2;      /* MAC header */
                off_linktype = off_mac + 12;
-               off_nl = off_mac + 14;          /* Ethernet II */
-               off_nl_nosnap = off_mac + 17;   /* 802.3+802.2 */
+               off_macpl = off_mac + 14;       /* Ethernet */
+               off_nl = 0;                     /* Ethernet II */
+               off_nl_nosnap = 3;              /* 802.3+802.2 */
                break;
 
        case A_LLC:
@@ -7031,6 +7991,7 @@ gen_mtp2type_abbrev(type)
 
        case M_FISU:
                if ( (linktype != DLT_MTP2) &&
+                    (linktype != DLT_ERF) &&
                     (linktype != DLT_MTP2_WITH_PHDR) )
                        bpf_error("'fisu' supported only on MTP2");
                /* gen_ncmp(offrel, offset, size, mask, jtype, reverse, value) */
@@ -7039,6 +8000,7 @@ gen_mtp2type_abbrev(type)
 
        case M_LSSU:
                if ( (linktype != DLT_MTP2) &&
+                    (linktype != DLT_ERF) &&
                     (linktype != DLT_MTP2_WITH_PHDR) )
                        bpf_error("'lssu' supported only on MTP2");
                b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 1, 2);
@@ -7048,6 +8010,7 @@ gen_mtp2type_abbrev(type)
 
        case M_MSU:
                if ( (linktype != DLT_MTP2) &&
+                    (linktype != DLT_ERF) &&
                     (linktype != DLT_MTP2_WITH_PHDR) )
                        bpf_error("'msu' supported only on MTP2");
                b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 2);
index f4c5cf7..39b1eea 100644 (file)
@@ -18,7 +18,7 @@
  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * @(#) $Header: /tcpdump/master/libpcap/gencode.h,v 1.60.2.11 2007/06/11 09:52:04 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/gencode.h,v 1.70.2.1 2007/11/18 02:04:55 guy Exp $ (LBL)
  */
 
 /*
 #define Q_DST          2
 #define Q_OR           3
 #define Q_AND          4
+#define Q_ADDR1                5
+#define Q_ADDR2                6
+#define Q_ADDR3                7
+#define Q_ADDR4                8
 
 #define Q_DEFAULT      0
 #define Q_UNDEF                255
@@ -312,6 +316,9 @@ struct block *gen_pf_reason(int);
 struct block *gen_pf_action(int);
 struct block *gen_pf_dir(int);
 
+struct block *gen_p80211_type(int, int);
+struct block *gen_p80211_fcdir(int);
+
 void bpf_optimize(struct block **);
 void bpf_error(const char *, ...)
     __attribute__((noreturn, format (printf, 1, 2)));
index f9b7cb1..7076c87 100644 (file)
@@ -22,7 +22,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/grammar.y,v 1.86.2.9 2007/09/12 19:17:25 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/grammar.y,v 1.99.2.2 2007/11/18 02:04:55 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -57,7 +57,8 @@ struct rtentry;
 #include <net/pfvar.h>
 #include <net/if_pflog.h>
 #endif
-#include <pcap-namedb.h>
+#include "ieee80211.h"
+#include <pcap/namedb.h>
 
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
@@ -67,6 +68,92 @@ struct rtentry;
                         (q).dir = (d),\
                         (q).addr = (a)
 
+struct tok {
+       int v;                  /* value */
+       const char *s;          /* string */
+};
+
+static const struct tok ieee80211_types[] = {
+       { IEEE80211_FC0_TYPE_DATA, "data" },
+       { IEEE80211_FC0_TYPE_MGT, "mgt" },
+       { IEEE80211_FC0_TYPE_MGT, "management" },
+       { IEEE80211_FC0_TYPE_CTL, "ctl" },
+       { IEEE80211_FC0_TYPE_CTL, "control" },
+       { 0, NULL }
+};
+static const struct tok ieee80211_mgt_subtypes[] = {
+       { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assocreq" },
+       { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assoc-req" },
+       { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assocresp" },
+       { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assoc-resp" },
+       { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassocreq" },
+       { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassoc-req" },
+       { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassocresp" },
+       { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassoc-resp" },
+       { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probereq" },
+       { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probe-req" },
+       { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "proberesp" },
+       { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "probe-resp" },
+       { IEEE80211_FC0_SUBTYPE_BEACON, "beacon" },
+       { IEEE80211_FC0_SUBTYPE_ATIM, "atim" },
+       { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassoc" },
+       { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassociation" },
+       { IEEE80211_FC0_SUBTYPE_AUTH, "auth" },
+       { IEEE80211_FC0_SUBTYPE_AUTH, "authentication" },
+       { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauth" },
+       { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauthentication" },
+       { 0, NULL }
+};
+static const struct tok ieee80211_ctl_subtypes[] = {
+       { IEEE80211_FC0_SUBTYPE_PS_POLL, "ps-poll" },
+       { IEEE80211_FC0_SUBTYPE_RTS, "rts" },
+       { IEEE80211_FC0_SUBTYPE_CTS, "cts" },
+       { IEEE80211_FC0_SUBTYPE_ACK, "ack" },
+       { IEEE80211_FC0_SUBTYPE_CF_END, "cf-end" },
+       { IEEE80211_FC0_SUBTYPE_CF_END_ACK, "cf-end-ack" },
+       { 0, NULL }
+};
+static const struct tok ieee80211_data_subtypes[] = {
+       { IEEE80211_FC0_SUBTYPE_DATA, "data" },
+       { IEEE80211_FC0_SUBTYPE_CF_ACK, "data-cf-ack" },
+       { IEEE80211_FC0_SUBTYPE_CF_POLL, "data-cf-poll" },
+       { IEEE80211_FC0_SUBTYPE_CF_ACPL, "data-cf-ack-poll" },
+       { IEEE80211_FC0_SUBTYPE_NODATA, "null" },
+       { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK, "cf-ack" },
+       { IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "cf-poll"  },
+       { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "cf-ack-poll" },
+       { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_DATA, "qos-data" },
+       { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACK, "qos-data-cf-ack" },
+       { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_POLL, "qos-data-cf-poll" },
+       { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACPL, "qos-data-cf-ack-poll" },
+       { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA, "qos" },
+       { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "qos-cf-poll" },
+       { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "qos-cf-ack-poll" },
+       { 0, NULL }
+};
+struct type2tok {
+       int type;
+       const struct tok *tok;
+};
+static const struct type2tok ieee80211_type_subtypes[] = {
+       { IEEE80211_FC0_TYPE_MGT, ieee80211_mgt_subtypes },
+       { IEEE80211_FC0_TYPE_CTL, ieee80211_ctl_subtypes },
+       { IEEE80211_FC0_TYPE_DATA, ieee80211_data_subtypes },
+       { 0, NULL }
+};
+
+static int
+str2tok(const char *str, const struct tok *toks)
+{
+       int i;
+
+       for (i = 0; toks[i].s != NULL; i++) {
+               if (pcap_strcasecmp(toks[i].s, str) == 0)
+                       return (toks[i].v);
+       }
+       return (-1);
+}
+
 int n_errors = 0;
 
 static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
@@ -113,6 +200,16 @@ pfaction_to_num(const char *action)
        else if (pcap_strcasecmp(action, "drop") == 0 ||
                pcap_strcasecmp(action, "block") == 0)
                return (PF_DROP);
+#if HAVE_PF_NAT_THROUGH_PF_NORDR
+       else if (pcap_strcasecmp(action, "rdr") == 0)
+               return (PF_RDR);
+       else if (pcap_strcasecmp(action, "nat") == 0)
+               return (PF_NAT);
+       else if (pcap_strcasecmp(action, "binat") == 0)
+               return (PF_BINAT);
+       else if (pcap_strcasecmp(action, "nordr") == 0)
+               return (PF_NORDR);
+#endif
        else {
                bpf_error("unknown PF action");
                /*NOTREACHED*/
@@ -124,6 +221,9 @@ pfreason_to_num(const char *reason)
 {
        bpf_error("libpcap was compiled on a machine without pf support");
        /*NOTREACHED*/
+
+       /* this is to make the VC compiler happy */
+       return -1;
 }
 
 static int
@@ -131,6 +231,9 @@ pfaction_to_num(const char *action)
 {
        bpf_error("libpcap was compiled on a machine without pf support");
        /*NOTREACHED*/
+
+       /* this is to make the VC compiler happy */
+       return -1;
 }
 #endif /* HAVE_NET_PFVAR_H */
 %}
@@ -157,7 +260,7 @@ pfaction_to_num(const char *action)
 %type  <a>     arth narth
 %type  <i>     byteop pname pnum relop irelop
 %type  <blk>   and or paren not null prog
-%type  <rblk>  other pfvar
+%type  <rblk>  other pfvar p80211
 %type  <i>     atmtype atmmultitype
 %type  <blk>   atmfield
 %type  <blk>   atmfieldvalue atmvalue atmlistvalue
@@ -173,6 +276,7 @@ pfaction_to_num(const char *action)
 %token  TK_BROADCAST TK_MULTICAST
 %token  NUM INBOUND OUTBOUND
 %token  PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION
+%token TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4
 %token  LINK
 %token GEQ LEQ NEQ
 %token ID EID HID HID6 AID
@@ -196,7 +300,7 @@ pfaction_to_num(const char *action)
 %type  <e> EID
 %type  <e> AID
 %type  <s> HID HID6
-%type  <i> NUM action reason
+%type  <i> NUM action reason type subtype type_subtype dir
 
 %left OR AND
 %nonassoc  '!'
@@ -238,6 +342,14 @@ nid:         ID                    { $$.b = gen_scode($1, $$.q = $<blk>0.q); }
        | HID                   {
                                  /* Decide how to parse HID based on proto */
                                  $$.q = $<blk>0.q;
+                                 if ($$.q.addr == Q_PORT)
+                                       bpf_error("'port' modifier applied to ip host");
+                                 else if ($$.q.addr == Q_PORTRANGE)
+                                       bpf_error("'portrange' modifier applied to ip host");
+                                 else if ($$.q.addr == Q_PROTO)
+                                       bpf_error("'proto' modifier applied to ip host");
+                                 else if ($$.q.addr == Q_PROTOCHAIN)
+                                       bpf_error("'protochain' modifier applied to ip host");
                                  $$.b = gen_ncode($1, 0, $$.q);
                                }
        | HID6 '/' NUM          {
@@ -325,6 +437,10 @@ dqual:       SRC                   { $$ = Q_SRC; }
        | DST OR SRC            { $$ = Q_OR; }
        | SRC AND DST           { $$ = Q_AND; }
        | DST AND SRC           { $$ = Q_AND; }
+       | ADDR1                 { $$ = Q_ADDR1; }
+       | ADDR2                 { $$ = Q_ADDR2; }
+       | ADDR3                 { $$ = Q_ADDR3; }
+       | ADDR4                 { $$ = Q_ADDR4; }
        ;
 /* address type qualifiers */
 aqual:   HOST                  { $$ = Q_HOST; }
@@ -388,6 +504,7 @@ other:        pqual TK_BROADCAST    { $$ = gen_broadcast($1); }
        | PPPOED                { $$ = gen_pppoed(); }
        | PPPOES                { $$ = gen_pppoes(); }
        | pfvar                 { $$ = $1; }
+       | pqual p80211          { $$ = $2; }
        ;
 
 pfvar:   PF_IFNAME ID          { $$ = gen_pf_ifname($2); }
@@ -398,6 +515,79 @@ pfvar:       PF_IFNAME ID          { $$ = gen_pf_ifname($2); }
        | PF_ACTION action      { $$ = gen_pf_action($2); }
        ;
 
+p80211:   TYPE type SUBTYPE subtype
+                               { $$ = gen_p80211_type($2 | $4,
+                                       IEEE80211_FC0_TYPE_MASK |
+                                       IEEE80211_FC0_SUBTYPE_MASK);
+                               }
+       | TYPE type             { $$ = gen_p80211_type($2,
+                                       IEEE80211_FC0_TYPE_MASK);
+                               }
+       | SUBTYPE type_subtype  { $$ = gen_p80211_type($2,
+                                       IEEE80211_FC0_TYPE_MASK |
+                                       IEEE80211_FC0_SUBTYPE_MASK);
+                               }
+       | DIR dir               { $$ = gen_p80211_fcdir($2); }
+       ;
+
+type:    NUM
+       | ID                    { $$ = str2tok($1, ieee80211_types);
+                                 if ($$ == -1)
+                                       bpf_error("unknown 802.11 type name");
+                               }
+       ;
+
+subtype:  NUM
+       | ID                    { const struct tok *types = NULL;
+                                 int i;
+                                 for (i = 0;; i++) {
+                                       if (ieee80211_type_subtypes[i].tok == NULL) {
+                                               /* Ran out of types */
+                                               bpf_error("unknown 802.11 type");
+                                               break;
+                                       }
+                                       if ($<i>-1 == ieee80211_type_subtypes[i].type) {
+                                               types = ieee80211_type_subtypes[i].tok;
+                                               break;
+                                       }
+                                 }
+
+                                 $$ = str2tok($1, types);
+                                 if ($$ == -1)
+                                       bpf_error("unknown 802.11 subtype name");
+                               }
+       ;
+
+type_subtype:  ID              { int i;
+                                 for (i = 0;; i++) {
+                                       if (ieee80211_type_subtypes[i].tok == NULL) {
+                                               /* Ran out of types */
+                                               bpf_error("unknown 802.11 type name");
+                                               break;
+                                       }
+                                       $$ = str2tok($1, ieee80211_type_subtypes[i].tok);
+                                       if ($$ != -1) {
+                                               $$ |= ieee80211_type_subtypes[i].type;
+                                               break;
+                                       }
+                                 }
+                               }
+               ;
+
+dir:     NUM
+       | ID                    { if (pcap_strcasecmp($1, "nods") == 0)
+                                       $$ = IEEE80211_FC1_DIR_NODS;
+                                 else if (pcap_strcasecmp($1, "tods") == 0)
+                                       $$ = IEEE80211_FC1_DIR_TODS;
+                                 else if (pcap_strcasecmp($1, "fromds") == 0)
+                                       $$ = IEEE80211_FC1_DIR_FROMDS;
+                                 else if (pcap_strcasecmp($1, "dstods") == 0)
+                                       $$ = IEEE80211_FC1_DIR_DSTODS;
+                                 else
+                                       bpf_error("unknown 802.11 direction");
+                               }
+       ;
+
 reason:          NUM                   { $$ = $1; }
        | ID                    { $$ = pfreason_to_num($1); }
        ;
index 8a44728..aad8796 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.66.2.6 2007/06/11 09:52:04 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.75.2.4 2008-04-20 18:19:24 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -356,6 +356,40 @@ add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name,
        return (0);
 }
 
+/*
+ * XXX - on FreeBSDs that support it, should it get the sysctl named
+ * "dev.{adapter family name}.{adapter unit}.%desc" to get a description
+ * of the adapter?  Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800"
+ * with my Cisco 350 card, so the name isn't entirely descriptive.  The
+ * "dev.an.0.%pnpinfo" has a better description, although one might argue
+ * that the problem is really a driver bug - if it can find out that it's
+ * a Cisco 340 or 350, rather than an old Aironet card, it should use
+ * that in the description.
+ *
+ * Do NetBSD, DragonflyBSD, or OpenBSD support this as well?  OpenBSD
+ * lets you get a description, but it's not generated by the OS, it's
+ * set with another ioctl that ifconfig supports; we use that to get
+ * the description in OpenBSD.
+ *
+ * In OS X, the System Configuration framework can apparently return
+ * names in 10.4 and later; it also appears that freedesktop.org's HAL
+ * offers an "info.product" string, but the HAL specification says
+ * it "should not be used in any UI" and "subsystem/capability
+ * specific properties" should be used instead.  Using that would
+ * require that libpcap applications be linked with the frameworks/
+ * libraries in question, which would be a bit of a pain unless we
+ * offer, for example, a pkg-config:
+ *
+ *     http://pkg-config.freedesktop.org/wiki/
+ *
+ * script, so applications can just use that script to find out what
+ * libraries you need to link with when linking with libpcap.
+ * pkg-config is GPLed; I don't know whether that would prevent its
+ * use with a BSD-licensed library such as libpcap.
+ *
+ * Do any other UN*Xes, or desktop environments support getting a
+ * description?
+ */
 int
 add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags,
     struct sockaddr *addr, size_t addr_size,
@@ -365,9 +399,32 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags,
     char *errbuf)
 {
        pcap_if_t *curdev;
+       char *description = NULL;
        pcap_addr_t *curaddr, *prevaddr, *nextaddr;
+#ifdef SIOCGIFDESCR
+       struct ifreq ifrdesc;
+       char ifdescr[IFDESCRSIZE];
+       int s;
+#endif
 
-       if (add_or_find_if(&curdev, alldevs, name, flags, NULL, errbuf) == -1) {
+#ifdef SIOCGIFDESCR
+       /*
+        * Get the description for the interface.
+        */
+       memset(&ifrdesc, 0, sizeof ifrdesc);
+       strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
+       ifrdesc.ifr_data = (caddr_t)&ifdescr;
+       s = socket(AF_INET, SOCK_DGRAM, 0);
+       if (s >= 0) {
+               if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0 &&
+                   strlen(ifrdesc.ifr_data) != 0)
+                       description = ifrdesc.ifr_data;
+               close(s);
+       }
+#endif
+
+       if (add_or_find_if(&curdev, alldevs, name, flags, description,
+           errbuf) == -1) {
                /*
                 * Error - give up.
                 */
@@ -608,6 +665,12 @@ pcap_lookupnet(device, netp, maskp, errbuf)
 #ifdef HAVE_SEPTEL_API
            || strstr(device, "septel") != NULL
 #endif
+#ifdef PCAP_SUPPORT_BT
+           || strstr(device, "bluetooth") != NULL
+#endif
+#ifdef PCAP_SUPPORT_USB
+           || strstr(device, "usb") != NULL
+#endif
            ) {
                *netp = *maskp = 0;
                return 0;
index d60e93d..c21e784 100644 (file)
@@ -24,7 +24,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/nametoaddr.c,v 1.77.2.4 2007/06/11 09:52:05 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/nametoaddr.c,v 1.82.2.1 2008/02/06 10:21:47 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -80,7 +80,7 @@ struct rtentry;               /* declarations in <net/if.h> */
 #include "pcap-int.h"
 
 #include "gencode.h"
-#include <pcap-namedb.h>
+#include <pcap/namedb.h>
 
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
@@ -398,7 +398,15 @@ __pcap_atodn(const char *s, bpf_u_int32 *addr)
 }
 
 /*
- * Convert 's' which has the form "xx:xx:xx:xx:xx:xx" into a new
+ * Convert 's', which can have the one of the forms:
+ *
+ *     "xx:xx:xx:xx:xx:xx"
+ *     "xx.xx.xx.xx.xx.xx"
+ *     "xx-xx-xx-xx-xx-xx"
+ *     "xxxx.xxxx.xxxx"
+ *     "xxxxxxxxxxxx"
+ *
+ * (or various mixes of ':', '.', and '-') into a new
  * ethernet address.  Assumes 's' is well formed.
  */
 u_char *
@@ -410,7 +418,7 @@ pcap_ether_aton(const char *s)
        e = ep = (u_char *)malloc(6);
 
        while (*s) {
-               if (*s == ':')
+               if (*s == ':' || *s == '.' || *s == '-')
                        s += 1;
                d = xdtoi(*s++);
                if (isxdigit((unsigned char)*s)) {
index d39273b..475313f 100644 (file)
@@ -22,7 +22,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/optimize.c,v 1.85.2.3 2007/09/12 21:29:45 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/optimize.c,v 1.90.2.1 2008/01/02 04:22:16 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -53,6 +53,10 @@ extern int _w32_ffs (int mask);
 #define ffs _w32_ffs
 #endif
 
+#if defined(WIN32) && defined (_MSC_VER)
+int ffs(int mask);
+#endif
+
 /*
  * Represents a deleted instruction.
  */
@@ -906,6 +910,17 @@ opt_peep(b)
                        JF(b) = JT(b);
        }
        /*
+        * If we're comparing against the index register, and the index
+        * register is a known constant, we can just compare against that
+        * constant.
+        */
+       val = b->val[X_ATOM];
+       if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) {
+               bpf_int32 v = vmap[val].const_val;
+               b->s.code &= ~BPF_X;
+               b->s.k = v;
+       }
+       /*
         * If the accumulator is a known constant, we can compute the
         * comparison result.
         */
@@ -2277,6 +2292,15 @@ install_bpf_program(pcap_t *p, struct bpf_program *fp)
        size_t prog_size;
 
        /*
+        * Validate the program.
+        */
+       if (!bpf_validate(fp->bf_insns, fp->bf_len)) {
+               snprintf(p->errbuf, sizeof(p->errbuf),
+                       "BPF program is not valid");
+               return (-1);
+       }
+
+       /*
         * Free up any already installed program.
         */
        pcap_freecode(&p->fcode);
index 027913e..6ec6515 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.86.2.12 2007/06/15 17:57:27 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.99.2.17 2008-09-16 18:43:02 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -28,6 +28,9 @@ static const char rcsid[] _U_ =
 #endif
 
 #include <sys/param.h>                 /* optionally get BSD define */
+#ifdef HAVE_ZEROCOPY_BPF
+#include <sys/mman.h>
+#endif
 #include <sys/time.h>
 #include <sys/timeb.h>
 #include <sys/socket.h>
@@ -35,12 +38,16 @@ static const char rcsid[] _U_ =
 #include <sys/ioctl.h>
 #include <sys/utsname.h>
 
+#ifdef HAVE_ZEROCOPY_BPF
+#include <machine/atomic.h>
+#endif
+
 #include <net/if.h>
 
 #ifdef _AIX
 
 /*
- * Make "pcap.h" not include "pcap-bpf.h"; we are going to include the
+ * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the
  * native OS version, as we need "struct bpf_config" from it.
  */
 #define PCAP_DONT_INCLUDE_PCAP_BPF_H
@@ -92,6 +99,10 @@ static int odmlockid = 0;
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_NET_IF_MEDIA_H
+# include <net/if_media.h>
+#endif
+
 #include "pcap-int.h"
 
 #ifdef HAVE_DAG_API
@@ -102,12 +113,579 @@ static int odmlockid = 0;
 #include "os-proto.h"
 #endif
 
-#include "gencode.h"   /* for "no_optimize" */
+#ifdef BIOCGDLTLIST
+# if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__)
+#define HAVE_BSD_IEEE80211
+# endif
+
+# if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)
+static int find_802_11(struct bpf_dltlist *);
+
+#  ifdef HAVE_BSD_IEEE80211
+static int monitor_mode(pcap_t *, int);
+#  endif
+
+#  if defined(__APPLE__)
+static void remove_en(pcap_t *);
+static void remove_802_11(pcap_t *);
+#  endif
+
+# endif /* defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) */
+
+#endif /* BIOCGDLTLIST */
+
+/*
+ * We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably
+ * don't get DLT_DOCSIS defined.
+ */
+#ifndef DLT_DOCSIS
+#define DLT_DOCSIS     143
+#endif
+
+/*
+ * On OS X, we don't even get any of the 802.11-plus-radio-header DLT_'s
+ * defined, even though some of them are used by various Airport drivers.
+ */
+#ifndef DLT_PRISM_HEADER
+#define DLT_PRISM_HEADER       119
+#endif
+#ifndef DLT_AIRONET_HEADER
+#define DLT_AIRONET_HEADER     120
+#endif
+#ifndef DLT_IEEE802_11_RADIO
+#define DLT_IEEE802_11_RADIO   127
+#endif
+#ifndef DLT_IEEE802_11_RADIO_AVS
+#define DLT_IEEE802_11_RADIO_AVS 163
+#endif
 
+static int pcap_can_set_rfmon_bpf(pcap_t *p);
+static int pcap_activate_bpf(pcap_t *p);
 static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp);
 static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t);
 static int pcap_set_datalink_bpf(pcap_t *p, int dlt);
 
+#ifdef HAVE_ZEROCOPY_BPF
+/*
+ * For zerocopy bpf, we need to override the setnonblock/getnonblock routines
+ * so we don't call select(2) if the pcap handle is in non-blocking mode.  We
+ * preserve the timeout supplied by pcap_open functions to make sure it
+ * does not get clobbered if the pcap handle moves between blocking and non-
+ * blocking mode.
+ */
+static int
+pcap_getnonblock_zbuf(pcap_t *p, char *errbuf)
+{ 
+       /*
+        * Use a negative value for the timeout to represent that the
+        * pcap handle is in non-blocking mode.
+        */
+       return (p->md.timeout < 0);
+}
+
+static int
+pcap_setnonblock_zbuf(pcap_t *p, int nonblock, char *errbuf)
+{   
+       /*
+        * Map each value to the corresponding 2's complement, to
+        * preserve the timeout value provided with pcap_set_timeout.
+        * (from pcap-linux.c).
+        */
+       if (nonblock) {
+               if (p->md.timeout > 0)
+                       p->md.timeout = p->md.timeout * -1 - 1;
+       } else
+               if (p->md.timeout < 0)
+                       p->md.timeout = (p->md.timeout + 1) * -1;
+       return (0);
+}
+
+/*
+ * Zero-copy specific close method.  Un-map the shared buffers then call
+ * pcap_cleanup_live_common.
+ */
+static void
+pcap_cleanup_zbuf(pcap_t *p)
+{
+       /*
+        * Delete the mappings.  Note that p->buffer gets initialized to one
+        * of the mmapped regions in this case, so do not try and free it
+        * directly; null it out so that pcap_cleanup_live_common() doesn't
+        * try to free it.
+        */
+       if (p->md.zbuf1 != MAP_FAILED && p->md.zbuf1 != NULL)
+               (void) munmap(p->md.zbuf1, p->md.zbufsize);
+       if (p->md.zbuf2 != MAP_FAILED && p->md.zbuf2 != NULL)
+               (void) munmap(p->md.zbuf2, p->md.zbufsize);
+       p->buffer = NULL;
+       pcap_cleanup_live_common(p);
+}
+
+/*
+ * Zero-copy BPF buffer routines to check for and acknowledge BPF data in
+ * shared memory buffers.
+ *
+ * pcap_next_zbuf_shm(): Check for a newly available shared memory buffer,
+ * and set up p->buffer and cc to reflect one if available.  Notice that if
+ * there was no prior buffer, we select zbuf1 as this will be the first
+ * buffer filled for a fresh BPF session.
+ */
+static int
+pcap_next_zbuf_shm(pcap_t *p, int *cc)
+{
+       struct bpf_zbuf_header *bzh;
+
+       if (p->md.zbuffer == p->md.zbuf2 || p->md.zbuffer == NULL) {
+               bzh = (struct bpf_zbuf_header *)p->md.zbuf1;
+               if (bzh->bzh_user_gen !=
+                   atomic_load_acq_int(&bzh->bzh_kernel_gen)) {
+                       p->md.bzh = bzh;
+                       p->md.zbuffer = (u_char *)p->md.zbuf1;
+                       p->buffer = p->md.zbuffer + sizeof(*bzh);
+                       *cc = bzh->bzh_kernel_len;
+                       return (1);
+               }
+       } else if (p->md.zbuffer == p->md.zbuf1) {
+               bzh = (struct bpf_zbuf_header *)p->md.zbuf2;
+               if (bzh->bzh_user_gen !=
+                   atomic_load_acq_int(&bzh->bzh_kernel_gen)) {
+                       p->md.bzh = bzh;
+                       p->md.zbuffer = (u_char *)p->md.zbuf2;
+                       p->buffer = p->md.zbuffer + sizeof(*bzh);
+                       *cc = bzh->bzh_kernel_len;
+                       return (1);
+               }
+       }
+       *cc = 0;
+       return (0);
+}
+
+/*
+ * pcap_next_zbuf() -- Similar to pcap_next_zbuf_shm(), except wait using
+ * select() for data or a timeout, and possibly force rotation of the buffer
+ * in the event we time out or are in immediate mode.  Invoke the shared
+ * memory check before doing system calls in order to avoid doing avoidable
+ * work.
+ */
+static int
+pcap_next_zbuf(pcap_t *p, int *cc)
+{
+       struct bpf_zbuf bz;
+       struct timeval tv;
+       struct timespec cur;
+       fd_set r_set;
+       int data, r;
+       int expire, tmout;
+
+#define TSTOMILLI(ts) (((ts)->tv_sec * 1000) + ((ts)->tv_nsec / 1000000))
+       /*
+        * Start out by seeing whether anything is waiting by checking the
+        * next shared memory buffer for data.
+        */
+       data = pcap_next_zbuf_shm(p, cc);
+       if (data)
+               return (data);
+       /*
+        * If a previous sleep was interrupted due to signal delivery, make
+        * sure that the timeout gets adjusted accordingly.  This requires
+        * that we analyze when the timeout should be been expired, and
+        * subtract the current time from that.  If after this operation,
+        * our timeout is less then or equal to zero, handle it like a
+        * regular timeout.
+        */
+       tmout = p->md.timeout;
+       if (tmout)
+               (void) clock_gettime(CLOCK_MONOTONIC, &cur);
+       if (p->md.interrupted && p->md.timeout) {
+               expire = TSTOMILLI(&p->md.firstsel) + p->md.timeout;
+               tmout = expire - TSTOMILLI(&cur);
+#undef TSTOMILLI
+               if (tmout <= 0) {
+                       p->md.interrupted = 0;
+                       data = pcap_next_zbuf_shm(p, cc);
+                       if (data)
+                               return (data);
+                       if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) {
+                               (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                                   "BIOCROTZBUF: %s", strerror(errno));
+                               return (PCAP_ERROR);
+                       }
+                       return (pcap_next_zbuf_shm(p, cc));
+               }
+       }
+       /*
+        * No data in the buffer, so must use select() to wait for data or
+        * the next timeout.  Note that we only call select if the handle
+        * is in blocking mode.
+        */
+       if (p->md.timeout >= 0) {
+               FD_ZERO(&r_set);
+               FD_SET(p->fd, &r_set);
+               if (tmout != 0) {
+                       tv.tv_sec = tmout / 1000;
+                       tv.tv_usec = (tmout * 1000) % 1000000;
+               }
+               r = select(p->fd + 1, &r_set, NULL, NULL,
+                   p->md.timeout != 0 ? &tv : NULL);
+               if (r < 0 && errno == EINTR) {
+                       if (!p->md.interrupted && p->md.timeout) {
+                               p->md.interrupted = 1;
+                               p->md.firstsel = cur;
+                       }
+                       return (0);
+               } else if (r < 0) {
+                       (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "select: %s", strerror(errno));
+                       return (PCAP_ERROR);
+               }
+       }
+       p->md.interrupted = 0;
+       /*
+        * Check again for data, which may exist now that we've either been
+        * woken up as a result of data or timed out.  Try the "there's data"
+        * case first since it doesn't require a system call.
+        */
+       data = pcap_next_zbuf_shm(p, cc);
+       if (data)
+               return (data);
+       /*
+        * Try forcing a buffer rotation to dislodge timed out or immediate
+        * data.
+        */
+       if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) {
+               (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "BIOCROTZBUF: %s", strerror(errno));
+               return (PCAP_ERROR);
+       }
+       return (pcap_next_zbuf_shm(p, cc));
+}
+
+/*
+ * Notify kernel that we are done with the buffer.  We don't reset zbuffer so
+ * that we know which buffer to use next time around.
+ */
+static int
+pcap_ack_zbuf(pcap_t *p)
+{
+
+       atomic_store_rel_int(&p->md.bzh->bzh_user_gen,
+           p->md.bzh->bzh_kernel_gen);
+       p->md.bzh = NULL;
+       p->buffer = NULL;
+       return (0);
+}
+#endif
+
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+#ifdef HAVE_DAG_API
+       if (strstr(device, "dag"))
+               return (dag_create(device, ebuf));
+#endif /* HAVE_DAG_API */
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_bpf;
+       p->can_set_rfmon_op = pcap_can_set_rfmon_bpf;
+       return (p);
+}
+
+static int
+bpf_open(pcap_t *p)
+{
+       int fd;
+#ifdef HAVE_CLONING_BPF
+       static const char device[] = "/dev/bpf";
+#else
+       int n = 0;
+       char device[sizeof "/dev/bpf0000000000"];
+#endif
+
+#ifdef _AIX
+       /*
+        * Load the bpf driver, if it isn't already loaded,
+        * and create the BPF device entries, if they don't
+        * already exist.
+        */
+       if (bpf_load(p->errbuf) == PCAP_ERROR)
+               return (PCAP_ERROR);
+#endif
+
+#ifdef HAVE_CLONING_BPF
+       if ((fd = open(device, O_RDWR)) == -1 &&
+           (errno != EACCES || (fd = open(device, O_RDONLY)) == -1)) {
+               if (errno == EACCES)
+                       fd = PCAP_ERROR_PERM_DENIED;
+               else
+                       fd = PCAP_ERROR;
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                 "(cannot open device) %s: %s", device, pcap_strerror(errno));
+       }
+#else
+       /*
+        * Go through all the minors and find one that isn't in use.
+        */
+       do {
+               (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+               /*
+                * Initially try a read/write open (to allow the inject
+                * method to work).  If that fails due to permission
+                * issues, fall back to read-only.  This allows a
+                * non-root user to be granted specific access to pcap
+                * capabilities via file permissions.
+                *
+                * XXX - we should have an API that has a flag that
+                * controls whether to open read-only or read-write,
+                * so that denial of permission to send (or inability
+                * to send, if sending packets isn't supported on
+                * the device in question) can be indicated at open
+                * time.
+                */
+               fd = open(device, O_RDWR);
+               if (fd == -1 && errno == EACCES)
+                       fd = open(device, O_RDONLY);
+       } while (fd < 0 && errno == EBUSY);
+
+       /*
+        * XXX better message for all minors used
+        */
+       if (fd < 0) {
+               if (errno == EACCES)
+                       fd = PCAP_ERROR_PERM_DENIED;
+               else
+                       fd = PCAP_ERROR;
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
+                   device, pcap_strerror(errno));
+       }
+#endif
+
+       return (fd);
+}
+
+#ifdef BIOCGDLTLIST
+static int
+get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf)
+{
+       memset(bdlp, 0, sizeof(*bdlp));
+       if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) == 0) {
+               u_int i;
+               int is_ethernet;
+
+               bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1));
+               if (bdlp->bfl_list == NULL) {
+                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+                           pcap_strerror(errno));
+                       return (PCAP_ERROR);
+               }
+
+               if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) {
+                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                           "BIOCGDLTLIST: %s", pcap_strerror(errno));
+                       free(bdlp->bfl_list);
+                       return (PCAP_ERROR);
+               }
+
+               /*
+                * OK, for real Ethernet devices, add DLT_DOCSIS to the
+                * list, so that an application can let you choose it,
+                * in case you're capturing DOCSIS traffic that a Cisco
+                * Cable Modem Termination System is putting out onto
+                * an Ethernet (it doesn't put an Ethernet header onto
+                * the wire, it puts raw DOCSIS frames out on the wire
+                * inside the low-level Ethernet framing).
+                *
+                * A "real Ethernet device" is defined here as a device
+                * that has a link-layer type of DLT_EN10MB and that has
+                * no alternate link-layer types; that's done to exclude
+                * 802.11 interfaces (which might or might not be the
+                * right thing to do, but I suspect it is - Ethernet <->
+                * 802.11 bridges would probably badly mishandle frames
+                * that don't have Ethernet headers).
+                */
+               if (v == DLT_EN10MB) {
+                       is_ethernet = 1;
+                       for (i = 0; i < bdlp->bfl_len; i++) {
+                               if (bdlp->bfl_list[i] != DLT_EN10MB) {
+                                       is_ethernet = 0;
+                                       break;
+                               }
+                       }
+                       if (is_ethernet) {
+                               /*
+                                * We reserved one more slot at the end of
+                                * the list.
+                                */
+                               bdlp->bfl_list[bdlp->bfl_len] = DLT_DOCSIS;
+                               bdlp->bfl_len++;
+                       }
+               }
+       } else {
+               /*
+                * EINVAL just means "we don't support this ioctl on
+                * this device"; don't treat it as an error.
+                */
+               if (errno != EINVAL) {
+                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                           "BIOCGDLTLIST: %s", pcap_strerror(errno));
+                       return (PCAP_ERROR);
+               }
+       }
+       return (0);
+}
+#endif
+
+static int
+pcap_can_set_rfmon_bpf(pcap_t *p)
+{
+#if defined(__APPLE__)
+       struct utsname osinfo;
+       struct ifreq ifr;
+       int fd;
+#ifdef BIOCGDLTLIST
+       struct bpf_dltlist bdl;
+#endif
+
+       /*
+        * The joys of monitor mode on OS X.
+        *
+        * Prior to 10.4, it's not supported at all.
+        *
+        * In 10.4, if adapter enN supports monitor mode, there's a
+        * wltN adapter corresponding to it; you open it, instead of
+        * enN, to get monitor mode.  You get whatever link-layer
+        * headers it supplies.
+        *
+        * In 10.5, and, we assume, later releases, if adapter enN
+        * supports monitor mode, it offers, among its selectable
+        * DLT_ values, values that let you get the 802.11 header;
+        * selecting one of those values puts the adapter into monitor
+        * mode (i.e., you can't get 802.11 headers except in monitor
+        * mode, and you can't get Ethernet headers in monitor mode).
+        */
+       if (uname(&osinfo) == -1) {
+               /*
+                * Can't get the OS version; just say "no".
+                */
+               return (0);
+       }
+       /*
+        * We assume osinfo.sysname is "Darwin", because
+        * __APPLE__ is defined.  We just check the version.
+        */
+       if (osinfo.release[0] < '8' && osinfo.release[1] == '.') {
+               /*
+                * 10.3 (Darwin 7.x) or earlier.
+                * Monitor mode not supported.
+                */
+               return (0);
+       }
+       if (osinfo.release[0] == '8' && osinfo.release[1] == '.') {
+               /*
+                * 10.4 (Darwin 8.x).  s/en/wlt/, and check
+                * whether the device exists.
+                */
+               if (strncmp(p->opt.source, "en", 2) != 0) {
+                       /*
+                        * Not an enN device; no monitor mode.
+                        */
+                       return (0);
+               }
+               fd = socket(AF_INET, SOCK_DGRAM, 0);
+               if (fd == -1) {
+                       (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "socket: %s", pcap_strerror(errno));
+                       return (PCAP_ERROR);
+               }
+               strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name));
+               strlcat(ifr.ifr_name, p->opt.source + 2, sizeof(ifr.ifr_name));
+               if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+                       /*
+                        * No such device?
+                        */
+                       close(fd);
+                       return (0);
+               }
+               close(fd);
+               return (1);
+       }
+
+#ifdef BIOCGDLTLIST
+       /*
+        * Everything else is 10.5 or later; for those,
+        * we just open the enN device, and check whether
+        * we have any 802.11 devices.
+        *
+        * First, open a BPF device.
+        */
+       fd = bpf_open(p);
+       if (fd < 0)
+               return (fd);
+
+       /*
+        * Now bind to the device.
+        */
+       (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name));
+       if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+               if (errno == ENETDOWN) {
+                       /*
+                        * Return a "network down" indication, so that
+                        * the application can report that rather than
+                        * saying we had a mysterious failure and
+                        * suggest that they report a problem to the
+                        * libpcap developers.
+                        */
+                       close(fd);
+                       return (PCAP_ERROR_IFACE_NOT_UP);
+               } else {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "BIOCSETIF: %s: %s",
+                           p->opt.source, pcap_strerror(errno));
+                       close(fd);
+                       return (PCAP_ERROR);
+               }
+       }
+
+       /*
+        * We know the default link type -- now determine all the DLTs
+        * this interface supports.  If this fails with EINVAL, it's
+        * not fatal; we just don't get to use the feature later.
+        * (We don't care about DLT_DOCSIS, so we pass DLT_NULL
+        * as the default DLT for this adapter.)
+        */
+       if (get_dlt_list(fd, DLT_NULL, &bdl, p->errbuf) == PCAP_ERROR) {
+               close(fd);
+               return (PCAP_ERROR);
+       }
+       if (find_802_11(&bdl) != -1) {
+               /*
+                * We have an 802.11 DLT, so we can set monitor mode.
+                */
+               free(bdl.bfl_list);
+               close(fd);
+               return (1);
+       }
+       free(bdl.bfl_list);
+#endif /* BIOCGDLTLIST */
+       return (0);
+#elif defined(HAVE_BSD_IEEE80211)
+       int ret;
+
+       ret = monitor_mode(p, 0);
+       if (ret == PCAP_ERROR_RFMON_NOTSUP)
+               return (0);     /* not an error, just a "can't do" */
+       if (ret == 0)
+               return (1);     /* success */
+       return (ret);
+#else
+       return (0);
+#endif
+}
+
 static int
 pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps)
 {
@@ -129,7 +707,7 @@ pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps)
        if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
                snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s",
                    pcap_strerror(errno));
-               return (-1);
+               return (PCAP_ERROR);
        }
 
        ps->ps_recv = s.bs_recv;
@@ -144,12 +722,13 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
        int n = 0;
        register u_char *bp, *ep;
        u_char *datap;
-       struct bpf_insn *fcode;
 #ifdef PCAP_FDDIPAD
        register int pad;
 #endif
+#ifdef HAVE_ZEROCOPY_BPF
+       int i;
+#endif
 
-       fcode = p->md.use_bpf ? NULL : p->fcode.bf_insns;
  again:
        /*
         * Has "pcap_breakloop()" been called?
@@ -157,15 +736,36 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
        if (p->break_loop) {
                /*
                 * Yes - clear the flag that indicates that it
-                * has, and return -2 to indicate that we were
-                * told to break out of the loop.
+                * has, and return PCAP_ERROR_BREAK to indicate
+                * that we were told to break out of the loop.
                 */
                p->break_loop = 0;
-               return (-2);
+               return (PCAP_ERROR_BREAK);
        }
        cc = p->cc;
        if (p->cc == 0) {
-               cc = read(p->fd, (char *)p->buffer, p->bufsize);
+               /*
+                * When reading without zero-copy from a file descriptor, we
+                * use a single buffer and return a length of data in the
+                * buffer.  With zero-copy, we update the p->buffer pointer
+                * to point at whatever underlying buffer contains the next
+                * data and update cc to reflect the data found in the
+                * buffer.
+                */
+#ifdef HAVE_ZEROCOPY_BPF
+               if (p->md.zerocopy) {
+                       if (p->buffer != NULL)
+                               pcap_ack_zbuf(p);
+                       i = pcap_next_zbuf(p, &cc);
+                       if (i == 0)
+                               goto again;
+                       if (i < 0)
+                               return (PCAP_ERROR);
+               } else
+#endif
+               {
+                       cc = read(p->fd, (char *)p->buffer, p->bufsize);
+               }
                if (cc < 0) {
                        /* Don't choke when we get ptraced */
                        switch (errno) {
@@ -180,16 +780,16 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                                 *
                                 * For some unknown reason the uiomove()
                                 * operation in the bpf kernel extension
-                                * used to copy the buffer into user 
+                                * used to copy the buffer into user
                                 * space sometimes returns EFAULT. I have
                                 * no idea why this is the case given that
-                                * a kernel debugger shows the user buffer 
-                                * is correct. This problem appears to 
-                                * be mostly mitigated by the memset of 
-                                * the buffer before it is first used. 
+                                * a kernel debugger shows the user buffer
+                                * is correct. This problem appears to
+                                * be mostly mitigated by the memset of
+                                * the buffer before it is first used.
                                 * Very strange.... Shaun Clowes
                                 *
-                                * In any case this means that we shouldn't 
+                                * In any case this means that we shouldn't
                                 * treat EFAULT as a fatal error; as we
                                 * don't have an API for returning
                                 * a "some packets were dropped since
@@ -197,8 +797,8 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                                 * we just ignore EFAULT and keep reading.
                                 */
                                goto again;
-#endif 
-  
+#endif
+
                        case EWOULDBLOCK:
                                return (0);
 #if defined(sun) && !defined(BSD)
@@ -218,7 +818,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                        }
                        snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s",
                            pcap_strerror(errno));
-                       return (-1);
+                       return (PCAP_ERROR);
                }
                bp = p->buffer;
        } else
@@ -238,16 +838,17 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                /*
                 * Has "pcap_breakloop()" been called?
                 * If so, return immediately - if we haven't read any
-                * packets, clear the flag and return -2 to indicate
-                * that we were told to break out of the loop, otherwise
-                * leave the flag set, so that the *next* call will break
-                * out of the loop without having read any packets, and
-                * return the number of packets we've processed so far.
+                * packets, clear the flag and return PCAP_ERROR_BREAK
+                * to indicate that we were told to break out of the loop,
+                * otherwise leave the flag set, so that the *next* call
+                * will break out of the loop without having read any
+                * packets, and return the number of packets we've
+                * processed so far.
                 */
                if (p->break_loop) {
                        if (n == 0) {
                                p->break_loop = 0;
-                               return (-2);
+                               return (PCAP_ERROR_BREAK);
                        } else {
                                p->bp = bp;
                                p->cc = ep - bp;
@@ -260,7 +861,8 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                datap = bp + hdrlen;
                /*
                 * Short-circuit evaluation: if using BPF filter
-                * in kernel, no need to do it now.
+                * in kernel, no need to do it now - we already know
+                * the packet passed the filter.
                 *
 #ifdef PCAP_FDDIPAD
                 * Note: the filter code was generated assuming
@@ -270,8 +872,8 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                 * skipping that padding.
 #endif
                 */
-               if (fcode == NULL ||
-                   bpf_filter(fcode, datap, bhp->bh_datalen, caplen)) {
+               if (p->md.use_bpf ||
+                   bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
                        struct pcap_pkthdr pkthdr;
 
                        pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec;
@@ -349,7 +951,7 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
                        (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                            "send: can't turn off BIOCSHDRCMPLT: %s",
                            pcap_strerror(errno));
-                       return (-1);
+                       return (PCAP_ERROR);
                }
 
                /*
@@ -361,13 +963,13 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
        if (ret == -1) {
                snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
                    pcap_strerror(errno));
-               return (-1);
+               return (PCAP_ERROR);
        }
        return (ret);
 }
 
 #ifdef _AIX
-static int 
+static int
 bpf_odminit(char *errbuf)
 {
        char *errstr;
@@ -378,7 +980,7 @@ bpf_odminit(char *errbuf)
                snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "bpf_load: odm_initialize failed: %s",
                    errstr);
-               return (-1);
+               return (PCAP_ERROR);
        }
 
        if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) {
@@ -387,13 +989,13 @@ bpf_odminit(char *errbuf)
                snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s",
                    errstr);
-               return (-1);
+               return (PCAP_ERROR);
        }
 
        return (0);
 }
 
-static int 
+static int
 bpf_odmcleanup(char *errbuf)
 {
        char *errstr;
@@ -404,7 +1006,7 @@ bpf_odmcleanup(char *errbuf)
                snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "bpf_load: odm_unlock failed: %s",
                    errstr);
-               return (-1);
+               return (PCAP_ERROR);
        }
 
        if (odm_terminate() == -1) {
@@ -413,7 +1015,7 @@ bpf_odmcleanup(char *errbuf)
                snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "bpf_load: odm_terminate failed: %s",
                    errstr);
-               return (-1);
+               return (PCAP_ERROR);
        }
 
        return (0);
@@ -438,14 +1040,14 @@ bpf_load(char *errbuf)
        if (bpfloadedflag)
                return (0);
 
-       if (bpf_odminit(errbuf) != 0)
-               return (-1);
+       if (bpf_odminit(errbuf) == PCAP_ERROR)
+               return (PCAP_ERROR);
 
        major = genmajor(BPF_NAME);
        if (major == -1) {
                snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "bpf_load: genmajor failed: %s", pcap_strerror(errno));
-               return (-1);
+               return (PCAP_ERROR);
        }
 
        minors = getminor(major, &numminors, BPF_NAME);
@@ -455,19 +1057,19 @@ bpf_load(char *errbuf)
                        snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "bpf_load: genminor failed: %s",
                            pcap_strerror(errno));
-                       return (-1);
+                       return (PCAP_ERROR);
                }
        }
 
-       if (bpf_odmcleanup(errbuf))
-               return (-1);
+       if (bpf_odmcleanup(errbuf) == PCAP_ERROR)
+               return (PCAP_ERROR);
 
        rc = stat(BPF_NODE "0", &sbuf);
        if (rc == -1 && errno != ENOENT) {
                snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "bpf_load: can't stat %s: %s",
                    BPF_NODE "0", pcap_strerror(errno));
-               return (-1);
+               return (PCAP_ERROR);
        }
 
        if (rc == -1 || getmajor(sbuf.st_rdev) != major) {
@@ -478,7 +1080,7 @@ bpf_load(char *errbuf)
                                snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "bpf_load: can't mknod %s: %s",
                                    buf, pcap_strerror(errno));
-                               return (-1);
+                               return (PCAP_ERROR);
                        }
                }
        }
@@ -494,7 +1096,7 @@ bpf_load(char *errbuf)
                        snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "bpf_load: could not load driver: %s",
                            strerror(errno));
-                       return (-1);
+                       return (PCAP_ERROR);
                }
        }
 
@@ -502,190 +1104,507 @@ bpf_load(char *errbuf)
        cfg_km.cmd = CFG_INIT;
        cfg_km.kmid = cfg_ld.kmid;
        cfg_km.mdilen = sizeof(cfg_bpf);
-       cfg_km.mdiptr = (void *)&cfg_bpf; 
+       cfg_km.mdiptr = (void *)&cfg_bpf;
        for (i = 0; i < BPF_MINORS; i++) {
                cfg_bpf.devno = domakedev(major, i);
                if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) {
                        snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "bpf_load: could not configure driver: %s",
                            strerror(errno));
-                       return (-1);
+                       return (PCAP_ERROR);
                }
        }
-       
+
        bpfloadedflag = 1;
 
        return (0);
 }
 #endif
 
-static inline int
-bpf_open(pcap_t *p, char *errbuf)
+/*
+ * Turn off rfmon mode if necessary.
+ */
+static void
+pcap_cleanup_bpf(pcap_t *p)
 {
-       int fd;
-#ifdef HAVE_CLONING_BPF
-       static const char device[] = "/dev/bpf";
-#else
-       int n = 0;
-       char device[sizeof "/dev/bpf0000000000"];
+#ifdef HAVE_BSD_IEEE80211
+       int sock;
+       struct ifmediareq req;
+       struct ifreq ifr;
 #endif
 
-#ifdef _AIX
-       /*
-        * Load the bpf driver, if it isn't already loaded,
-        * and create the BPF device entries, if they don't
-        * already exist.
-        */
-       if (bpf_load(errbuf) == -1)
-               return (-1);
-#endif
+       if (p->md.must_clear != 0) {
+               /*
+                * There's something we have to do when closing this
+                * pcap_t.
+                */
+#ifdef HAVE_BSD_IEEE80211
+               if (p->md.must_clear & MUST_CLEAR_RFMON) {
+                       /*
+                        * We put the interface into rfmon mode;
+                        * take it out of rfmon mode.
+                        *
+                        * XXX - if somebody else wants it in rfmon
+                        * mode, this code cannot know that, so it'll take
+                        * it out of rfmon mode.
+                        */
+                       sock = socket(AF_INET, SOCK_DGRAM, 0);
+                       if (sock == -1) {
+                               fprintf(stderr,
+                                   "Can't restore interface flags (socket() failed: %s).\n"
+                                   "Please adjust manually.\n",
+                                   strerror(errno));
+                       } else {
+                               memset(&req, 0, sizeof(req));
+                               strncpy(req.ifm_name, p->md.device,
+                                   sizeof(req.ifm_name));
+                               if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+                                       fprintf(stderr,
+                                           "Can't restore interface flags (SIOCGIFMEDIA failed: %s).\n"
+                                           "Please adjust manually.\n",
+                                           strerror(errno));
+                               } else {
+                                       if (req.ifm_current & IFM_IEEE80211_MONITOR) {
+                                               /*
+                                                * Rfmon mode is currently on;
+                                                * turn it off.
+                                                */
+                                               memset(&ifr, 0, sizeof(ifr));
+                                               (void)strncpy(ifr.ifr_name,
+                                                   p->md.device,
+                                                   sizeof(ifr.ifr_name));
+                                               ifr.ifr_media =
+                                                   req.ifm_current & ~IFM_IEEE80211_MONITOR;
+                                               if (ioctl(sock, SIOCSIFMEDIA,
+                                                   &ifr) == -1) {
+                                                       fprintf(stderr,
+                                                           "Can't restore interface flags (SIOCSIFMEDIA failed: %s).\n"
+                                                           "Please adjust manually.\n",
+                                                           strerror(errno));
+                                               }
+                                       }
+                               }
+                               close(sock);
+                       }
+               }
+#endif /* HAVE_BSD_IEEE80211 */
 
-#ifdef HAVE_CLONING_BPF
-       if ((fd = open(device, O_RDWR)) == -1 &&
-           (errno != EACCES || (fd = open(device, O_RDONLY)) == -1))
-               snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                 "(cannot open device) %s: %s", device, pcap_strerror(errno));
-#else
-       /*
-        * Go through all the minors and find one that isn't in use.
-        */
-       do {
-               (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
                /*
-                * Initially try a read/write open (to allow the inject
-                * method to work).  If that fails due to permission
-                * issues, fall back to read-only.  This allows a
-                * non-root user to be granted specific access to pcap
-                * capabilities via file permissions.
-                *
-                * XXX - we should have an API that has a flag that
-                * controls whether to open read-only or read-write,
-                * so that denial of permission to send (or inability
-                * to send, if sending packets isn't supported on
-                * the device in question) can be indicated at open
-                * time.
+                * Take this pcap out of the list of pcaps for which we
+                * have to take the interface out of some mode.
                 */
-               fd = open(device, O_RDWR);
-               if (fd == -1 && errno == EACCES)
-                       fd = open(device, O_RDONLY);
-       } while (fd < 0 && errno == EBUSY);
+               pcap_remove_from_pcaps_to_close(p);
+               p->md.must_clear = 0;
+       }
 
+#ifdef HAVE_ZEROCOPY_BPF
        /*
-        * XXX better message for all minors used
+        * In zero-copy mode, p->buffer is just a pointer into one of the two
+        * memory-mapped buffers, so no need to free it.
         */
-       if (fd < 0)
-               snprintf(errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
-                   device, pcap_strerror(errno));
+       if (p->md.zerocopy) {
+               if (p->md.zbuf1 != MAP_FAILED && p->md.zbuf1 != NULL)
+                       munmap(p->md.zbuf1, p->md.zbufsize);
+               if (p->md.zbuf2 != MAP_FAILED && p->md.zbuf2 != NULL)
+                       munmap(p->md.zbuf2, p->md.zbufsize);
+       }
 #endif
-
-       return (fd);
+       if (p->md.device != NULL) {
+               free(p->md.device);
+               p->md.device = NULL;
+       }
+       pcap_cleanup_live_common(p);
 }
 
-/*
- * We include the OS's <net/bpf.h>, not our "pcap-bpf.h", so we probably
- * don't get DLT_DOCSIS defined.
- */
-#ifndef DLT_DOCSIS
-#define DLT_DOCSIS     143
+static int
+check_setif_failure(pcap_t *p, int error)
+{
+#ifdef __APPLE__
+       int fd;
+       struct ifreq ifr;
+       int err;
 #endif
 
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+       if (error == ENXIO) {
+               /*
+                * No such device exists.
+                */
+#ifdef __APPLE__
+               if (p->opt.rfmon && strncmp(p->opt.source, "wlt", 3) == 0) {
+                       /*
+                        * Monitor mode was requested, and we're trying
+                        * to open a "wltN" device.  Assume that this
+                        * is 10.4 and that we were asked to open an
+                        * "enN" device; if that device exists, return
+                        * "monitor mode not supported on the device".
+                        */
+                       fd = socket(AF_INET, SOCK_DGRAM, 0);
+                       if (fd != -1) {
+                               strlcpy(ifr.ifr_name, "en",
+                                   sizeof(ifr.ifr_name));
+                               strlcat(ifr.ifr_name, p->opt.source + 3,
+                                   sizeof(ifr.ifr_name));
+                               if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+                                       /*
+                                        * We assume this failed because
+                                        * the underlying device doesn't
+                                        * exist.
+                                        */
+                                       err = PCAP_ERROR_NO_SUCH_DEVICE;
+                                       strcpy(p->errbuf, "");
+                               } else {
+                                       /*
+                                        * The underlying "enN" device
+                                        * exists, but there's no
+                                        * corresponding "wltN" device;
+                                        * that means that the "enN"
+                                        * device doesn't support
+                                        * monitor mode, probably because
+                                        * it's an Ethernet device rather
+                                        * than a wireless device.
+                                        */
+                                       err = PCAP_ERROR_RFMON_NOTSUP;
+                               }
+                               close(fd);
+                       } else {
+                               /*
+                                * We can't find out whether there's
+                                * an underlying "enN" device, so
+                                * just report "no such device".
+                                */
+                               err = PCAP_ERROR_NO_SUCH_DEVICE;
+                               strcpy(p->errbuf, "");
+                       }
+                       return (err);
+               }
+#endif
+               /*
+                * No such device.
+                */
+               strcpy(p->errbuf, "");
+               return (PCAP_ERROR_NO_SUCH_DEVICE);
+       } else if (errno == ENETDOWN) {
+               /*
+                * Return a "network down" indication, so that
+                * the application can report that rather than
+                * saying we had a mysterious failure and
+                * suggest that they report a problem to the
+                * libpcap developers.
+                */
+               return (PCAP_ERROR_IFACE_NOT_UP);
+       } else {
+               /*
+                * Some other error; fill in the error string, and
+                * return PCAP_ERROR.
+                */
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
+                   p->opt.source, pcap_strerror(errno));
+               return (PCAP_ERROR);
+       }
+}
+
+static int
+pcap_activate_bpf(pcap_t *p)
 {
+       int status = 0;
        int fd;
        struct ifreq ifr;
        struct bpf_version bv;
+#ifdef __APPLE__
+       int sockfd;
+       char *wltdev = NULL;
+#endif
 #ifdef BIOCGDLTLIST
        struct bpf_dltlist bdl;
+#if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)
+       int new_dlt;
 #endif
+#endif /* BIOCGDLTLIST */
 #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
        u_int spoof_eth_src = 1;
 #endif
        u_int v;
-       pcap_t *p;
        struct bpf_insn total_insn;
        struct bpf_program total_prog;
        struct utsname osinfo;
+       int have_osinfo = 0;
+#ifdef HAVE_ZEROCOPY_BPF
+       struct bpf_zbuf bz;
+       u_int bufmode, zbufmax;
+#endif
 
-#ifdef HAVE_DAG_API
-       if (strstr(device, "dag")) {
-               return dag_open_live(device, snaplen, promisc, to_ms, ebuf);
+       fd = bpf_open(p);
+       if (fd < 0) {
+               status = fd;
+               goto bad;
        }
-#endif /* HAVE_DAG_API */
 
-#ifdef BIOCGDLTLIST
-       memset(&bdl, 0, sizeof(bdl));
-#endif
+       p->fd = fd;
 
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+       if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
                    pcap_strerror(errno));
-               return (NULL);
+               status = PCAP_ERROR;
+               goto bad;
        }
-       memset(p, 0, sizeof(*p));
-       fd = bpf_open(p, ebuf);
-       if (fd < 0)
+       if (bv.bv_major != BPF_MAJOR_VERSION ||
+           bv.bv_minor < BPF_MINOR_VERSION) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "kernel bpf filter out of date");
+               status = PCAP_ERROR;
+               goto bad;
+       }
+
+       p->md.device = strdup(p->opt.source);
+       if (p->md.device == NULL) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s",
+                    pcap_strerror(errno));
+               status = PCAP_ERROR;
                goto bad;
+       }
 
-       p->fd = fd;
-       p->snapshot = snaplen;
+       /*
+        * Attempt to find out the version of the OS on which we're running.
+        */
+       if (uname(&osinfo) == 0)
+               have_osinfo = 1;
+
+#ifdef __APPLE__
+       /*
+        * See comment in pcap_can_set_rfmon_bpf() for an explanation
+        * of why we check the version number.
+        */
+       if (p->opt.rfmon) {
+               if (have_osinfo) {
+                       /*
+                        * We assume osinfo.sysname is "Darwin", because
+                        * __APPLE__ is defined.  We just check the version.
+                        */
+                       if (osinfo.release[0] < '8' &&
+                           osinfo.release[1] == '.') {
+                               /*
+                                * 10.3 (Darwin 7.x) or earlier.
+                                */
+                               status = PCAP_ERROR_RFMON_NOTSUP;
+                               goto bad;
+                       }
+                       if (osinfo.release[0] == '8' &&
+                           osinfo.release[1] == '.') {
+                               /*
+                                * 10.4 (Darwin 8.x).  s/en/wlt/
+                                */
+                               if (strncmp(p->opt.source, "en", 2) != 0) {
+                                       /*
+                                        * Not an enN device; check
+                                        * whether the device even exists.
+                                        */
+                                       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+                                       if (sockfd != -1) {
+                                               strlcpy(ifr.ifr_name,
+                                                   p->opt.source,
+                                                   sizeof(ifr.ifr_name));
+                                               if (ioctl(sockfd, SIOCGIFFLAGS,
+                                                   (char *)&ifr) < 0) {
+                                                       /*
+                                                        * We assume this
+                                                        * failed because
+                                                        * the underlying
+                                                        * device doesn't
+                                                        * exist.
+                                                        */
+                                                       status = PCAP_ERROR_NO_SUCH_DEVICE;
+                                                       strcpy(p->errbuf, "");
+                                               } else
+                                                       status = PCAP_ERROR_RFMON_NOTSUP;
+                                               close(sockfd);
+                                       } else {
+                                               /*
+                                                * We can't find out whether
+                                                * the device exists, so just
+                                                * report "no such device".
+                                                */
+                                               status = PCAP_ERROR_NO_SUCH_DEVICE;
+                                               strcpy(p->errbuf, "");
+                                       }
+                                       goto bad;
+                               }
+                               wltdev = malloc(strlen(p->opt.source) + 2);
+                               if (wltdev == NULL) {
+                                       (void)snprintf(p->errbuf,
+                                           PCAP_ERRBUF_SIZE, "malloc: %s",
+                                           pcap_strerror(errno));
+                                       status = PCAP_ERROR;
+                                       goto bad;
+                               }
+                               strcpy(wltdev, "wlt");
+                               strcat(wltdev, p->opt.source + 2);
+                               free(p->opt.source);
+                               p->opt.source = wltdev;
+                       }
+                       /*
+                        * Everything else is 10.5 or later; for those,
+                        * we just open the enN device, and set the DLT.
+                        */
+               }
+       }
+#endif /* __APPLE__ */
+#ifdef HAVE_ZEROCOPY_BPF
+       /*
+        * If the BPF extension to set buffer mode is present, try setting
+        * the mode to zero-copy.  If that fails, use regular buffering.  If
+        * it succeeds but other setup fails, return an error to the user.
+        */
+       bufmode = BPF_BUFMODE_ZBUF;
+       if (ioctl(fd, BIOCSETBUFMODE, (caddr_t)&bufmode) == 0) {
+               /*
+                * We have zerocopy BPF; use it.
+                */
+               p->md.zerocopy = 1;
+
+               /*
+                * Set the cleanup and set/get nonblocking mode ops
+                * as appropriate for zero-copy mode.
+                */
+               p->cleanup_op = pcap_cleanup_zbuf;
+               p->setnonblock_op = pcap_setnonblock_zbuf;
+               p->getnonblock_op = pcap_getnonblock_zbuf;
+
+               /*
+                * How to pick a buffer size: first, query the maximum buffer
+                * size supported by zero-copy.  This also lets us quickly
+                * determine whether the kernel generally supports zero-copy.
+                * Then, if a buffer size was specified, use that, otherwise
+                * query the default buffer size, which reflects kernel
+                * policy for a desired default.  Round to the nearest page
+                * size.
+                */
+               if (ioctl(fd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGETZMAX: %s",
+                           pcap_strerror(errno));
+                       goto bad;
+               }
+
+               if (p->opt.buffer_size != 0) {
+                       /*
+                        * A buffer size was explicitly specified; use it.
+                        */
+                       v = p->opt.buffer_size;
+               } else {
+                       if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) ||
+                           v < 32768)
+                               v = 32768;
+               }
+#ifndef roundup
+#define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))  /* to any y */
+#endif
+               p->md.zbufsize = roundup(v, getpagesize());
+               if (p->md.zbufsize > zbufmax)
+                       p->md.zbufsize = zbufmax;
+               p->md.zbuf1 = mmap(NULL, p->md.zbufsize, PROT_READ | PROT_WRITE,
+                   MAP_ANON, -1, 0);
+               p->md.zbuf2 = mmap(NULL, p->md.zbufsize, PROT_READ | PROT_WRITE,
+                   MAP_ANON, -1, 0);
+               if (p->md.zbuf1 == MAP_FAILED || p->md.zbuf2 == MAP_FAILED) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "mmap: %s",
+                           pcap_strerror(errno));
+                       goto bad;
+               }
+               bzero(&bz, sizeof(bz));
+               bz.bz_bufa = p->md.zbuf1;
+               bz.bz_bufb = p->md.zbuf2;
+               bz.bz_buflen = p->md.zbufsize;
+               if (ioctl(fd, BIOCSETZBUF, (caddr_t)&bz) < 0) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETZBUF: %s",
+                           pcap_strerror(errno));
+                       goto bad;
+               }
+               (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name));
+               if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
+                           p->opt.source, pcap_strerror(errno));
+                       goto bad;
+               }
+               v = p->md.zbufsize - sizeof(struct bpf_zbuf_header);
+       } else
+#endif
+       {
+               /*
+                * We don't have zerocopy BPF.
+                * Set the buffer size.
+                */
+               if (p->opt.buffer_size != 0) {
+                       /*
+                        * A buffer size was explicitly specified; use it.
+                        */
+                       if (ioctl(fd, BIOCSBLEN,
+                           (caddr_t)&p->opt.buffer_size) < 0) {
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                                   "BIOCSBLEN: %s: %s", p->opt.source,
+                                   pcap_strerror(errno));
+                               status = PCAP_ERROR;
+                               goto bad;
+                       }
 
-       if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
-                   pcap_strerror(errno));
-               goto bad;
-       }
-       if (bv.bv_major != BPF_MAJOR_VERSION ||
-           bv.bv_minor < BPF_MINOR_VERSION) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                   "kernel bpf filter out of date");
-               goto bad;
-       }
+                       /*
+                        * Now bind to the device.
+                        */
+                       (void)strncpy(ifr.ifr_name, p->opt.source,
+                           sizeof(ifr.ifr_name));
+                       if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+                               status = check_setif_failure(p, errno);
+                               goto bad;
+                       }
+               } else {
+                       /*
+                        * No buffer size was explicitly specified.
+                        *
+                        * Try finding a good size for the buffer; 32768 may
+                        * be too big, so keep cutting it in half until we
+                        * find a size that works, or run out of sizes to try.
+                        * If the default is larger, don't make it smaller.
+                        */
+                       if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) ||
+                           v < 32768)
+                               v = 32768;
+                       for ( ; v != 0; v >>= 1) {
+                               /*
+                                * Ignore the return value - this is because the
+                                * call fails on BPF systems that don't have
+                                * kernel malloc.  And if the call fails, it's
+                                * no big deal, we just continue to use the
+                                * standard buffer size.
+                                */
+                               (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
 
-       /*
-        * Try finding a good size for the buffer; 32768 may be too
-        * big, so keep cutting it in half until we find a size
-        * that works, or run out of sizes to try.  If the default
-        * is larger, don't make it smaller.
-        *
-        * XXX - there should be a user-accessible hook to set the
-        * initial buffer size.
-        */
-       if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
-               v = 32768;
-       for ( ; v != 0; v >>= 1) {
-               /* Ignore the return value - this is because the call fails
-                * on BPF systems that don't have kernel malloc.  And if
-                * the call fails, it's no big deal, we just continue to
-                * use the standard buffer size.
-                */
-               (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
+                               (void)strncpy(ifr.ifr_name, p->opt.source,
+                                   sizeof(ifr.ifr_name));
+                               if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
+                                       break;  /* that size worked; we're done */
 
-               (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
-               if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
-                       break;  /* that size worked; we're done */
+                               if (errno != ENOBUFS) {
+                                       status = check_setif_failure(p, errno);
+                                       goto bad;
+                               }
+                       }
 
-               if (errno != ENOBUFS) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
-                           device, pcap_strerror(errno));
-                       goto bad;
+                       if (v == 0) {
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                                   "BIOCSBLEN: %s: No buffer size worked",
+                                   p->opt.source);
+                               status = PCAP_ERROR;
+                               goto bad;
+                       }
                }
        }
 
-       if (v == 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                        "BIOCSBLEN: %s: No buffer size worked", device);
-               goto bad;
-       }
-
        /* Get the data link layer type. */
        if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
                    pcap_strerror(errno));
+               status = PCAP_ERROR;
                goto bad;
        }
+
 #ifdef _AIX
        /*
         * AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT.
@@ -713,8 +1632,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                /*
                 * We don't know what to map this to yet.
                 */
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
                    v);
+               status = PCAP_ERROR;
                goto bad;
        }
 #endif
@@ -739,13 +1659,6 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                break;
        }
 #endif
-#ifdef PCAP_FDDIPAD
-       if (v == DLT_FDDI)
-               p->fddipad = PCAP_FDDIPAD;
-       else
-               p->fddipad = 0;
-#endif
-       p->linktype = v;
 
 #ifdef BIOCGDLTLIST
        /*
@@ -753,68 +1666,144 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * this interface supports.  If this fails with EINVAL, it's
         * not fatal; we just don't get to use the feature later.
         */
-       if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) {
-               u_int i;
-               int is_ethernet;
+       if (get_dlt_list(fd, v, &bdl, p->errbuf) == -1) {
+               status = PCAP_ERROR;
+               goto bad;
+       }
+       p->dlt_count = bdl.bfl_len;
+       p->dlt_list = bdl.bfl_list;
 
-               bdl.bfl_list = (u_int *) malloc(sizeof(u_int) * (bdl.bfl_len + 1));
-               if (bdl.bfl_list == NULL) {
-                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                           pcap_strerror(errno));
-                       goto bad;
+#ifdef __APPLE__
+       /*
+        * Monitor mode fun, continued.
+        *
+        * For 10.5 and, we're assuming, later releases, as noted above,
+        * 802.1 adapters that support monitor mode offer both DLT_EN10MB,
+        * DLT_IEEE802_11, and possibly some 802.11-plus-radio-information
+        * DLT_ value.  Choosing one of the 802.11 DLT_ values will turn
+        * monitor mode on.
+        *
+        * Therefore, if the user asked for monitor mode, we filter out
+        * the DLT_EN10MB value, as you can't get that in monitor mode,
+        * and, if the user didn't ask for monitor mode, we filter out
+        * the 802.11 DLT_ values, because selecting those will turn
+        * monitor mode on.  Then, for monitor mode, if an 802.11-plus-
+        * radio DLT_ value is offered, we try to select that, otherwise
+        * we try to select DLT_IEEE802_11.
+        */
+       if (have_osinfo) {
+               if (isdigit((unsigned)osinfo.release[0]) &&
+                    (osinfo.release[0] == '9' ||
+                    isdigit((unsigned)osinfo.release[1]))) {
+                       /*
+                        * 10.5 (Darwin 9.x), or later.
+                        */
+                       new_dlt = find_802_11(&bdl);
+                       if (new_dlt != -1) {
+                               /*
+                                * We have at least one 802.11 DLT_ value,
+                                * so this is an 802.11 interface.
+                                * new_dlt is the best of the 802.11
+                                * DLT_ values in the list.
+                                */
+                               if (p->opt.rfmon) {
+                                       /*
+                                        * Our caller wants monitor mode.
+                                        * Purge DLT_EN10MB from the list
+                                        * of link-layer types, as selecting
+                                        * it will keep monitor mode off.
+                                        */
+                                       remove_en(p);
+
+                                       /*
+                                        * If the new mode we want isn't
+                                        * the default mode, attempt to
+                                        * select the new mode.
+                                        */
+                                       if (new_dlt != v) {
+                                               if (ioctl(p->fd, BIOCSDLT,
+                                                   &new_dlt) != -1) {
+                                                       /*
+                                                        * We succeeded;
+                                                        * make this the
+                                                        * new DLT_ value.
+                                                        */
+                                                       v = new_dlt;
+                                               }
+                                       }
+                               } else {
+                                       /*
+                                        * Our caller doesn't want
+                                        * monitor mode.  Unless this
+                                        * is being done by pcap_open_live(),
+                                        * purge the 802.11 link-layer types
+                                        * from the list, as selecting
+                                        * one of them will turn monitor
+                                        * mode on.
+                                        */
+                                       if (!p->oldstyle)
+                                               remove_802_11(p);
+                               }
+                       } else {
+                               if (p->opt.rfmon) {
+                                       /*
+                                        * The caller requested monitor
+                                        * mode, but we have no 802.11
+                                        * link-layer types, so they
+                                        * can't have it.
+                                        */
+                                       status = PCAP_ERROR_RFMON_NOTSUP;
+                                       goto bad;
+                               }
+                       }
                }
-
-               if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) < 0) {
-                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                           "BIOCGDLTLIST: %s", pcap_strerror(errno));
-                       free(bdl.bfl_list);
+       }
+#elif defined(HAVE_BSD_IEEE80211)
+       /*
+        * *BSD with the new 802.11 ioctls.
+        * Do we want monitor mode?
+        */
+       if (p->opt.rfmon) {
+               /*
+                * Try to put the interface into monitor mode.
+                */
+               status = monitor_mode(p, 1);
+               if (status != 0) {
+                       /*
+                        * We failed.
+                        */
                        goto bad;
                }
 
                /*
-                * OK, for real Ethernet devices, add DLT_DOCSIS to the
-                * list, so that an application can let you choose it,
-                * in case you're capturing DOCSIS traffic that a Cisco
-                * Cable Modem Termination System is putting out onto
-                * an Ethernet (it doesn't put an Ethernet