[initial] Pull libpcap tags/libpcap-1.10.1

Bug: 55476, 84480

Change-Id: I1a0e648381a61abaeb2a0320d2d7405dab60b1ab
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..d01e832
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,254 @@
+This file lists people who have contributed to libpcap.
+
+The current maintainers (in alphabetical order):
+    Denis Ovsienko                <denis at ovsienko dot info>
+    Francois-Xavier Le Bail       <devel dot fx dot lebail at orange dot fr>
+    Guy Harris                    <gharris at sonic dot net>
+    Michael Richardson            <mcr at sandelman dot ottawa dot on dot ca>
+
+Additional people who have contributed patches (in alphabetical order):
+    Adrian Budau                  <adbudau at bitdefender dot com>
+    Akos Vandra                   <axos88 at gmail dot com>
+    Alan Bawden                   <Alan at LCS dot MIT dot EDU>
+    Albert Chin                   <china at thewrittenword dot com>
+    Alexander Galanin             <al at galanin dot nnov dot ru>
+    Alexander 'Leo' Bergolth      <Leo dot Bergolth at wu-wien dot ac dot at>
+    Alexey Kuznetsov              <kuznet at ms2 dot inr dot ac dot ru>
+    Alex Smith                    <44322503+MadAlexUK at users dot noreply dot github dot com>
+    Alfredo Alvarez Fernandez     <alfredoalvarezernandez at gmail dot com>
+    Ali Abdulkadir                <autostart dot ini at gmail dot com>
+    Alon Bar-Lev                  <alonbl at sourceforge dot net>
+    Anders Broman                 <anders dot broman at ericsson dot com>
+    Andres Perera                 <andres dot p at zoho dot com>
+    Andrew Brown                  <atatat at atatdot dot net>
+                                  <andy-1 at sourceforge dot net>
+    Ani Sinha                     <ani at aristanetworks dot com>
+    Anthony Kirby                 <Anthony dot Kirby at nominet dot uk>
+    Antti Kantee                  <pooka at netbsd dot org>
+    Arien Vijn                    <arienvijn at sourceforge dot net>
+    Arkadiusz Miskiewicz          <misiek at pld dot org dot pl>
+    Armando L. Caro Jr.           <acaro at mail dot eecis dot udel dot edu>
+    Assar Westerlund              <assar at sics dot se>
+    Atzm Watanabe                 <atzm at atzm dot org>
+    Baptiste Peugnez              <baptiste dot peugnez at cea dot fr>
+    Baruch Siach                  <baruch at tkos dot co dot il>
+    Bill Parker                   <wp02855 at gmail dot com>
+    blazeable                     <blazeable at blazeable dot eu>
+    bleader                       <bleader at ratonland dot org>
+    Brent Cook                    <brent at boundary dot com>
+    Brian Ginsbach                <ginsbach at cray dot com>
+    B. Scott Michel               <scooter dot phd at gmail dot com>
+    Cedric Cellier                <rixed at happyleptic dot org>
+    Charles M. Hannum             <mycroft at netbsd dot org>
+    Chris G. Demetriou            <cgd at netbsd dot org>
+    Chris Lightfoot               <cwrl at users dot sourceforge dot net>
+    Chris Maynard                 <Chris dot Maynard at gtech dot com>
+    Chris Pepper                  <pepper at mail dot reppep dot com>
+    Christian Bell                <csbell at myri dot com>
+    Christian Peron               <csjp at freebsd dot org>
+    Christian Svensson            <blue at cmd dot nu>
+    Christopher K Lee             <christopher dot lee at cspi dot com>
+    Daniel Borkmann               <dborkman at redhat dot com>
+    Daniele Orlandi               <daniele at orlandi dot com>
+    Daniel Lublin                 <daniel at lublin dot se>
+    Daniel Miller                 <dmiller at nmap dot org>
+    Dario Lombardo                <lomato at gmail dot com>
+    Darren Lim                    <darren dot lim at endace dot com>
+    Darren Reed                   <darrenr at sun dot com>
+    Dave Barach                   <dave at barachs dot net>
+    David Clark                   <david dot clark at datasoft dot com>
+    David Kaelbling               <drk at sgi dot com>
+    David Ward                    <david dot ward at ll dot mit dot edu>
+    David Young                   <dyoung at ojctech dot com>
+    Dean Gaudet                   <dean at arctic dot org>
+    dhruv                         <rsrivat at sourceforge dot net>
+    Dmytro Ovdiienko              <dmitriy dot ovdienko at gmail dot com>
+    Don Ebright                   <Don dot Ebright at compuware dot com>
+    Dug Song                      <dugsong at monkey dot org>
+    Dustin Spicuzza               <dustin at virtualroadside dot com>
+    dzejarczech                   <dzejarczech at sourceforge dot net>
+    Edward Sheldrake              <ejs1920 at sourceforge dot net>
+    Eric Anderson                 <anderse at hpl dot hp dot com>
+    Erik de Castro Lopo           <erik dot de dot castro dot lopo at sensorynetworks dot com>
+    Fedor Sakharov                <fedor dot sakharov at gmail dot com>
+    Felix Janda                   <felix dot janda at posteo dot de>
+    Felix Obenhuber               <felix at obenhuber dot de>
+    Florent Drouin                <Florent dot Drouin at alcatel-lucent dot fr>
+    Florian Fainelli              <f dot fainelli at gmail dot com>
+    François Revol                <revol at free dot fr>
+    Franz Schaefer                <schaefer at mond dot at>
+    frederich                     <frederich at sourceforge dot net>
+    Fulko Hew                     <fulko dot hew at gmail dot com>
+    Fumiyuki Shimizu              <fumifumi at abacustech dot jp>
+    Gabor Tatarka                 <gabor dot tatarka at ericsson dot com>
+    Garrett Cooper                <yaberauneya at sourceforge dot net>
+    George Neville-Neil           <gnn at freebsd dot org>
+    Gerald Combs                  <gerald at zing dot org>
+    Gerard Garcia                 <nouboh at gmail dot com>
+    Gianluca Varenni              <gianluca dot varenni at gmail dot com>
+    Gilbert Hoyek                 <gil_hoyek at hotmail dot com>
+    Gisle Vanem                   <gvanem at yahoo dot no>
+    Graeme Hewson                 <ghewson at cix dot compulink dot co dot uk>
+    Gregor Maier                  <gregor at net dot in dot tum dot de>
+    Greg Stark                    <gsstark at mit dot edu>
+    Greg Troxel                   <gdt at ir dot bbn dot com>
+    Guillaume Pelat               <endymion_ at users dot sourceforge dot net>
+    Gustavo Zacarias              <gustavo at zacarias dot com dot ar>
+    Hagen Paul Pfeifer            <hagen at jauu dot net>
+    Henri Doreau                  <hdoreau at sourceforge dot net>
+    Hiroaki KAWAI                 <kawai at stratosphere dot co dot jp>
+    Hyung Sik Yoon                <hsyn at kr dot ibm dot com>
+    Igor Khristophorov            <igor at atdot dot org>
+    Jakub Sitnicki                <jsitnicki at gmail dot com>
+    Jakub Zawadzki                <darkjames at darkjames dot pl>
+    James Ko                      <jck at exegin dot com>
+    Jan-Philip Velders            <jpv at veldersjes dot net>
+    Jason R. Thorpe               <thorpej at netbsd dot org>
+    Javier Achirica               <achirica at ttd dot net>
+    Jean-Louis Charton            <Jean-Louis dot CHARTON at oikialog dot com>
+    Jean Tourrilhes               <jt at hpl dot hp dot com>
+    Jefferson Ogata               <jogata at nodc dot noaa dot gov>
+    Jerome Duval                  <jerome dot duval at gmail dot com>
+    Jesper Dangaard Brouer        <hawk at comx dot dk>
+    Jesper Peterson               <jesper at endace dot com>
+    Jesse Gross                   <jesse at nicira dot com>
+    JHA                           <jon dot anderson at oracle dot com>
+    jingyu yang                   <jingleyang at users dot noreply dot github dot com>
+    Jiri Slaby                    <jirislaby at gmail dot com>
+    João Valverde                 <joao dot valverde at tecnico dot ulisboa dot pt>
+    Joerg Mayer                   <jmayer at loplof dot de>
+    John Bankier                  <jbankier at rainfinity dot com>
+    Jon Lindgren                  <jonl at yubyub dot net>
+    Jon Smirl                     <jonsmirl at gmail dot com>
+    Jorge Boncompte [DTI2]        <jorge at dti2 dot net>
+    jromanr                       <jromanr at hotmail dot com>
+    Juergen Schoenwaelder         <schoenw at ibr dot cs dot tu-bs dot de>
+    Julien Moutinho               <julm at savines dot alpes dot fr dot eu dot org>
+    Jung-uk Kim                   <jkim at FreeBSD dot org>
+    Kazushi Sugyo                 <sugyo at pb dot jp dot nec dot com>
+    Kevin Boulain                 <kevin dot boulain at securactive dot net>
+    Klaus Klein                   <kleink at netbsd dot org>
+    Koryn Grant                   <koryn at endace dot com>
+    Kris Katterjohn               <katterjohn at gmail dot com>
+    Krzysztof Halasa              <khc at pm dot waw dot pl>
+    Lennert Buytenhek             <buytenh at wantstofly dot org>
+    lixiaoyan                     <lixiaoyan at google dot com>
+    Lorenzo Cavallaro             <sullivan at sikurezza dot org>
+    Loris Degioanni               <loris at netgroup-serv dot polito dot it>
+    Love Hörnquist-Åstrand        <lha at stacken dot kth dot se>
+    Luis MartinGarcia             <luis dot mgarc at gmail dot com>
+    lxy                           <391861737 at qq dot com>
+    Maciej W. Rozycki             <macro at ds2 dot pg dot gda dot pl>
+    Mansour Behabadi              <mansour at oxplot dot com>
+    Marcus Felipe Pereira         <marcus at task dot com dot br>
+    Mario J. Rugiero              <mrugiero at gmail dot com>
+    Mark C. Brown                 <mbrown at hp dot com>
+    Mark Johnston                 <markjdb at gmail dot com>
+    Mark Marshall                 <mark dot marshall at omicronenergy dot com>
+    Mark Pizzolato                <List-tcpdump-workers at subscriptions dot pizzolato dot net>
+    Markus Mayer                  <markus_mayer at sourceforge dot net>
+    Martin Husemann               <martin at netbsd dot org>
+    Márton Németh                 <nm127 at freemail dot hu>
+    Matt Eaton                    <agnosticdev at gmail dot com>
+    Matthew Luckie                <mjl at luckie dot org dot nz>
+    Matthias Hannig               <matthias at hannig dot cc>
+    Matwey V. Kornilov            <matwey dot kornilov at gmail dot com>
+    maxice8                       <thinkabit dot ukim at gmail dot com>
+    Max Laier                     <max at love2party dot net>
+    Michal Kubecek                <mkubecek at suse dot cz>
+    Michal Labedzki               <michal dot labedzki at tieto dot com>
+    Michal Sekletar               <msekleta at redhat dot com>
+    Mike Frysinger                <vapier at gmail dot com>
+    Mike Kershaw                  <dragorn at kismetwireless dot net>
+    Mike Wiacek                   <mike at iroot dot net>
+    Milosz Kaniewski              <milosz dot kaniewski at gmail dot com>
+    Miroslav Lichvar              <mlichvar at redhat dot com>
+    Monroe Williams               <monroe at pobox dot com>
+    Myricom Help                  <myri at users dot noreply dot github dot com>
+    Nan Xiao                      <nan at chinadtrace dot org>
+    Nick Kelsey                   <nickk at silicondust dot com>
+    Nicolas Dade                  <ndade at nsd dot dyndns dot org>
+    Niko Delarich                 <niko dot delarich at gmail dot com>
+    N. Leiten                     <nleiten at sourceforge dot net>
+    nnposter                      <nnposter at users dot noreply dot github dot com>
+                                  <nvercamm at sourceforge dot net>
+    Octavian Cerna                <tavy at ylabs dot com>
+    Olaf Kirch                    <okir at caldera dot de>
+    Ollie Wild                    <aaw at users dot sourceforge dot net>
+    Ondřej Hošek                  <ondra dot hosek at gmail dot com>
+    Onno van der Linden           <onno at simplex dot nl>
+    Orgad Shaneh                  <orgad dot shaneh at audiocodes dot com>
+    Ørjan Malde                   <red at foxi dot me>
+    Paolo Abeni                   <pabeni at redhat dot com>
+    Patrick Marie                 <mycroft at virgaria dot org>
+    Patrick McHardy               <kaber at trash not net>
+    Paul Mundt                    <lethal at linux-sh dot org>
+    Pavel Kankovsky               <kan at dcit dot cz>
+    Pawel Brzezinski              <pawel dot brzezinski at harman dot com>
+    Pawel Pokrywka                <publicpp at gmail dot com>
+    Peter Fales                   <peter at fales-lorenz dot net>
+    Peter Jeremy                  <peter dot jeremy at alcatel dot com dot au>
+    Peter Volkov                  <pva at gentoo dot org>
+    Petr Vorel                    <pvorel at suse dot cz>
+    Philippe Antoine              <contact at catenacyber dot fr>
+    Phil Wood                     <cpw at lanl dot gov>
+    Rafal Maszkowski              <rzm at icm dot edu dot pl>
+                                  <rcb-isis at users dot sourceforge dot net>
+    Richard Stearn                <richard at rns-stearn dot demon dot co dot uk>
+    Rick Jones                    <raj at cup dot hp dot com>
+    Robert Edmonds                <stu-42 at sourceforge dot net>
+    Roberto Mariani               <jelot-tcpdump at jelot dot it>
+    Roland Dreier                 <roland at purestorage dot com>
+    Romain Francoise              <rfrancoise at debian dot org>
+    Rongxi Li                     <rongxi dot li at chaitin dot com>
+    Sagun Shakya                  <sagun dot shakya at sun dot com>
+    Scott Barron                  <sb125499 at ohiou dot edu>
+    Scott Gifford                 <sgifford at tir dot com>
+    Scott Mcmillan                <scott dot a dot mcmillan at intel dot com>
+    Sebastian Krahmer             <krahmer at cs dot uni-potsdam dot de>
+    Sebastien Roy                 <Sebastien dot Roy at Sun dot COM>
+    Sepherosa Ziehau              <sepherosa at gmail dot com>
+    Shaun Clowes                  <delius at progsoc dot uts dot edu dot au>
+    solofox                       <wensg100 at sina dot com>
+    Solomon Peachy                <pizza at shaftnet dot org>
+    Stefan Hudson                 <hudson at mbay dot net>
+    Stephen Donnelly              <stephen at endace dot com>
+    Steve Karg                    <skarg at users dot sourceforge dot net>
+    stubbfel                      <stubbfel at gmail dot com>
+    Takashi Yamamoto              <yamt at mwd dot biglobe dot ne dot jp>
+    Tanaka Shin-ya                <zstanaka at archer dot livedoor dot com>
+    Thomas Habets                 <habets at google dot com>
+    Thomas Petazzoni              <thomas dot petazzoni at free-electrons dot com>
+    Tobias Poschwatta             <posch at sourceforge dot net>
+    Tomasz Moń                    <desowin at gmail dot com>
+    Tommy Beadle                  <tbeadle at arbor dot net>
+    Tony Li                       <tli at procket dot com>
+    Torsten Landschoff            <torsten at debian dot org>
+    Tymoteusz Blazejczyk          <tymoteusz dot blazejczyk at intel dot com>
+    Uns Lider                     <unslider at miranda dot org>
+    Uwe Girlich                   <Uwe dot Girlich at philosys dot de>
+    Vitaly Lavrov                 <vel21ripn at gmail dot com>
+    Vivien Didelot                <vivien dot didelot at gmail dot com>
+    Vladimir Gladkov              <vovkos at gmail dot com>
+    Vladimir Marek                <vlmarek at volny dot cz>
+    Walter Schell                 <walterschell at users dot noreply dot github dot com>
+    Wesley Shields                <wxs at FreeBSD dot org>
+    Xianjie Zhang                 <xzhang at cup dot hp dot com>
+    Xin Li                        <delphij at FreeBSD dot org>
+    Xue Jiang Qing                <xuejianqing at star-net dot cn>
+    Yang Luo                      <hsluoyz at qq dot com>
+    Yen Yen Lim
+    Yoann Vandoorselaere          <yoann at prelude-ids dot org>
+    Yogesh Prasad                 <yogesh dot prasad at rockwellcollins dot com>
+    Yvan Vanhullebus              <vanhu at sourceforge dot net>
+
+The original LBL crew:
+    Steve McCanne
+    Craig Leres
+    Van Jacobson
+
+Past maintainers (in alphabetical order):
+    Bill Fenner                   <fenner at research dot att dot com>
+    Fulvio Risso                  <risso at polito dot it>
+    Hannes Gredler                <hannes at gredler dot at>
+    Jun-ichiro itojun Hagino      <itojun at iijlab dot net>		Also see: http://www.wide.ad.jp/itojun-award/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a10474d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+License: BSD
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d89e3bb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,78 @@
+# LIBPCAP 1.x.y by [The Tcpdump Group](https://www.tcpdump.org)
+
+**To report a security issue please send an e-mail to security@tcpdump.org.**
+
+To report bugs and other problems, contribute patches, request a
+feature, provide generic feedback etc please see the
+[guidelines for contributing](CONTRIBUTING.md).
+
+The [documentation directory](doc/) has README files about specific
+operating systems and options.
+
+Anonymous Git is available via:
+
+  https://github.com/the-tcpdump-group/libpcap.git
+
+This directory contains source code for libpcap, a system-independent
+interface for user-level packet capture.  libpcap provides a portable
+framework for low-level network monitoring.  Applications include
+network statistics collection, security monitoring, network debugging,
+etc.  Since almost every system vendor provides a different interface
+for packet capture, and since we've developed several tools that
+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.
+
+```text
+formerly from 	Lawrence Berkeley National Laboratory
+		Network Research Group <libpcap@ee.lbl.gov>
+		ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z
+```
+
+### Support for particular platforms and BPF
+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
+by default.
+
+The libpcap interface supports a filtering mechanism based on the
+architecture in the BSD packet filter.  BPF is described in the 1993
+Winter Usenix paper ``The BSD Packet Filter: A New Architecture for
+User-level Packet Capture''
+([compressed PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.Z),
+[gzipped PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.gz),
+[PDF](https://www.tcpdump.org/papers/bpf-usenix93.pdf)).
+
+Although most packet capture interfaces support in-kernel filtering,
+libpcap utilizes in-kernel filtering only for the BPF interface.
+On systems that don't have BPF, all packets are read into user-space
+and the BPF filters are evaluated in the libpcap library, incurring
+added overhead (especially, for selective filters).  Ideally, libpcap
+would translate BPF filters into a filter program that is compatible
+with the underlying kernel subsystem, but this is not yet implemented.
+
+BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, OpenBSD, DragonFly
+BSD, and macOS; an older, modified and undocumented version is standard
+in AIX.  {DEC OSF/1, Digital UNIX, Tru64 UNIX} uses the packetfilter
+interface but has been extended to accept BPF filters (which libpcap
+utilizes).  Also, you can add BPF filter support to Ultrix using the
+kernel source and/or object patches available
+[here](https://www.tcpdump.org/other/bpfext42.tar.Z).
+
+Linux has a number of BPF based systems, and libpcap does not support
+any of the eBPF mechanisms as yet, although it supports many of the
+memory mapped receive mechanisms.
+See the [Linux-specific README](doc/README.linux) for more information.
+
+### 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, among other platforms.
+
+It sets the soname of the library to `libpcap.so.1`; this is what it
+should be, **NOT** `libpcap.so.1.x` or `libpcap.so.1.x.y` 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.
diff --git a/arcnet.h b/arcnet.h
new file mode 100644
index 0000000..5869098
--- /dev/null
+++ b/arcnet.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp
+ */
+
+/* RFC 1051 */
+#define	ARCTYPE_IP_OLD		240	/* IP protocol */
+#define	ARCTYPE_ARP_OLD		241	/* address resolution protocol */
+
+/* RFC 1201 */
+#define	ARCTYPE_IP		212	/* IP protocol */
+#define	ARCTYPE_ARP		213	/* address resolution protocol */
+#define	ARCTYPE_REVARP		214	/* reverse addr resolution protocol */
+
+#define	ARCTYPE_ATALK		221	/* Appletalk */
+#define	ARCTYPE_BANIAN		247	/* Banyan Vines */
+#define	ARCTYPE_IPX		250	/* Novell IPX */
+
+#define ARCTYPE_INET6		0xc4	/* IPng */
+#define ARCTYPE_DIAGNOSE	0x80	/* as per ANSI/ATA 878.1 */
diff --git a/atmuni31.h b/atmuni31.h
new file mode 100644
index 0000000..7d4f270
--- /dev/null
+++ b/atmuni31.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997 Yen Yen Lim and North Dakota State University
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Yen Yen Lim and
+        North Dakota State University
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Based on UNI3.1 standard by ATM Forum */
+
+/* ATM traffic types based on VPI=0 and (the following VCI */
+#define VCI_PPC			0x05	/* Point-to-point signal msg */
+#define VCI_BCC			0x02	/* Broadcast signal msg */
+#define VCI_OAMF4SC		0x03	/* Segment OAM F4 flow cell */
+#define VCI_OAMF4EC		0x04	/* End-to-end OAM F4 flow cell */
+#define VCI_METAC		0x01	/* Meta signal msg */
+#define VCI_ILMIC		0x10	/* ILMI msg */
+
+/* Q.2931 signalling messages */
+#define CALL_PROCEED		0x02	/* call proceeding */
+#define CONNECT			0x07	/* connect */
+#define CONNECT_ACK		0x0f	/* connect_ack */
+#define SETUP			0x05	/* setup */
+#define RELEASE			0x4d	/* release */
+#define RELEASE_DONE		0x5a	/* release_done */
+#define RESTART			0x46	/* restart */
+#define RESTART_ACK		0x4e	/* restart ack */
+#define STATUS			0x7d	/* status */
+#define STATUS_ENQ		0x75	/* status ack */
+#define ADD_PARTY		0x80	/* add party */
+#define ADD_PARTY_ACK		0x81	/* add party ack */
+#define ADD_PARTY_REJ		0x82	/* add party rej */
+#define DROP_PARTY		0x83	/* drop party */
+#define DROP_PARTY_ACK		0x84	/* drop party ack */
+
+/* Information Element Parameters in the signalling messages */
+#define CAUSE			0x08	/* cause */
+#define ENDPT_REF		0x54	/* endpoint reference */
+#define AAL_PARA		0x58	/* ATM adaptation layer parameters */
+#define TRAFF_DESCRIP		0x59	/* atm traffic descriptors */
+#define CONNECT_ID		0x5a	/* connection identifier */
+#define QOS_PARA		0x5c	/* quality of service parameters */
+#define B_HIGHER		0x5d	/* broadband higher layer information */
+#define B_BEARER		0x5e	/* broadband bearer capability */
+#define B_LOWER			0x5f	/* broadband lower information */
+#define CALLING_PARTY		0x6c	/* calling party number */
+#define CALLED_PARTY		0x70	/* called party nmber */
+
+#define Q2931			0x09
+
+/* Q.2931 signalling general messages format */
+#define PROTO_POS       0	/* offset of protocol discriminator */
+#define CALL_REF_POS    2	/* offset of call reference value */
+#define MSG_TYPE_POS    5	/* offset of message type */
+#define MSG_LEN_POS     7	/* offset of message length */
+#define IE_BEGIN_POS    9	/* offset of first information element */
+
+/* format of signalling messages */
+#define TYPE_POS	0
+#define LEN_POS		2
+#define FIELD_BEGIN_POS 4
diff --git a/bpf_dump.c b/bpf_dump.c
new file mode 100644
index 0000000..a9c9116
--- /dev/null
+++ b/bpf_dump.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1992, 1993, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap.h>
+#include <stdio.h>
+
+#include "optimize.h"
+
+void
+bpf_dump(const struct bpf_program *p, int option)
+{
+	const struct bpf_insn *insn;
+	int i;
+	int n = p->bf_len;
+
+	insn = p->bf_insns;
+	if (option > 2) {
+		printf("%d\n", n);
+		for (i = 0; i < n; ++insn, ++i) {
+			printf("%u %u %u %u\n", insn->code,
+			       insn->jt, insn->jf, insn->k);
+		}
+		return ;
+	}
+	if (option > 1) {
+		for (i = 0; i < n; ++insn, ++i)
+			printf("{ 0x%x, %d, %d, 0x%08x },\n",
+			       insn->code, insn->jt, insn->jf, insn->k);
+		return;
+	}
+	for (i = 0; i < n; ++insn, ++i) {
+#ifdef BDEBUG
+		if (i < NBIDS && bids[i] > 0)
+			printf("[%02d]", bids[i] - 1);
+		else
+			printf(" -- ");
+#endif
+		puts(bpf_image(insn, i));
+	}
+}
diff --git a/bpf_filter.c b/bpf_filter.c
new file mode 100644
index 0000000..8691d0d
--- /dev/null
+++ b/bpf_filter.c
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)bpf.c	7.5 (Berkeley) 7/15/91
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap/pcap-inttypes.h>
+#include "pcap-types.h"
+#include "extract.h"
+#include "diag-control.h"
+
+#define EXTRACT_SHORT	EXTRACT_BE_U_2
+#define EXTRACT_LONG	EXTRACT_BE_U_4
+
+#ifndef _WIN32
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#endif /* _WIN32 */
+
+#include <pcap-int.h>
+
+#include <stdlib.h>
+
+#ifdef __linux__
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+#endif
+
+enum {
+        BPF_S_ANC_NONE,
+        BPF_S_ANC_VLAN_TAG,
+        BPF_S_ANC_VLAN_TAG_PRESENT,
+};
+
+/*
+ * Execute the filter program starting at pc on the packet p
+ * wirelen is the length of the original packet
+ * buflen is the amount of data present
+ * aux_data is auxiliary data, currently used only when interpreting
+ * filters intended for the Linux kernel in cases where the kernel
+ * rejects the filter; it contains VLAN tag information
+ * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0,
+ * in all other cases, p is a pointer to a buffer and buflen is its size.
+ *
+ * Thanks to Ani Sinha <ani@arista.com> for providing initial implementation
+ */
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+u_int
+pcap_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+    u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data)
+#else
+u_int
+pcap_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+    u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data _U_)
+#endif
+{
+	register uint32_t A, X;
+	register bpf_u_int32 k;
+	uint32_t mem[BPF_MEMWORDS];
+
+	if (pc == 0)
+		/*
+		 * No filter means accept all.
+		 */
+		return (u_int)-1;
+	A = 0;
+	X = 0;
+	--pc;
+	for (;;) {
+		++pc;
+		switch (pc->code) {
+
+		default:
+			abort();
+		case BPF_RET|BPF_K:
+			return (u_int)pc->k;
+
+		case BPF_RET|BPF_A:
+			return (u_int)A;
+
+		case BPF_LD|BPF_W|BPF_ABS:
+			k = pc->k;
+			if (k > buflen || sizeof(int32_t) > buflen - k) {
+				return 0;
+			}
+			A = EXTRACT_LONG(&p[k]);
+			continue;
+
+		case BPF_LD|BPF_H|BPF_ABS:
+			k = pc->k;
+			if (k > buflen || sizeof(int16_t) > buflen - k) {
+				return 0;
+			}
+			A = EXTRACT_SHORT(&p[k]);
+			continue;
+
+		case BPF_LD|BPF_B|BPF_ABS:
+			/*
+			 * Yes, we know, this switch doesn't do
+			 * anything unless we're building for
+			 * a Linux kernel with removed VLAN
+			 * tags available as meta-data.
+			 */
+DIAG_OFF_DEFAULT_ONLY_SWITCH
+			switch (pc->k) {
+
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+			case SKF_AD_OFF + SKF_AD_VLAN_TAG:
+				if (!aux_data)
+					return 0;
+				A = aux_data->vlan_tag;
+				break;
+
+			case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT:
+				if (!aux_data)
+					return 0;
+				A = aux_data->vlan_tag_present;
+				break;
+#endif
+			default:
+				k = pc->k;
+				if (k >= buflen) {
+					return 0;
+				}
+				A = p[k];
+				break;
+			}
+DIAG_ON_DEFAULT_ONLY_SWITCH
+			continue;
+
+		case BPF_LD|BPF_W|BPF_LEN:
+			A = wirelen;
+			continue;
+
+		case BPF_LDX|BPF_W|BPF_LEN:
+			X = wirelen;
+			continue;
+
+		case BPF_LD|BPF_W|BPF_IND:
+			k = X + pc->k;
+			if (pc->k > buflen || X > buflen - pc->k ||
+			    sizeof(int32_t) > buflen - k) {
+				return 0;
+			}
+			A = EXTRACT_LONG(&p[k]);
+			continue;
+
+		case BPF_LD|BPF_H|BPF_IND:
+			k = X + pc->k;
+			if (X > buflen || pc->k > buflen - X ||
+			    sizeof(int16_t) > buflen - k) {
+				return 0;
+			}
+			A = EXTRACT_SHORT(&p[k]);
+			continue;
+
+		case BPF_LD|BPF_B|BPF_IND:
+			k = X + pc->k;
+			if (pc->k >= buflen || X >= buflen - pc->k) {
+				return 0;
+			}
+			A = p[k];
+			continue;
+
+		case BPF_LDX|BPF_MSH|BPF_B:
+			k = pc->k;
+			if (k >= buflen) {
+				return 0;
+			}
+			X = (p[pc->k] & 0xf) << 2;
+			continue;
+
+		case BPF_LD|BPF_IMM:
+			A = pc->k;
+			continue;
+
+		case BPF_LDX|BPF_IMM:
+			X = pc->k;
+			continue;
+
+		case BPF_LD|BPF_MEM:
+			A = mem[pc->k];
+			continue;
+
+		case BPF_LDX|BPF_MEM:
+			X = mem[pc->k];
+			continue;
+
+		case BPF_ST:
+			mem[pc->k] = A;
+			continue;
+
+		case BPF_STX:
+			mem[pc->k] = X;
+			continue;
+
+		case BPF_JMP|BPF_JA:
+			/*
+			 * XXX - we currently implement "ip6 protochain"
+			 * with backward jumps, so sign-extend pc->k.
+			 */
+			pc += (bpf_int32)pc->k;
+			continue;
+
+		case BPF_JMP|BPF_JGT|BPF_K:
+			pc += (A > pc->k) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_JMP|BPF_JGE|BPF_K:
+			pc += (A >= pc->k) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_JMP|BPF_JEQ|BPF_K:
+			pc += (A == pc->k) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_JMP|BPF_JSET|BPF_K:
+			pc += (A & pc->k) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_JMP|BPF_JGT|BPF_X:
+			pc += (A > X) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_JMP|BPF_JGE|BPF_X:
+			pc += (A >= X) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_JMP|BPF_JEQ|BPF_X:
+			pc += (A == X) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_JMP|BPF_JSET|BPF_X:
+			pc += (A & X) ? pc->jt : pc->jf;
+			continue;
+
+		case BPF_ALU|BPF_ADD|BPF_X:
+			A += X;
+			continue;
+
+		case BPF_ALU|BPF_SUB|BPF_X:
+			A -= X;
+			continue;
+
+		case BPF_ALU|BPF_MUL|BPF_X:
+			A *= X;
+			continue;
+
+		case BPF_ALU|BPF_DIV|BPF_X:
+			if (X == 0)
+				return 0;
+			A /= X;
+			continue;
+
+		case BPF_ALU|BPF_MOD|BPF_X:
+			if (X == 0)
+				return 0;
+			A %= X;
+			continue;
+
+		case BPF_ALU|BPF_AND|BPF_X:
+			A &= X;
+			continue;
+
+		case BPF_ALU|BPF_OR|BPF_X:
+			A |= X;
+			continue;
+
+		case BPF_ALU|BPF_XOR|BPF_X:
+			A ^= X;
+			continue;
+
+		case BPF_ALU|BPF_LSH|BPF_X:
+			if (X < 32)
+				A <<= X;
+			else
+				A = 0;
+			continue;
+
+		case BPF_ALU|BPF_RSH|BPF_X:
+			if (X < 32)
+				A >>= X;
+			else
+				A = 0;
+			continue;
+
+		case BPF_ALU|BPF_ADD|BPF_K:
+			A += pc->k;
+			continue;
+
+		case BPF_ALU|BPF_SUB|BPF_K:
+			A -= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_MUL|BPF_K:
+			A *= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_DIV|BPF_K:
+			A /= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_MOD|BPF_K:
+			A %= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_AND|BPF_K:
+			A &= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_OR|BPF_K:
+			A |= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_XOR|BPF_K:
+			A ^= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_LSH|BPF_K:
+			A <<= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_RSH|BPF_K:
+			A >>= pc->k;
+			continue;
+
+		case BPF_ALU|BPF_NEG:
+			/*
+			 * Most BPF arithmetic is unsigned, but negation
+			 * can't be unsigned; respecify it as subtracting
+			 * the accumulator from 0U, so that 1) we don't
+			 * get compiler warnings about negating an unsigned
+			 * value and 2) don't get UBSan warnings about
+			 * the result of negating 0x80000000 being undefined.
+			 */
+			A = (0U - A);
+			continue;
+
+		case BPF_MISC|BPF_TAX:
+			X = A;
+			continue;
+
+		case BPF_MISC|BPF_TXA:
+			A = X;
+			continue;
+		}
+	}
+}
+
+u_int
+pcap_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+    u_int buflen)
+{
+	return pcap_filter_with_aux_data(pc, p, wirelen, buflen, NULL);
+}
+
+/*
+ * Return true if the 'fcode' is a valid filter program.
+ * The constraints are that each jump be forward and to a valid
+ * 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
+pcap_validate_filter(const struct bpf_insn *f, int len)
+{
+	u_int i, from;
+	const struct bpf_insn *p;
+
+	if (len < 1)
+		return 0;
+
+	for (i = 0; i < (u_int)len; ++i) {
+		p = &f[i];
+		switch (BPF_CLASS(p->code)) {
+		/*
+		 * Check that memory operations use valid addresses.
+		 */
+		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.
+				 */
+				break;
+			case BPF_MEM:
+				if (p->k >= BPF_MEMWORDS)
+					return 0;
+				break;
+			case BPF_LEN:
+				break;
+			default:
+				return 0;
+			}
+			break;
+		case BPF_ST:
+		case BPF_STX:
+			if (p->k >= BPF_MEMWORDS)
+				return 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_XOR:
+			case BPF_LSH:
+			case BPF_RSH:
+			case BPF_NEG:
+				break;
+			case BPF_DIV:
+			case BPF_MOD:
+				/*
+				 * Check for constant division or modulus
+				 * by 0.
+				 */
+				if (BPF_SRC(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 (from + p->k >= (u_int)len)
+					return 0;
+				break;
+			case BPF_JEQ:
+			case BPF_JGT:
+			case BPF_JGE:
+			case BPF_JSET:
+				if (from + p->jt >= (u_int)len || from + p->jf >= (u_int)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;
+}
+
+/*
+ * Exported because older versions of libpcap exported them.
+ */
+u_int
+bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+    u_int buflen)
+{
+	return pcap_filter(pc, p, wirelen, buflen);
+}
+
+int
+bpf_validate(const struct bpf_insn *f, int len)
+{
+	return pcap_validate_filter(f, len);
+}
diff --git a/bpf_image.c b/bpf_image.c
new file mode 100644
index 0000000..e48c76d
--- /dev/null
+++ b/bpf_image.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __linux__
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+
+/*
+ * We want our versions of these #defines, not Linux's version.
+ * (The two should be the same; if not, we have a problem; all BPF
+ * implementations *should* be source-compatible supersets of ours.)
+ */
+#undef BPF_STMT
+#undef BPF_JUMP
+#endif
+
+#include "pcap-int.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef SKF_AD_OFF
+/*
+ * Symbolic names for offsets that refer to the special Linux BPF locations.
+ */
+static const char *offsets[SKF_AD_MAX] = {
+#ifdef SKF_AD_PROTOCOL
+	[SKF_AD_PROTOCOL] = "proto",
+#endif
+#ifdef SKF_AD_PKTTYPE
+	[SKF_AD_PKTTYPE] = "type",
+#endif
+#ifdef SKF_AD_IFINDEX
+	[SKF_AD_IFINDEX] = "ifidx",
+#endif
+#ifdef SKF_AD_NLATTR
+	[SKF_AD_NLATTR] = "nla",
+#endif
+#ifdef SKF_AD_NLATTR_NEST
+	[SKF_AD_NLATTR_NEST] = "nlan",
+#endif
+#ifdef SKF_AD_MARK
+	[SKF_AD_MARK] = "mark",
+#endif
+#ifdef SKF_AD_QUEUE
+	[SKF_AD_QUEUE] = "queue",
+#endif
+#ifdef SKF_AD_HATYPE
+	[SKF_AD_HATYPE] = "hatype",
+#endif
+#ifdef SKF_AD_RXHASH
+	[SKF_AD_RXHASH] = "rxhash",
+#endif
+#ifdef SKF_AD_CPU
+	[SKF_AD_CPU] = "cpu",
+#endif
+#ifdef SKF_AD_ALU_XOR_X
+	[SKF_AD_ALU_XOR_X] = "xor_x",
+#endif
+#ifdef SKF_AD_VLAN_TAG
+	[SKF_AD_VLAN_TAG] = "vlan_tci",
+#endif
+#ifdef SKF_AD_VLAN_TAG_PRESENT
+	[SKF_AD_VLAN_TAG_PRESENT] = "vlanp",
+#endif
+#ifdef SKF_AD_PAY_OFFSET
+	[SKF_AD_PAY_OFFSET] = "poff",
+#endif
+#ifdef SKF_AD_RANDOM
+	[SKF_AD_RANDOM] = "random",
+#endif
+#ifdef SKF_AD_VLAN_TPID
+	[SKF_AD_VLAN_TPID] = "vlan_tpid"
+#endif
+};
+#endif
+
+static void
+bpf_print_abs_load_operand(char *buf, size_t bufsize, const struct bpf_insn *p)
+{
+#ifdef SKF_AD_OFF
+	const char *sym;
+
+	/*
+	 * It's an absolute load.
+	 * Is the offset a special Linux offset that we know about?
+	 */
+	if (p->k >= (bpf_u_int32)SKF_AD_OFF &&
+	    p->k < (bpf_u_int32)(SKF_AD_OFF + SKF_AD_MAX) &&
+	    (sym = offsets[p->k - (bpf_u_int32)SKF_AD_OFF]) != NULL) {
+		/*
+		 * Yes.  Print the offset symbolically.
+		 */
+		(void)snprintf(buf, bufsize, "[%s]", sym);
+	} else
+#endif
+		(void)snprintf(buf, bufsize, "[%d]", p->k);
+}
+
+char *
+bpf_image(const struct bpf_insn *p, int n)
+{
+	const char *op;
+	static char image[256];
+	char operand_buf[64];
+	const char *operand;
+
+	switch (p->code) {
+
+	default:
+		op = "unimp";
+		(void)snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code);
+		operand = operand_buf;
+		break;
+
+	case BPF_RET|BPF_K:
+		op = "ret";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_RET|BPF_A:
+		op = "ret";
+		operand = "";
+		break;
+
+	case BPF_LD|BPF_W|BPF_ABS:
+		op = "ld";
+		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
+		operand = operand_buf;
+		break;
+
+	case BPF_LD|BPF_H|BPF_ABS:
+		op = "ldh";
+		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
+		operand = operand_buf;
+		break;
+
+	case BPF_LD|BPF_B|BPF_ABS:
+		op = "ldb";
+		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
+		operand = operand_buf;
+		break;
+
+	case BPF_LD|BPF_W|BPF_LEN:
+		op = "ld";
+		operand = "#pktlen";
+		break;
+
+	case BPF_LD|BPF_W|BPF_IND:
+		op = "ld";
+		(void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_LD|BPF_H|BPF_IND:
+		op = "ldh";
+		(void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_LD|BPF_B|BPF_IND:
+		op = "ldb";
+		(void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_LD|BPF_IMM:
+		op = "ld";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_LDX|BPF_IMM:
+		op = "ldx";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_LDX|BPF_MSH|BPF_B:
+		op = "ldxb";
+		(void)snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_LD|BPF_MEM:
+		op = "ld";
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_LDX|BPF_MEM:
+		op = "ldx";
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ST:
+		op = "st";
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_STX:
+		op = "stx";
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_JMP|BPF_JA:
+		op = "ja";
+		(void)snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_JMP|BPF_JGT|BPF_K:
+		op = "jgt";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_JMP|BPF_JGE|BPF_K:
+		op = "jge";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_JMP|BPF_JEQ|BPF_K:
+		op = "jeq";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_JMP|BPF_JSET|BPF_K:
+		op = "jset";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_JMP|BPF_JGT|BPF_X:
+		op = "jgt";
+		operand = "x";
+		break;
+
+	case BPF_JMP|BPF_JGE|BPF_X:
+		op = "jge";
+		operand = "x";
+		break;
+
+	case BPF_JMP|BPF_JEQ|BPF_X:
+		op = "jeq";
+		operand = "x";
+		break;
+
+	case BPF_JMP|BPF_JSET|BPF_X:
+		op = "jset";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_ADD|BPF_X:
+		op = "add";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_SUB|BPF_X:
+		op = "sub";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_MUL|BPF_X:
+		op = "mul";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_DIV|BPF_X:
+		op = "div";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_MOD|BPF_X:
+		op = "mod";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_AND|BPF_X:
+		op = "and";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_OR|BPF_X:
+		op = "or";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_XOR|BPF_X:
+		op = "xor";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_LSH|BPF_X:
+		op = "lsh";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_RSH|BPF_X:
+		op = "rsh";
+		operand = "x";
+		break;
+
+	case BPF_ALU|BPF_ADD|BPF_K:
+		op = "add";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_SUB|BPF_K:
+		op = "sub";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_MUL|BPF_K:
+		op = "mul";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_DIV|BPF_K:
+		op = "div";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_MOD|BPF_K:
+		op = "mod";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_AND|BPF_K:
+		op = "and";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_OR|BPF_K:
+		op = "or";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_XOR|BPF_K:
+		op = "xor";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_LSH|BPF_K:
+		op = "lsh";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_RSH|BPF_K:
+		op = "rsh";
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		operand = operand_buf;
+		break;
+
+	case BPF_ALU|BPF_NEG:
+		op = "neg";
+		operand = "";
+		break;
+
+	case BPF_MISC|BPF_TAX:
+		op = "tax";
+		operand = "";
+		break;
+
+	case BPF_MISC|BPF_TXA:
+		op = "txa";
+		operand = "";
+		break;
+	}
+	if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) {
+		(void)snprintf(image, sizeof image,
+			      "(%03d) %-8s %-16s jt %d\tjf %d",
+			      n, op, operand, n + 1 + p->jt, n + 1 + p->jf);
+	} else {
+		(void)snprintf(image, sizeof image,
+			      "(%03d) %-8s %s",
+			      n, op, operand);
+	}
+	return image;
+}
diff --git a/charconv.h b/charconv.h
new file mode 100644
index 0000000..a37d424
--- /dev/null
+++ b/charconv.h
@@ -0,0 +1,44 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef charonv_h
+#define charonv_h
+
+#ifdef _WIN32
+extern wchar_t *cp_to_utf_16le(UINT codepage, const char *cp_string, DWORD flags);
+extern char *utf_16le_to_cp(UINT codepage, const wchar_t *utf16le_string);
+extern void utf_8_to_acp_truncated(char *);
+#endif
+
+#endif
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..a1e371a
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,371 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if arpa/inet.h declares `ether_hostton' */
+#undef ARPA_INET_H_DECLARES_ETHER_HOSTTON
+
+/* Enable optimizer debugging */
+#undef BDEBUG
+
+/* Define to 1 if remote packet capture is to be supported */
+#undef ENABLE_REMOTE
+
+/* define if we have the AIX getnetbyname_r() */
+#undef HAVE_AIX_GETNETBYNAME_R
+
+/* define if we have the AIX getprotobyname_r() */
+#undef HAVE_AIX_GETPROTOBYNAME_R
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Define to 1 if you have the <config/HaikuConfig.h> header file. */
+#undef HAVE_CONFIG_HAIKUCONFIG_H
+
+/* Define to 1 if you have the <dagapi.h> header file. */
+#undef HAVE_DAGAPI_H
+
+/* define if you have the DAG API */
+#undef HAVE_DAG_API
+
+/* define if you have dag_get_erf_types() */
+#undef HAVE_DAG_GET_ERF_TYPES
+
+/* define if you have dag_get_stream_erf_types() */
+#undef HAVE_DAG_GET_STREAM_ERF_TYPES
+
+/* define if you have large streams capable DAG API */
+#undef HAVE_DAG_LARGE_STREAMS_API
+
+/* define if you have vdag_set_device_info() */
+#undef HAVE_DAG_VDAG
+
+/* Define to 1 if you have the declaration of `ether_hostton' */
+#undef HAVE_DECL_ETHER_HOSTTON
+
+/* Define to 1 if `dl_module_id_1' is a member of `dl_hp_ppa_info_t'. */
+#undef HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1
+
+/* Define to 1 if the system has the type `dl_passive_req_t'. */
+#undef HAVE_DL_PASSIVE_REQ_T
+
+/* Define to 1 if you have the `ether_hostton' function. */
+#undef HAVE_ETHER_HOSTTON
+
+/* Define to 1 if you have the `ffs' function. */
+#undef HAVE_FFS
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `getspnam' function. */
+#undef HAVE_GETSPNAM
+
+/* Define to 1 if you have a GNU-style `strerror_r' function. */
+#undef HAVE_GNU_STRERROR_R
+
+/* on HP-UX 10.20 or later */
+#undef HAVE_HPUX10_20_OR_LATER
+
+/* on HP-UX 9.x */
+#undef HAVE_HPUX9
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `dag' library (-ldag). */
+#undef HAVE_LIBDAG
+
+/* if libdlpi exists */
+#undef HAVE_LIBDLPI
+
+/* if libnl exists */
+#undef HAVE_LIBNL
+
+/* Define to 1 if you have the <linux/compiler.h> header file. */
+#undef HAVE_LINUX_COMPILER_H
+
+/* define if we have the Linux getnetbyname_r() */
+#undef HAVE_LINUX_GETNETBYNAME_R
+
+/* define if we have the Linux getprotobyname_r() */
+#undef HAVE_LINUX_GETPROTOBYNAME_R
+
+/* Define to 1 if you have the <linux/net_tstamp.h> header file. */
+#undef HAVE_LINUX_NET_TSTAMP_H
+
+/* Define to 1 if you have the <linux/socket.h> header file. */
+#undef HAVE_LINUX_SOCKET_H
+
+/* Define to 1 if you have the <linux/usbdevice_fs.h> header file. */
+#undef HAVE_LINUX_USBDEVICE_FS_H
+
+/* Define to 1 if you have the <linux/wireless.h> header file. */
+#undef HAVE_LINUX_WIRELESS_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define to 1 if you have the <net/bpf.h> header file. */
+#undef HAVE_NET_BPF_H
+
+/* Define to 1 if you have the <net/enet.h> header file. */
+#undef HAVE_NET_ENET_H
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the <net/if_media.h> header file. */
+#undef HAVE_NET_IF_MEDIA_H
+
+/* Define to 1 if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define to 1 if you have the <net/nit.h> header file. */
+#undef HAVE_NET_NIT_H
+
+/* Define to 1 if you have the <net/pfilt.h> header file. */
+#undef HAVE_NET_PFILT_H
+
+/* Define to 1 if you have the <net/pfvar.h> header file. */
+#undef HAVE_NET_PFVAR_H
+
+/* Define to 1 if you have the <net/raw.h> header file. */
+#undef HAVE_NET_RAW_H
+
+/* Use OpenSSL */
+#undef HAVE_OPENSSL
+
+/* if there's an os_proto.h for this platform, to use additional prototypes */
+#undef HAVE_OS_PROTO_H
+
+/* define if net/pfvar.h defines PF_NAT through PF_NORDR */
+#undef HAVE_PF_NAT_THROUGH_PF_NORDR
+
+/* Define to 1 if you have a POSIX-style `strerror_r' function. */
+#undef HAVE_POSIX_STRERROR_R
+
+/* define if you have the Septel API */
+#undef HAVE_SEPTEL_API
+
+/* define if you have the Myricom SNF API */
+#undef HAVE_SNF_API
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#undef HAVE_SOCKLEN_T
+
+/* On solaris */
+#undef HAVE_SOLARIS
+
+/* define if we have the Solaris/IRIX getnetbyname_r() */
+#undef HAVE_SOLARIS_IRIX_GETNETBYNAME_R
+
+/* define if we have the Solaris/IRIX getprotobyname_r() */
+#undef HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */
+#undef HAVE_STRUCT_BPF_TIMEVAL
+
+/* Define to 1 if the system has the type `struct ether_addr'. */
+#undef HAVE_STRUCT_ETHER_ADDR
+
+/* Define to 1 if `msg_control' is a member of `struct msghdr'. */
+#undef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+
+/* Define to 1 if `msg_flags' is a member of `struct msghdr'. */
+#undef HAVE_STRUCT_MSGHDR_MSG_FLAGS
+
+/* Define to 1 if the system has the type `struct rte_ether_addr'. */
+#undef HAVE_STRUCT_RTE_ETHER_ADDR
+
+/* Define to 1 if `hci_channel' is a member of `struct sockaddr_hci'. */
+#undef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL
+
+/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
+#undef HAVE_STRUCT_SOCKADDR_SA_LEN
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if `tp_vlan_tci' is a member of `struct tpacket_auxdata'. */
+#undef HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI
+
+/* Define to 1 if `bRequestType' is a member of `struct
+   usbdevfs_ctrltransfer'. */
+#undef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
+
+/* Define to 1 if you have the <sys/bufmod.h> header file. */
+#undef HAVE_SYS_BUFMOD_H
+
+/* Define to 1 if you have the <sys/dlpi_ext.h> header file. */
+#undef HAVE_SYS_DLPI_EXT_H
+
+/* Define to 1 if you have the <sys/dlpi.h> header file. */
+#undef HAVE_SYS_DLPI_H
+
+/* Define to 1 if you have the <sys/ioccom.h> header file. */
+#undef HAVE_SYS_IOCCOM_H
+
+/* Define to 1 if you have the <sys/net/nit.h> header file. */
+#undef HAVE_SYS_NET_NIT_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* define if you have the TurboCap API */
+#undef HAVE_TC_API
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vsyslog' function. */
+#undef HAVE_VSYSLOG
+
+/* Define to 1 if you have the `_wcserror_s' function. */
+#undef HAVE__WCSERROR_S
+
+/* define if __atomic_load_n is supported by the compiler */
+#undef HAVE___ATOMIC_LOAD_N
+
+/* define if __atomic_store_n is supported by the compiler */
+#undef HAVE___ATOMIC_STORE_N
+
+/* IPv6 */
+#undef INET6
+
+/* path for device for USB sniffing */
+#undef LINUX_USB_MON_DEV
+
+/* Define to 1 if netinet/ether.h declares `ether_hostton' */
+#undef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON
+
+/* Define to 1 if netinet/if_ether.h declares `ether_hostton' */
+#undef NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON
+
+/* Define to 1 if net/ethernet.h declares `ether_hostton' */
+#undef NET_ETHERNET_H_DECLARES_ETHER_HOSTTON
+
+/* do not use protochain */
+#undef NO_PROTOCHAIN
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* target host supports Bluetooth sniffing */
+#undef PCAP_SUPPORT_BT
+
+/* target host supports Bluetooth Monitor */
+#undef PCAP_SUPPORT_BT_MONITOR
+
+/* support D-Bus sniffing */
+#undef PCAP_SUPPORT_DBUS
+
+/* target host supports DPDK */
+#undef PCAP_SUPPORT_DPDK
+
+/* target host supports Linux usbmon for USB sniffing */
+#undef PCAP_SUPPORT_LINUX_USBMON
+
+/* target host supports netfilter sniffing */
+#undef PCAP_SUPPORT_NETFILTER
+
+/* target host supports netmap */
+#undef PCAP_SUPPORT_NETMAP
+
+/* target host supports RDMA sniffing */
+#undef PCAP_SUPPORT_RDMASNIFF
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if strings.h declares `ffs' */
+#undef STRINGS_H_DECLARES_FFS
+
+/* Define to 1 if sys/ethernet.h declares `ether_hostton' */
+#undef SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON
+
+/* Enable parser debugging */
+#undef YYDEBUG
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* define on AIX to get certain functions */
+#undef _SUN
+
+/* to handle Ultrix compilers that don't support const in prototypes */
+#undef const
+
+/* Define as token for inline if inlining supported */
+#undef inline
+
+/* on sinix */
+#undef sinix
diff --git a/diag-control.h b/diag-control.h
new file mode 100644
index 0000000..47d31b9
--- /dev/null
+++ b/diag-control.h
@@ -0,0 +1,297 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _diag_control_h
+#define _diag_control_h
+
+#include "pcap/compiler-tests.h"
+
+#ifndef _MSC_VER
+  /*
+   * Clang and GCC both support this way of putting pragmas into #defines.
+   * We don't use it unless we have a compiler that supports it; the
+   * warning-suppressing pragmas differ between Clang and GCC, so we test
+   * for both of those separately.
+   */
+  #define PCAP_DO_PRAGMA(x) _Pragma (#x)
+#endif
+
+/*
+ * Suppress "enum value not explicitly handled in switch" warnings.
+ * We may have to build on multiple different Windows SDKs, so we
+ * may not be able to include all enum values in a switch, as they
+ * won't necessarily be defined on all the SDKs, and, unlike
+ * #defines, there's no easy way to test whether a given enum has
+ * a given value.  It *could* be done by the configure script or
+ * CMake tests.
+ */
+#if defined(_MSC_VER)
+  #define DIAG_OFF_ENUM_SWITCH \
+    __pragma(warning(push)) \
+    __pragma(warning(disable:4061))
+  #define DIAG_ON_ENUM_SWITCH \
+    __pragma(warning(pop))
+#else
+  #define DIAG_OFF_ENUM_SWITCH
+  #define DIAG_ON_ENUM_SWITCH
+#endif
+
+/*
+ * Suppress "switch statement has only a default case" warnings.
+ * There's a switch in bpf_filter.c that only has additional
+ * cases on Linux.
+ */
+#if defined(_MSC_VER)
+  #define DIAG_OFF_DEFAULT_ONLY_SWITCH \
+    __pragma(warning(push)) \
+    __pragma(warning(disable:4065))
+  #define DIAG_ON_DEFAULT_ONLY_SWITCH \
+    __pragma(warning(pop))
+#else
+  #define DIAG_OFF_DEFAULT_ONLY_SWITCH
+  #define DIAG_ON_DEFAULT_ONLY_SWITCH
+#endif
+
+/*
+ * Suppress Flex, narrowing, and deprecation warnings.
+ */
+#if defined(_MSC_VER)
+  /*
+   * This is Microsoft Visual Studio; we can use __pragma(warning(disable:XXXX))
+   * and __pragma(warning(push/pop)).
+   *
+   * Suppress signed-vs-unsigned comparison, narrowing, and unreachable
+   * code warnings.
+   */
+  #define DIAG_OFF_FLEX \
+    __pragma(warning(push)) \
+    __pragma(warning(disable:4127)) \
+    __pragma(warning(disable:4242)) \
+    __pragma(warning(disable:4244)) \
+    __pragma(warning(disable:4702))
+  #define DIAG_ON_FLEX \
+    __pragma(warning(pop))
+
+  /*
+   * Suppress narrowing warnings.
+   */
+  #define DIAG_OFF_NARROWING \
+    __pragma(warning(push)) \
+    __pragma(warning(disable:4242)) \
+    __pragma(warning(disable:4311))
+  #define DIAG_ON_NARROWING \
+    __pragma(warning(pop))
+
+  /*
+   * Suppress deprecation warnings.
+   */
+  #define DIAG_OFF_DEPRECATION \
+    __pragma(warning(push)) \
+    __pragma(warning(disable:4996))
+  #define DIAG_ON_DEPRECATION \
+    __pragma(warning(pop))
+#elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
+  /*
+   * This is Clang 2.8 or later; we can use "clang diagnostic
+   * ignored -Wxxx" and "clang diagnostic push/pop".
+   *
+   * Suppress -Wdocumentation warnings; GCC doesn't support -Wdocumentation,
+   * at least according to the GCC 7.3 documentation.  Apparently, Flex
+   * generates code that upsets at least some versions of Clang's
+   * -Wdocumentation.
+   */
+  #define DIAG_OFF_FLEX \
+    PCAP_DO_PRAGMA(clang diagnostic push) \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wsign-compare") \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdocumentation") \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32") \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wmissing-noreturn") \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunused-parameter") \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
+  #define DIAG_ON_FLEX \
+    PCAP_DO_PRAGMA(clang diagnostic pop)
+
+  /*
+   * Suppress the only narrowing warnings you get from Clang.
+   */
+  #define DIAG_OFF_NARROWING \
+    PCAP_DO_PRAGMA(clang diagnostic push) \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32")
+
+  #define DIAG_ON_NARROWING \
+    PCAP_DO_PRAGMA(clang diagnostic pop)
+
+  /*
+   * Suppress deprecation warnings.
+   */
+  #define DIAG_OFF_DEPRECATION \
+    PCAP_DO_PRAGMA(clang diagnostic push) \
+    PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-declarations")
+  #define DIAG_ON_DEPRECATION \
+    PCAP_DO_PRAGMA(clang diagnostic pop)
+#elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
+  /*
+   * This is GCC 4.6 or later, or a compiler claiming to be that.
+   * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2)
+   * and "GCC diagnostic push/pop" (introduced in 4.6).
+   */
+  #define DIAG_OFF_FLEX \
+    PCAP_DO_PRAGMA(GCC diagnostic push) \
+    PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wsign-compare") \
+    PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunused-parameter") \
+    PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
+  #define DIAG_ON_FLEX \
+    PCAP_DO_PRAGMA(GCC diagnostic pop)
+
+  /*
+   * GCC currently doesn't issue any narrowing warnings.
+   */
+  #define DIAG_OFF_NARROWING
+  #define DIAG_ON_NARROWING
+
+  /*
+   * Suppress deprecation warnings.
+   */
+  #define DIAG_OFF_DEPRECATION \
+    PCAP_DO_PRAGMA(GCC diagnostic push) \
+    PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations")
+  #define DIAG_ON_DEPRECATION \
+    PCAP_DO_PRAGMA(GCC diagnostic pop)
+#else
+  /*
+   * Neither Visual Studio, nor Clang 2.8 or later, nor GCC 4.6 or later
+   * or a compiler claiming to be that; there's nothing we know of that
+   * we can do.
+   */
+  #define DIAG_OFF_FLEX
+  #define DIAG_ON_FLEX
+  #define DIAG_OFF_NARROWING
+  #define DIAG_ON_NARROWING
+  #define DIAG_OFF_DEPRECATION
+  #define DIAG_ON_DEPRECATION
+#endif
+
+#ifdef YYBYACC
+  /*
+   * Berkeley YACC.
+   *
+   * It generates a global declaration of yylval, or the appropriately
+   * prefixed version of yylval, in grammar.h, *even though it's been
+   * told to generate a pure parser, meaning it doesn't have any global
+   * variables*.  Bison doesn't do this.
+   *
+   * That causes a warning due to the local declaration in the parser
+   * shadowing the global declaration.
+   *
+   * So, if the compiler warns about that, we turn off -Wshadow warnings.
+   *
+   * In addition, the generated code may have functions with unreachable
+   * code, so suppress warnings about those.
+   */
+  #if defined(_MSC_VER)
+    /*
+     * This is Microsoft Visual Studio; we can use
+     * __pragma(warning(disable:XXXX)).
+     */
+    #define DIAG_OFF_BISON_BYACC \
+      __pragma(warning(disable:4702))
+  #elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
+    /*
+     * This is Clang 2.8 or later; we can use "clang diagnostic
+     * ignored -Wxxx".
+     */
+    #define DIAG_OFF_BISON_BYACC \
+      PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshadow") \
+      PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
+  #elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
+    /*
+     * This is GCC 4.6 or later, or a compiler claiming to be that.
+     * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2,
+     * but it may not actually work very well prior to 4.6).
+     */
+    #define DIAG_OFF_BISON_BYACC \
+      PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wshadow") \
+      PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
+  #else
+    /*
+     * Neither Clang 2.8 or later nor GCC 4.6 or later or a compiler
+     * claiming to be that; there's nothing we know of that we can do.
+     */
+    #define DIAG_OFF_BISON_BYACC
+  #endif
+#else
+  /*
+   * Bison.
+   *
+   * The generated code may have functions with unreachable code and
+   * switches with only a default case, so suppress warnings about those.
+   */
+  #if defined(_MSC_VER)
+    /*
+     * This is Microsoft Visual Studio; we can use
+     * __pragma(warning(disable:XXXX)).
+     *
+     * Suppress some /Wall warnings.
+     */
+    #define DIAG_OFF_BISON_BYACC \
+      __pragma(warning(disable:4065)) \
+      __pragma(warning(disable:4127)) \
+      __pragma(warning(disable:4242)) \
+      __pragma(warning(disable:4244)) \
+      __pragma(warning(disable:4702))
+  #elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
+    /*
+     * This is Clang 2.8 or later; we can use "clang diagnostic
+     * ignored -Wxxx".
+     */
+    #define DIAG_OFF_BISON_BYACC \
+      PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
+  #elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
+    /*
+     * This is GCC 4.6 or later, or a compiler claiming to be that.
+     * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2,
+     * but it may not actually work very well prior to 4.6).
+     */
+    #define DIAG_OFF_BISON_BYACC \
+      PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
+  #else
+    /*
+     * Neither Clang 2.8 or later nor GCC 4.6 or later or a compiler
+     * claiming to be that; there's nothing we know of that we can do.
+     */
+    #define DIAG_OFF_BISON_BYACC
+  #endif
+#endif
+
+#endif /* _diag_control_h */
diff --git a/etherent.c b/etherent.c
new file mode 100644
index 0000000..69da9a5
--- /dev/null
+++ b/etherent.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pcap-int.h"
+
+#include <pcap/namedb.h>
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+static inline int skip_space(FILE *);
+static inline int skip_line(FILE *);
+
+/* Hex digit to integer. */
+static inline u_char
+xdtoi(u_char c)
+{
+	if (c >= '0' && c <= '9')
+		return (u_char)(c - '0');
+	else if (c >= 'a' && c <= 'f')
+		return (u_char)(c - 'a' + 10);
+	else
+		return (u_char)(c - 'A' + 10);
+}
+
+/*
+ * Skip linear white space (space and tab) and any CRs before LF.
+ * Stop when we hit a non-white-space character or an end-of-line LF.
+ */
+static inline int
+skip_space(FILE *f)
+{
+	int c;
+
+	do {
+		c = getc(f);
+	} while (c == ' ' || c == '\t' || c == '\r');
+
+	return c;
+}
+
+static inline int
+skip_line(FILE *f)
+{
+	int c;
+
+	do
+		c = getc(f);
+	while (c != '\n' && c != EOF);
+
+	return c;
+}
+
+struct pcap_etherent *
+pcap_next_etherent(FILE *fp)
+{
+	register int c, i;
+	u_char d;
+	char *bp;
+	size_t namesize;
+	static struct pcap_etherent e;
+
+	memset((char *)&e, 0, sizeof(e));
+	for (;;) {
+		/* Find addr */
+		c = skip_space(fp);
+		if (c == EOF)
+			return (NULL);
+		if (c == '\n')
+			continue;
+
+		/* If this is a comment, or first thing on line
+		   cannot be Ethernet address, skip the line. */
+		if (!PCAP_ISXDIGIT(c)) {
+			c = skip_line(fp);
+			if (c == EOF)
+				return (NULL);
+			continue;
+		}
+
+		/* must be the start of an address */
+		for (i = 0; i < 6; i += 1) {
+			d = xdtoi((u_char)c);
+			c = getc(fp);
+			if (c == EOF)
+				return (NULL);
+			if (PCAP_ISXDIGIT(c)) {
+				d <<= 4;
+				d |= xdtoi((u_char)c);
+				c = getc(fp);
+				if (c == EOF)
+					return (NULL);
+			}
+			e.addr[i] = d;
+			if (c != ':')
+				break;
+			c = getc(fp);
+			if (c == EOF)
+				return (NULL);
+		}
+
+		/* Must be whitespace */
+		if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
+			c = skip_line(fp);
+			if (c == EOF)
+				return (NULL);
+			continue;
+		}
+		c = skip_space(fp);
+		if (c == EOF)
+			return (NULL);
+
+		/* hit end of line... */
+		if (c == '\n')
+			continue;
+
+		if (c == '#') {
+			c = skip_line(fp);
+			if (c == EOF)
+				return (NULL);
+			continue;
+		}
+
+		/* pick up name */
+		bp = e.name;
+		/* Use 'namesize' to prevent buffer overflow. */
+		namesize = sizeof(e.name) - 1;
+		do {
+			*bp++ = (u_char)c;
+			c = getc(fp);
+			if (c == EOF)
+				return (NULL);
+		} while (c != ' ' && c != '\t' && c != '\r' && c != '\n'
+		    && --namesize != 0);
+		*bp = '\0';
+
+		/* Eat trailing junk */
+		if (c != '\n')
+			(void)skip_line(fp);
+
+		return &e;
+	}
+}
diff --git a/ethertype.h b/ethertype.h
new file mode 100644
index 0000000..e34e07b
--- /dev/null
+++ b/ethertype.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1993, 1994, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Ethernet types.
+ *
+ * We wrap the declarations with #ifdef, so that if a file includes
+ * <netinet/if_ether.h>, which may declare some of these, we don't
+ * get a bunch of complaints from the C compiler about redefinitions
+ * of these values.
+ *
+ * We declare all of them here so that no file has to include
+ * <netinet/if_ether.h> if all it needs are ETHERTYPE_ values.
+ */
+
+#ifndef ETHERTYPE_PUP
+#define ETHERTYPE_PUP		0x0200	/* PUP protocol */
+#endif
+#ifndef ETHERTYPE_IP
+#define ETHERTYPE_IP		0x0800	/* IP protocol */
+#endif
+#ifndef ETHERTYPE_ARP
+#define ETHERTYPE_ARP		0x0806	/* Addr. resolution protocol */
+#endif
+#ifndef ETHERTYPE_NS
+#define ETHERTYPE_NS		0x0600
+#endif
+#ifndef	ETHERTYPE_SPRITE
+#define ETHERTYPE_SPRITE	0x0500
+#endif
+#ifndef ETHERTYPE_TRAIL
+#define ETHERTYPE_TRAIL		0x1000
+#endif
+#ifndef	ETHERTYPE_MOPDL
+#define ETHERTYPE_MOPDL		0x6001
+#endif
+#ifndef	ETHERTYPE_MOPRC
+#define ETHERTYPE_MOPRC		0x6002
+#endif
+#ifndef	ETHERTYPE_DN
+#define ETHERTYPE_DN		0x6003
+#endif
+#ifndef	ETHERTYPE_LAT
+#define ETHERTYPE_LAT		0x6004
+#endif
+#ifndef ETHERTYPE_SCA
+#define ETHERTYPE_SCA		0x6007
+#endif
+#ifndef ETHERTYPE_TEB
+#define ETHERTYPE_TEB		0x6558
+#endif
+#ifndef ETHERTYPE_REVARP
+#define ETHERTYPE_REVARP	0x8035	/* reverse Addr. resolution protocol */
+#endif
+#ifndef	ETHERTYPE_LANBRIDGE
+#define ETHERTYPE_LANBRIDGE	0x8038
+#endif
+#ifndef	ETHERTYPE_DECDNS
+#define ETHERTYPE_DECDNS	0x803c
+#endif
+#ifndef	ETHERTYPE_DECDTS
+#define ETHERTYPE_DECDTS	0x803e
+#endif
+#ifndef	ETHERTYPE_VEXP
+#define ETHERTYPE_VEXP		0x805b
+#endif
+#ifndef	ETHERTYPE_VPROD
+#define ETHERTYPE_VPROD		0x805c
+#endif
+#ifndef ETHERTYPE_ATALK
+#define ETHERTYPE_ATALK		0x809b
+#endif
+#ifndef ETHERTYPE_AARP
+#define ETHERTYPE_AARP		0x80f3
+#endif
+#ifndef ETHERTYPE_8021Q
+#define ETHERTYPE_8021Q		0x8100
+#endif
+#ifndef ETHERTYPE_IPX
+#define ETHERTYPE_IPX		0x8137
+#endif
+#ifndef ETHERTYPE_IPV6
+#define ETHERTYPE_IPV6		0x86dd
+#endif
+#ifndef ETHERTYPE_MPLS
+#define ETHERTYPE_MPLS		0x8847
+#endif
+#ifndef ETHERTYPE_MPLS_MULTI
+#define ETHERTYPE_MPLS_MULTI	0x8848
+#endif
+#ifndef ETHERTYPE_PPPOED
+#define ETHERTYPE_PPPOED	0x8863
+#endif
+#ifndef ETHERTYPE_PPPOES
+#define ETHERTYPE_PPPOES	0x8864
+#endif
+#ifndef ETHERTYPE_8021AD
+#define ETHERTYPE_8021AD	0x88a8
+#endif
+#ifndef	ETHERTYPE_LOOPBACK
+#define ETHERTYPE_LOOPBACK	0x9000
+#endif
+#ifndef ETHERTYPE_8021QINQ
+#define ETHERTYPE_8021QINQ	0x9100
+#endif
diff --git a/extract.h b/extract.h
new file mode 100644
index 0000000..e776a9e
--- /dev/null
+++ b/extract.h
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1992, 1993, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+#include <pcap/pcap-inttypes.h>
+#include <pcap/compiler-tests.h>
+#include "portability.h"
+
+/*
+ * If we have versions of GCC or Clang that support an __attribute__
+ * to say "if we're building with unsigned behavior sanitization,
+ * don't complain about undefined behavior in this function", we
+ * label these functions with that attribute - we *know* it's undefined
+ * in the C standard, but we *also* know it does what we want with
+ * the ISA we're targeting and the compiler we're using.
+ *
+ * For GCC 4.9.0 and later, we use __attribute__((no_sanitize_undefined));
+ * pre-5.0 GCC doesn't have __has_attribute, and I'm not sure whether
+ * GCC or Clang first had __attribute__((no_sanitize(XXX)).
+ *
+ * For Clang, we check for __attribute__((no_sanitize(XXX)) with
+ * __has_attribute, as there are versions of Clang that support
+ * __attribute__((no_sanitize("undefined")) but don't support
+ * __attribute__((no_sanitize_undefined)).
+ *
+ * We define this here, rather than in funcattrs.h, because we
+ * only want it used here, we don't want it to be broadly used.
+ * (Any printer will get this defined, but this should at least
+ * make it harder for people to find.)
+ */
+#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409)
+#define UNALIGNED_OK	__attribute__((no_sanitize_undefined))
+#elif __has_attribute(no_sanitize)
+#define UNALIGNED_OK	__attribute__((no_sanitize("undefined")))
+#else
+#define UNALIGNED_OK
+#endif
+
+#if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
+    (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
+    (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
+    (defined(__s390__) || defined(__s390x__) || defined(__zarch__))
+/*
+ * The processor natively handles unaligned loads, so we can just
+ * cast the pointer and fetch through it.
+ *
+ * XXX - are those all the x86 tests we need?
+ * XXX - are those the only 68k tests we need not to generated
+ * unaligned accesses if the target is the 68000 or 68010?
+ * XXX - are there any tests we don't need, because some definitions are for
+ * compilers that also predefine the GCC symbols?
+ * XXX - do we need to test for both 32-bit and 64-bit versions of those
+ * architectures in all cases?
+ */
+UNALIGNED_OK static inline uint16_t
+EXTRACT_BE_U_2(const void *p)
+{
+	return ((uint16_t)ntohs(*(const uint16_t *)(p)));
+}
+
+UNALIGNED_OK static inline int16_t
+EXTRACT_BE_S_2(const void *p)
+{
+	return ((int16_t)ntohs(*(const int16_t *)(p)));
+}
+
+UNALIGNED_OK static inline uint32_t
+EXTRACT_BE_U_4(const void *p)
+{
+	return ((uint32_t)ntohl(*(const uint32_t *)(p)));
+}
+
+UNALIGNED_OK static inline int32_t
+EXTRACT_BE_S_4(const void *p)
+{
+	return ((int32_t)ntohl(*(const int32_t *)(p)));
+}
+
+UNALIGNED_OK static inline uint64_t
+EXTRACT_BE_U_8(const void *p)
+{
+	return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 |
+		((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
+
+}
+
+UNALIGNED_OK static inline int64_t
+EXTRACT_BE_S_8(const void *p)
+{
+	return ((int64_t)(((int64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 |
+		((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
+
+}
+#elif PCAP_IS_AT_LEAST_GNUC_VERSION(2,0) && \
+    (defined(__alpha) || defined(__alpha__) || \
+     defined(__mips) || defined(__mips__))
+/*
+ * This is MIPS or Alpha, which don't natively handle unaligned loads,
+ * but which have instructions that can help when doing unaligned
+ * loads, and this is GCC 2.0 or later or a compiler that claims to
+ * be GCC 2.0 or later, which we assume that mean we have
+ * __attribute__((packed)), which we can use to convince the compiler
+ * to generate those instructions.
+ *
+ * Declare packed structures containing a uint16_t and a uint32_t,
+ * cast the pointer to point to one of those, and fetch through it;
+ * the GCC manual doesn't appear to explicitly say that
+ * __attribute__((packed)) causes the compiler to generate unaligned-safe
+ * code, but it apppears to do so.
+ *
+ * We do this in case the compiler can generate code using those
+ * instructions to do an unaligned load and pass stuff to "ntohs()" or
+ * "ntohl()", which might be better than the code to fetch the
+ * bytes one at a time and assemble them.  (That might not be the
+ * case on a little-endian platform, such as DEC's MIPS machines and
+ * Alpha machines, where "ntohs()" and "ntohl()" might not be done
+ * inline.)
+ *
+ * We do this only for specific architectures because, for example,
+ * at least some versions of GCC, when compiling for 64-bit SPARC,
+ * generate code that assumes alignment if we do this.
+ *
+ * XXX - add other architectures and compilers as possible and
+ * appropriate.
+ *
+ * HP's C compiler, indicated by __HP_cc being defined, supports
+ * "#pragma unaligned N" in version A.05.50 and later, where "N"
+ * specifies a number of bytes at which the typedef on the next
+ * line is aligned, e.g.
+ *
+ *	#pragma unalign 1
+ *	typedef uint16_t unaligned_uint16_t;
+ *
+ * to define unaligned_uint16_t as a 16-bit unaligned data type.
+ * This could be presumably used, in sufficiently recent versions of
+ * the compiler, with macros similar to those below.  This would be
+ * useful only if that compiler could generate better code for PA-RISC
+ * or Itanium than would be generated by a bunch of shifts-and-ORs.
+ *
+ * DEC C, indicated by __DECC being defined, has, at least on Alpha,
+ * an __unaligned qualifier that can be applied to pointers to get the
+ * compiler to generate code that does unaligned loads and stores when
+ * dereferencing the pointer in question.
+ *
+ * XXX - what if the native C compiler doesn't support
+ * __attribute__((packed))?  How can we get it to generate unaligned
+ * accesses for *specific* items?
+ */
+typedef struct {
+	uint16_t	val;
+} __attribute__((packed)) unaligned_uint16_t;
+
+typedef struct {
+	int16_t		val;
+} __attribute__((packed)) unaligned_int16_t;
+
+typedef struct {
+	uint32_t	val;
+} __attribute__((packed)) unaligned_uint32_t;
+
+typedef struct {
+	int32_t		val;
+} __attribute__((packed)) unaligned_int32_t;
+
+UNALIGNED_OK static inline uint16_t
+EXTRACT_BE_U_2(const void *p)
+{
+	return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline int16_t
+EXTRACT_BE_S_2(const void *p)
+{
+	return ((int16_t)ntohs(((const unaligned_int16_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline uint32_t
+EXTRACT_BE_U_4(const void *p)
+{
+	return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline int32_t
+EXTRACT_BE_S_4(const void *p)
+{
+	return ((int32_t)ntohl(((const unaligned_int32_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline uint64_t
+EXTRACT_BE_U_8(const void *p)
+{
+	return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 |
+		((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0));
+}
+
+UNALIGNED_OK static inline int64_t
+EXTRACT_BE_S_8(const void *p)
+{
+	return ((int64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 |
+		((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0));
+}
+#else
+/*
+ * This architecture doesn't natively support unaligned loads, and either
+ * this isn't a GCC-compatible compiler, we don't have __attribute__,
+ * or we do but we don't know of any better way with this instruction
+ * set to do unaligned loads, so do unaligned loads of big-endian
+ * quantities the hard way - fetch the bytes one at a time and
+ * assemble them.
+ *
+ * XXX - ARM is a special case.  ARMv1 through ARMv5 didn't suppory
+ * unaligned loads; ARMv6 and later support it *but* have a bit in
+ * the system control register that the OS can set and that causes
+ * unaligned loads to fault rather than succeeding.
+ *
+ * At least some OSes may set that flag, so we do *not* treat ARM
+ * as supporting unaligned loads.  If your OS supports them on ARM,
+ * and you want to use them, please update the tests in the #if above
+ * to check for ARM *and* for your OS.
+ */
+#define EXTRACT_BE_U_2(p) \
+	((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \
+	            ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0)))
+#define EXTRACT_BE_S_2(p) \
+	((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \
+	           ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0)))
+#define EXTRACT_BE_U_4(p) \
+	((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0)))
+#define EXTRACT_BE_S_4(p) \
+	((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0)))
+#define EXTRACT_BE_U_8(p) \
+	((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0)))
+#define EXTRACT_BE_S_8(p) \
+	((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0)))
+
+/*
+ * Extract an IPv4 address, which is in network byte order, and not
+ * necessarily aligned, and provide the result in host byte order.
+ */
+#define EXTRACT_IPV4_TO_HOST_ORDER(p) \
+	((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0)))
+#endif /* unaligned access checks */
+
+/*
+ * Non-power-of-2 sizes.
+ */
+#define EXTRACT_BE_U_3(p) \
+	((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0)))
+
+#define EXTRACT_BE_S_3(p) \
+	(((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+	  ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \
+	             ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	             ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))) : \
+	  ((int32_t)(0xFF000000U | \
+	             ((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \
+	             ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	             ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))))
+
+#define EXTRACT_BE_U_5(p) \
+	((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0)))
+
+#define EXTRACT_BE_S_5(p) \
+	(((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+	  ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))) : \
+	  ((int64_t)(INT64_T_CONSTANT(0xFFFFFF0000000000U) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))))
+
+#define EXTRACT_BE_U_6(p) \
+	((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0)))
+
+#define EXTRACT_BE_S_6(p) \
+	(((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+	   ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))) : \
+	  ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFF00000000U) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
+	              ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))))
+
+#define EXTRACT_BE_U_7(p) \
+	((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0)))
+
+#define EXTRACT_BE_S_7(p) \
+	(((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+	  ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))) : \
+	    ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFFFF000000U) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \
+	             ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))))
+
+/*
+ * Macros to extract possibly-unaligned little-endian integral values.
+ * XXX - do loads on little-endian machines that support unaligned loads?
+ */
+#define EXTRACT_LE_U_2(p) \
+	((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	            ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_S_2(p) \
+	((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	           ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_U_4(p) \
+	((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_S_4(p) \
+	((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_U_3(p) \
+	((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	            ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_S_3(p) \
+	((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	           ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_U_8(p) \
+	((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	            ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_S_8(p) \
+	((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+	           ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
diff --git a/fad-getad.c b/fad-getad.c
new file mode 100644
index 0000000..ba8f975
--- /dev/null
+++ b/fad-getad.c
@@ -0,0 +1,279 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <net/if.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+#include "pcap-int.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+/*
+ * We don't do this on Solaris 11 and later, as it appears there aren't
+ * any AF_PACKET addresses on interfaces, so we don't need this, and
+ * we end up including both the OS's <net/bpf.h> and our <pcap/bpf.h>,
+ * and their definitions of some data structures collide.
+ */
+#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
+# ifdef HAVE_NETPACKET_PACKET_H
+/* Linux distributions with newer glibc */
+#  include <netpacket/packet.h>
+# else /* HAVE_NETPACKET_PACKET_H */
+/* LynxOS, Linux distributions with older glibc */
+# ifdef __Lynx__
+/* LynxOS */
+#  include <netpacket/if_packet.h>
+# else /* __Lynx__ */
+/* Linux */
+#  include <linux/types.h>
+#  include <linux/if_packet.h>
+# endif /* __Lynx__ */
+# endif /* HAVE_NETPACKET_PACKET_H */
+#endif /* (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) */
+
+/*
+ * This is fun.
+ *
+ * In older BSD systems, socket addresses were fixed-length, and
+ * "sizeof (struct sockaddr)" gave the size of the structure.
+ * All addresses fit within a "struct sockaddr".
+ *
+ * In newer BSD systems, the socket address is variable-length, and
+ * there's an "sa_len" field giving the length of the structure;
+ * this allows socket addresses to be longer than 2 bytes of family
+ * and 14 bytes of data.
+ *
+ * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
+ * variant of the old BSD scheme (with "struct sockaddr_storage" rather
+ * than "struct sockaddr"), and some use the new BSD scheme.
+ *
+ * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
+ * macro that determines the size based on the address family.  Other
+ * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
+ * but not in the final version).  On the latter systems, we explicitly
+ * check the AF_ type to determine the length; we assume that on
+ * all those systems we have "struct sockaddr_storage".
+ */
+#ifndef SA_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+#define SA_LEN(addr)	((addr)->sa_len)
+#else /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+static size_t
+get_sa_len(struct sockaddr *addr)
+{
+	switch (addr->sa_family) {
+
+#ifdef AF_INET
+	case AF_INET:
+		return (sizeof (struct sockaddr_in));
+#endif
+
+#ifdef AF_INET6
+	case AF_INET6:
+		return (sizeof (struct sockaddr_in6));
+#endif
+
+#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
+	case AF_PACKET:
+		return (sizeof (struct sockaddr_ll));
+#endif
+
+	default:
+		return (sizeof (struct sockaddr));
+	}
+}
+#define SA_LEN(addr)	(get_sa_len(addr))
+#else /* HAVE_STRUCT_SOCKADDR_STORAGE */
+#define SA_LEN(addr)	(sizeof (struct sockaddr))
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+#endif /* SA_LEN */
+
+/*
+ * Get a list of all interfaces that are up and that we can open.
+ * Returns -1 on error, 0 otherwise.
+ * The list, as returned through "alldevsp", may be null if no interfaces
+ * could be opened.
+ */
+int
+pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
+    int (*check_usable)(const char *), get_if_flags_func get_flags_func)
+{
+	struct ifaddrs *ifap, *ifa;
+	struct sockaddr *addr, *netmask, *broadaddr, *dstaddr;
+	size_t addr_size, broadaddr_size, dstaddr_size;
+	int ret = 0;
+	char *p, *q;
+
+	/*
+	 * Get the list of interface addresses.
+	 *
+	 * Note: this won't return information about interfaces
+	 * with no addresses, so, if a platform has interfaces
+	 * with no interfaces on which traffic can be captured,
+	 * we must check for those interfaces as well (see, for
+	 * example, what's done on Linux).
+	 *
+	 * LAN interfaces will probably have link-layer
+	 * addresses; I don't know whether all implementations
+	 * of "getifaddrs()" now, or in the future, will return
+	 * those.
+	 */
+	if (getifaddrs(&ifap) != 0) {
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "getifaddrs");
+		return (-1);
+	}
+	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+		/*
+		 * If this entry has a colon followed by a number at
+		 * the end, we assume it's a logical interface.  Those
+		 * are just the way you assign multiple IP addresses to
+		 * a real interface on Linux, so an entry for a logical
+		 * interface should be treated like the entry for the
+		 * real interface; we do that by stripping off the ":"
+		 * and the number.
+		 *
+		 * XXX - should we do this only on Linux?
+		 */
+		p = strchr(ifa->ifa_name, ':');
+		if (p != NULL) {
+			/*
+			 * We have a ":"; is it followed by a number?
+			 */
+			q = p + 1;
+			while (PCAP_ISDIGIT(*q))
+				q++;
+			if (*q == '\0') {
+				/*
+				 * All digits after the ":" until the end.
+				 * Strip off the ":" and everything after
+				 * it.
+				 */
+			       *p = '\0';
+			}
+		}
+
+		/*
+		 * Can we capture on this device?
+		 */
+		if (!(*check_usable)(ifa->ifa_name)) {
+			/*
+			 * No.
+			 */
+			continue;
+		}
+
+		/*
+		 * "ifa_addr" was apparently null on at least one
+		 * interface on some system.  Therefore, we supply
+		 * the address and netmask only if "ifa_addr" is
+		 * non-null (if there's no address, there's obviously
+		 * no netmask).
+		 */
+		if (ifa->ifa_addr != NULL) {
+			addr = ifa->ifa_addr;
+			addr_size = SA_LEN(addr);
+			netmask = ifa->ifa_netmask;
+		} else {
+			addr = NULL;
+			addr_size = 0;
+			netmask = NULL;
+		}
+
+		/*
+		 * Note that, on some platforms, ifa_broadaddr and
+		 * ifa_dstaddr could be the same field (true on at
+		 * least some versions of *BSD and macOS), so we
+		 * can't just check whether the broadcast address
+		 * is null and add it if so and check whether the
+		 * destination address is null and add it if so.
+		 *
+		 * Therefore, we must also check the IFF_BROADCAST
+		 * flag, and only add a broadcast address if it's
+		 * set, and check the IFF_POINTTOPOINT flag, and
+		 * only add a destination address if it's set (as
+		 * per man page recommendations on some of those
+		 * platforms).
+		 */
+		if (ifa->ifa_flags & IFF_BROADCAST &&
+		    ifa->ifa_broadaddr != NULL) {
+			broadaddr = ifa->ifa_broadaddr;
+			broadaddr_size = SA_LEN(broadaddr);
+		} else {
+			broadaddr = NULL;
+			broadaddr_size = 0;
+		}
+		if (ifa->ifa_flags & IFF_POINTOPOINT &&
+		    ifa->ifa_dstaddr != NULL) {
+			dstaddr = ifa->ifa_dstaddr;
+			dstaddr_size = SA_LEN(ifa->ifa_dstaddr);
+		} else {
+			dstaddr = NULL;
+			dstaddr_size = 0;
+		}
+
+		/*
+		 * Add information for this address to the list.
+		 */
+		if (add_addr_to_if(devlistp, ifa->ifa_name, ifa->ifa_flags,
+		    get_flags_func,
+		    addr, addr_size, netmask, addr_size,
+		    broadaddr, broadaddr_size, dstaddr, dstaddr_size,
+		    errbuf) < 0) {
+			ret = -1;
+			break;
+		}
+	}
+
+	freeifaddrs(ifap);
+
+	return (ret);
+}
diff --git a/fmtutils.c b/fmtutils.c
new file mode 100644
index 0000000..5c7ddad
--- /dev/null
+++ b/fmtutils.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Utilities for message formatting used both by libpcap and rpcapd.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ftmacros.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "pcap-int.h"
+
+#include "portability.h"
+
+#include "fmtutils.h"
+
+#ifdef _WIN32
+#include "charconv.h"
+#endif
+
+/*
+ * Set the encoding.
+ */
+#ifdef _WIN32
+/*
+ * True if we shouold use UTF-8.
+ */
+static int use_utf_8;
+
+void
+pcap_fmt_set_encoding(unsigned int opts)
+{
+	if (opts == PCAP_CHAR_ENC_UTF_8)
+		use_utf_8 = 1;
+}
+#else
+void
+pcap_fmt_set_encoding(unsigned int opts _U_)
+{
+	/*
+	 * Nothing to do here.
+	 */
+}
+#endif
+
+#ifdef _WIN32
+/*
+ * Convert a null-terminated UTF-16LE string to UTF-8, putting it into
+ * a buffer starting at the specified location and stopping if we go
+ * past the specified size.  This will only put out complete UTF-8
+ * sequences.
+ *
+ * We do this ourselves because Microsoft doesn't offer a "convert and
+ * stop at a UTF-8 character boundary if we run out of space" routine.
+ */
+#define IS_LEADING_SURROGATE(c) \
+	((c) >= 0xd800 && (c) < 0xdc00)
+#define IS_TRAILING_SURROGATE(c) \
+	((c) >= 0xdc00 && (c) < 0xe000)
+#define SURROGATE_VALUE(leading, trailing) \
+	(((((leading) - 0xd800) << 10) | ((trailing) - 0xdc00)) + 0x10000)
+#define REPLACEMENT_CHARACTER	0x0FFFD
+
+static char *
+utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8,
+    size_t utf_8_len)
+{
+	wchar_t c, c2;
+	uint32_t uc;
+
+	if (utf_8_len == 0) {
+		/*
+		 * Not even enough room for a trailing '\0'.
+		 * Don't put anything into the buffer.
+		 */
+		return (utf_8);
+	}
+
+	while ((c = *utf_16++) != '\0') {
+		if (IS_LEADING_SURROGATE(c)) {
+			/*
+			 * Leading surrogate.  Must be followed by
+			 * a trailing surrogate.
+			 */
+			c2 = *utf_16;
+			if (c2 == '\0') {
+				/*
+				 * Oops, string ends with a lead
+				 * surrogate.  Try to drop in
+				 * a REPLACEMENT CHARACTER, and
+				 * don't move the string pointer,
+				 * so on the next trip through
+				 * the loop we grab the terminating
+				 * '\0' and quit.
+				 */
+				uc = REPLACEMENT_CHARACTER;
+			} else {
+				/*
+				 * OK, we can consume this 2-octet
+				 * value.
+				 */
+				utf_16++;
+				if (IS_TRAILING_SURROGATE(c2)) {
+					/*
+					 * Trailing surrogate.
+					 * This calculation will,
+					 * for c being a leading
+					 * surrogate and c2 being
+					 * a trailing surrogate,
+					 * produce a value between
+					 * 0x100000 and 0x10ffff,
+					 * so it's always going to be
+					 * a valid Unicode code point.
+					 */
+					uc = SURROGATE_VALUE(c, c2);
+				} else {
+					/*
+					 * Not a trailing surroage;
+					 * try to drop in a
+					 * REPLACEMENT CHARACTER.
+					 */
+					uc = REPLACEMENT_CHARACTER;
+				}
+			}
+		} else {
+			/*
+			 * Not a leading surrogate.
+			 */
+			if (IS_TRAILING_SURROGATE(c)) {
+				/*
+				 * Trailing surrogate without
+				 * a preceding leading surrogate.
+				 * Try to drop in a REPLACEMENT
+				 * CHARACTER.
+				 */
+				uc = REPLACEMENT_CHARACTER;
+			} else {
+				/*
+				 * This is a valid BMP character;
+				 * drop it in.
+				 */
+				uc = c;
+			}
+		}
+
+		/*
+		 * OK, uc is a valid Unicode character; how
+		 * many bytes worth of UTF-8 does it require?
+		 */
+		if (uc < 0x0080) {
+			/* 1 byte. */
+			if (utf_8_len < 2) {
+				/*
+				 * Not enough room for that byte
+				 * plus a trailing '\0'.
+				 */
+				break;
+			}
+			*utf_8++ = (char)uc;
+			utf_8_len--;
+		} else if (uc < 0x0800) {
+			/* 2 bytes. */
+			if (utf_8_len < 3) {
+				/*
+				 * Not enough room for those bytes
+				 * plus a trailing '\0'.
+				 */
+				break;
+			}
+			*utf_8++ = ((uc >> 6) & 0x3F) | 0xC0;
+			*utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+			utf_8_len -= 2;
+		} else if (uc < 0x010000) {
+			/* 3 bytes. */
+			if (utf_8_len < 4) {
+				/*
+				 * Not enough room for those bytes
+				 * plus a trailing '\0'.
+				 */
+				break;
+			}
+			*utf_8++ = ((uc >> 12) & 0x0F) | 0xE0;
+			*utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
+			*utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+			utf_8_len -= 3;
+		} else {
+			/* 4 bytes. */
+			if (utf_8_len < 5) {
+				/*
+				 * Not enough room for those bytes
+				 * plus a trailing '\0'.
+				 */
+				break;
+			}
+			*utf_8++ = ((uc >> 18) & 0x03) | 0xF0;
+			*utf_8++ = ((uc >> 12) & 0x3F) | 0x80;
+			*utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
+			*utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+			utf_8_len -= 3;
+		}
+	}
+
+	/*
+	 * OK, we have enough room for (at least) a trailing '\0'.
+	 * (We started out with enough room, thanks to the test
+	 * for a zero-length buffer at the beginning, and if
+	 * there wasn't enough room for any character we wanted
+	 * to put into the buffer *plus* a trailing '\0',
+	 * we'd have quit before putting it into the buffer,
+	 * and thus would have left enough room for the trailing
+	 * '\0'.)
+	 *
+	 * Drop it in.
+	 */
+	*utf_8 = '\0';
+
+	/*
+	 * Return a pointer to the terminating '\0', in case we
+	 * want to drop something in after that.
+	 */
+	return (utf_8);
+}
+#endif /* _WIN32 */
+
+/*
+ * Generate an error message based on a format, arguments, and an
+ * errno, with a message for the errno after the formatted output.
+ */
+void
+pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
+    const char *fmt, ...)
+{
+	va_list ap;
+	size_t msglen;
+	char *p;
+	size_t errbuflen_remaining;
+
+	va_start(ap, fmt);
+	vsnprintf(errbuf, errbuflen, fmt, ap);
+	va_end(ap);
+	msglen = strlen(errbuf);
+
+	/*
+	 * Do we have enough space to append ": "?
+	 * Including the terminating '\0', that's 3 bytes.
+	 */
+	if (msglen + 3 > errbuflen) {
+		/* No - just give them what we've produced. */
+		return;
+	}
+	p = errbuf + msglen;
+	errbuflen_remaining = errbuflen - msglen;
+	*p++ = ':';
+	*p++ = ' ';
+	*p = '\0';
+	errbuflen_remaining -= 2;
+
+	/*
+	 * Now append the string for the error code.
+	 */
+#if defined(HAVE__WCSERROR_S)
+	/*
+	 * We have a Windows-style _wcserror_s().
+	 * Generate a UTF-16LE error message.
+	 */
+	wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
+	errno_t err = _wcserror_s(utf_16_errbuf, PCAP_ERRBUF_SIZE, errnum);
+	if (err != 0) {
+		/*
+		 * It doesn't appear to be documented anywhere obvious
+		 * what the error returns from _wcserror_s().
+		 */
+		snprintf(p, errbuflen_remaining, "Error %d", errnum);
+		return;
+	}
+
+	/*
+	 * Now convert it from UTF-16LE to UTF-8, dropping it in the
+	 * remaining space in the buffer, and truncating it - cleanly,
+	 * on a UTF-8 character boundary - if it doesn't fit.
+	 */
+	utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
+
+	/*
+	 * Now, if we're not in UTF-8 mode, convert errbuf to the
+	 * local code page.
+	 */
+	if (!use_utf_8)
+		utf_8_to_acp_truncated(errbuf);
+#elif defined(HAVE_GNU_STRERROR_R)
+	/*
+	 * We have a GNU-style strerror_r(), which is *not* guaranteed to
+	 * do anything to the buffer handed to it, and which returns a
+	 * pointer to the error string, which may or may not be in
+	 * the buffer.
+	 *
+	 * It is, however, guaranteed to succeed.
+	 */
+	char strerror_buf[PCAP_ERRBUF_SIZE];
+	char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE);
+	snprintf(p, errbuflen_remaining, "%s", errstring);
+#elif defined(HAVE_POSIX_STRERROR_R)
+	/*
+	 * We have a POSIX-style strerror_r(), which is guaranteed to fill
+	 * in the buffer, but is not guaranteed to succeed.
+	 */
+	int err = strerror_r(errnum, p, errbuflen_remaining);
+	if (err == EINVAL) {
+		/*
+		 * UNIX 03 says this isn't guaranteed to produce a
+		 * fallback error message.
+		 */
+		snprintf(p, errbuflen_remaining, "Unknown error: %d",
+		    errnum);
+	} else if (err == ERANGE) {
+		/*
+		 * UNIX 03 says this isn't guaranteed to produce a
+		 * fallback error message.
+		 */
+		snprintf(p, errbuflen_remaining,
+		    "Message for error %d is too long", errnum);
+	}
+#else
+	/*
+	 * We have neither _wcserror_s() nor strerror_r(), so we're
+	 * stuck with using pcap_strerror().
+	 */
+	snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
+#endif
+}
+
+#ifdef _WIN32
+/*
+ * Generate an error message based on a format, arguments, and a
+ * Win32 error, with a message for the Win32 error after the formatted output.
+ */
+void
+pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum,
+    const char *fmt, ...)
+{
+	va_list ap;
+	size_t msglen;
+	char *p;
+	size_t errbuflen_remaining;
+	DWORD retval;
+	wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
+	size_t utf_8_len;
+
+	va_start(ap, fmt);
+	vsnprintf(errbuf, errbuflen, fmt, ap);
+	va_end(ap);
+	msglen = strlen(errbuf);
+
+	/*
+	 * Do we have enough space to append ": "?
+	 * Including the terminating '\0', that's 3 bytes.
+	 */
+	if (msglen + 3 > errbuflen) {
+		/* No - just give them what we've produced. */
+		return;
+	}
+	p = errbuf + msglen;
+	errbuflen_remaining = errbuflen - msglen;
+	*p++ = ':';
+	*p++ = ' ';
+	*p = '\0';
+	msglen += 2;
+	errbuflen_remaining -= 2;
+
+	/*
+	 * Now append the string for the error code.
+	 *
+	 * XXX - what language ID to use?
+	 *
+	 * For UN*Xes, pcap_strerror() may or may not return localized
+	 * strings.
+	 *
+	 * We currently don't have localized messages for libpcap, but
+	 * we might want to do so.  On the other hand, if most of these
+	 * messages are going to be read by libpcap developers and
+	 * perhaps by developers of libpcap-based applications, English
+	 * might be a better choice, so the developer doesn't have to
+	 * get the message translated if it's in a language they don't
+	 * happen to understand.
+	 */
+	retval = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
+	    NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+	    utf_16_errbuf, PCAP_ERRBUF_SIZE, NULL);
+	if (retval == 0) {
+		/*
+		 * Failed.
+		 */
+		snprintf(p, errbuflen_remaining,
+		    "Couldn't get error message for error (%lu)", errnum);
+		return;
+	}
+
+	/*
+	 * Now convert it from UTF-16LE to UTF-8.
+	 */
+	p = utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
+
+	/*
+	 * Now append the error number, if it fits.
+	 */
+	utf_8_len = p - errbuf;
+	errbuflen_remaining -= utf_8_len;
+	if (utf_8_len == 0) {
+		/* The message was empty. */
+		snprintf(p, errbuflen_remaining, "(%lu)", errnum);
+	} else
+		snprintf(p, errbuflen_remaining, " (%lu)", errnum);
+
+	/*
+	 * Now, if we're not in UTF-8 mode, convert errbuf to the
+	 * local code page.
+	 */
+	if (!use_utf_8)
+		utf_8_to_acp_truncated(errbuf);
+}
+#endif
diff --git a/fmtutils.h b/fmtutils.h
new file mode 100644
index 0000000..ba0f66c
--- /dev/null
+++ b/fmtutils.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef fmtutils_h
+#define	fmtutils_h
+
+#include "pcap/funcattrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void	pcap_fmt_set_encoding(unsigned int);
+
+void	pcap_fmt_errmsg_for_errno(char *, size_t, int,
+    PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5);
+
+#ifdef _WIN32
+void	pcap_fmt_errmsg_for_win32_err(char *, size_t, DWORD,
+    PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ftmacros.h b/ftmacros.h
new file mode 100644
index 0000000..3cd7505
--- /dev/null
+++ b/ftmacros.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ftmacros_h
+#define	ftmacros_h
+
+/*
+ * Define some feature test macros to make sure that everything we want
+ * to be declared gets declared.
+ *
+ * On some UN*Xes we need to force strtok_r() to be declared.
+ * We do *NOT* want to define _POSIX_C_SOURCE, as that tends
+ * to make non-POSIX APIs that we use unavailable.
+ * XXX - is there no portable way to say "please pollute the
+ * namespace to the maximum extent possible"?
+ */
+#if defined(sun) || defined(__sun)
+  #define __EXTENSIONS__
+
+  /*
+   * We also need to define _XPG4_2 in order to get
+   * the Single UNIX Specification version of
+   * recvmsg().
+   */
+  #define _XPG4_2
+#elif defined(_hpux) || defined(hpux) || defined(__hpux)
+  #define _REENTRANT
+
+  /*
+   * We need this to get the versions of socket functions that
+   * use socklen_t.  Define it only if it's not already defined,
+   * so we don't get redefiniton warnings.
+   */
+  #ifndef _XOPEN_SOURCE_EXTENDED
+    #define _XOPEN_SOURCE_EXTENDED
+  #endif
+
+  /*
+   * XXX - the list of PA-RISC options for GCC makes it sound as if
+   * building code that uses a particular vintage of UNIX API/ABI
+   * is complicated:
+   *
+   *    https://gcc.gnu.org/onlinedocs/gcc/HPPA-Options.html
+   *
+   * See the description of the -munix flag.
+   *
+   * We probably want libpcap to work with programs built for any
+   * UN*X standard.  I'm not sure whether that's possible and, if
+   * it is, what sort of stuff it'd have to do.
+   *
+   * It might also be a requirement that we build with a special
+   * flag to allow the library to be used with threaded code, at
+   * least with HP's C compiler; hopefully doing so won't make it
+   * *not* work with *un*-threaded code.
+   */
+#else
+  /*
+   * Turn on _GNU_SOURCE to get everything GNU libc has to offer,
+   * including asprintf(), if we're using GNU libc.
+   *
+   * Unfortunately, one thing it has to offer is a strerror_r()
+   * that's not POSIX-compliant, but we deal with that in
+   * pcap_fmt_errmsg_for_errno().
+   *
+   * We don't limit this to, for example, Linux and Cygwin, because
+   * this might, for example, be GNU/HURD or one of Debian's kFreeBSD
+   * OSes ("GNU/FreeBSD").
+   */
+  #define _GNU_SOURCE
+
+  /*
+   * We turn on both _DEFAULT_SOURCE and _BSD_SOURCE to try to get
+   * the BSD u_XXX types, such as u_int and u_short, defined.  We
+   * define _DEFAULT_SOURCE first, so that newer versions of GNU libc
+   * don't whine about _BSD_SOURCE being deprecated; we still have
+   * to define _BSD_SOURCE to handle older versions of GNU libc that
+   * don't support _DEFAULT_SOURCE.
+   *
+   * But, if it's already defined, don't define it, so that we don't
+   * get a warning of it being redefined if it's defined as, for
+   * example, 1.
+   */
+  #ifndef _DEFAULT_SOURCE
+    #define _DEFAULT_SOURCE
+  #endif
+  /* Avoid redefining _BSD_SOURCE if it's already defined as for ex. 1 */
+  #ifndef _BSD_SOURCE
+    #define _BSD_SOURCE
+  #endif
+#endif
+
+#endif
diff --git a/gencode.c b/gencode.c
new file mode 100644
index 0000000..efdcb98
--- /dev/null
+++ b/gencode.c
@@ -0,0 +1,10058 @@
+/*#define CHASE_CHAIN*/
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifdef _WIN32
+  #include <ws2tcpip.h>
+#else
+  #include <sys/socket.h>
+
+  #ifdef __NetBSD__
+    #include <sys/param.h>
+  #endif
+
+  #include <netinet/in.h>
+  #include <arpa/inet.h>
+#endif /* _WIN32 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <setjmp.h>
+#include <stdarg.h>
+
+#ifdef MSDOS
+#include "pcap-dos.h"
+#endif
+
+#ifdef HAVE_NET_PFVAR_H
+/*
+ * In NetBSD <net/if.h> includes <net/dlt.h>, which is an older version of
+ * "pcap/dlt.h" with a lower value of DLT_MATCHING_MAX. Include the headers
+ * below before "pcap-int.h", which eventually includes "pcap/dlt.h", which
+ * redefines DLT_MATCHING_MAX from what this version of NetBSD has to what
+ * this version of libpcap has.
+ */
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <net/if_pflog.h>
+#endif /* HAVE_NET_PFVAR_H */
+
+#include "pcap-int.h"
+
+#include "extract.h"
+
+#include "ethertype.h"
+#include "nlpid.h"
+#include "llc.h"
+#include "gencode.h"
+#include "ieee80211.h"
+#include "atmuni31.h"
+#include "sunatmpos.h"
+#include "ppp.h"
+#include "pcap/sll.h"
+#include "pcap/ipnet.h"
+#include "arcnet.h"
+
+#include "grammar.h"
+#include "scanner.h"
+
+#if defined(linux)
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+#endif
+
+#ifndef offsetof
+#define offsetof(s, e) ((size_t)&((s *)0)->e)
+#endif
+
+#ifdef _WIN32
+  #ifdef INET6
+    #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
+/* IPv6 address */
+struct in6_addr
+  {
+    union
+      {
+	uint8_t		u6_addr8[16];
+	uint16_t	u6_addr16[8];
+	uint32_t	u6_addr32[4];
+      } in6_u;
+#define s6_addr			in6_u.u6_addr8
+#define s6_addr16		in6_u.u6_addr16
+#define s6_addr32		in6_u.u6_addr32
+#define s6_addr64		in6_u.u6_addr64
+  };
+
+typedef unsigned short	sa_family_t;
+
+#define	__SOCKADDR_COMMON(sa_prefix) \
+  sa_family_t sa_prefix##family
+
+/* Ditto, for IPv6.  */
+struct sockaddr_in6
+  {
+    __SOCKADDR_COMMON (sin6_);
+    uint16_t sin6_port;		/* Transport layer port # */
+    uint32_t sin6_flowinfo;	/* IPv6 flow information */
+    struct in6_addr sin6_addr;	/* IPv6 address */
+  };
+
+      #ifndef EAI_ADDRFAMILY
+struct addrinfo {
+	int	ai_flags;	/* AI_PASSIVE, AI_CANONNAME */
+	int	ai_family;	/* PF_xxx */
+	int	ai_socktype;	/* SOCK_xxx */
+	int	ai_protocol;	/* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+	size_t	ai_addrlen;	/* length of ai_addr */
+	char	*ai_canonname;	/* canonical name for hostname */
+	struct sockaddr *ai_addr;	/* binary address */
+	struct addrinfo *ai_next;	/* next structure in linked list */
+};
+      #endif /* EAI_ADDRFAMILY */
+    #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */
+  #endif /* INET6 */
+#else /* _WIN32 */
+  #include <netdb.h>	/* for "struct addrinfo" */
+#endif /* _WIN32 */
+#include <pcap/namedb.h>
+
+#include "nametoaddr.h"
+
+#define ETHERMTU	1500
+
+#ifndef IPPROTO_HOPOPTS
+#define IPPROTO_HOPOPTS 0
+#endif
+#ifndef IPPROTO_ROUTING
+#define IPPROTO_ROUTING 43
+#endif
+#ifndef IPPROTO_FRAGMENT
+#define IPPROTO_FRAGMENT 44
+#endif
+#ifndef IPPROTO_DSTOPTS
+#define IPPROTO_DSTOPTS 60
+#endif
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+#define GENEVE_PORT 6081
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#define JMP(c) ((c)|BPF_JMP|BPF_K)
+
+/*
+ * "Push" the current value of the link-layer header type and link-layer
+ * header offset onto a "stack", and set a new value.  (It's not a
+ * full-blown stack; we keep only the top two items.)
+ */
+#define PUSH_LINKHDR(cs, new_linktype, new_is_variable, new_constant_part, new_reg) \
+{ \
+	(cs)->prevlinktype = (cs)->linktype; \
+	(cs)->off_prevlinkhdr = (cs)->off_linkhdr; \
+	(cs)->linktype = (new_linktype); \
+	(cs)->off_linkhdr.is_variable = (new_is_variable); \
+	(cs)->off_linkhdr.constant_part = (new_constant_part); \
+	(cs)->off_linkhdr.reg = (new_reg); \
+	(cs)->is_geneve = 0; \
+}
+
+/*
+ * Offset "not set" value.
+ */
+#define OFFSET_NOT_SET	0xffffffffU
+
+/*
+ * Absolute offsets, which are offsets from the beginning of the raw
+ * packet data, are, in the general case, the sum of a variable value
+ * and a constant value; the variable value may be absent, in which
+ * case the offset is only the constant value, and the constant value
+ * may be zero, in which case the offset is only the variable value.
+ *
+ * bpf_abs_offset is a structure containing all that information:
+ *
+ *   is_variable is 1 if there's a variable part.
+ *
+ *   constant_part is the constant part of the value, possibly zero;
+ *
+ *   if is_variable is 1, reg is the register number for a register
+ *   containing the variable value if the register has been assigned,
+ *   and -1 otherwise.
+ */
+typedef struct {
+	int	is_variable;
+	u_int	constant_part;
+	int	reg;
+} bpf_abs_offset;
+
+/*
+ * Value passed to gen_load_a() to indicate what the offset argument
+ * is relative to the beginning of.
+ */
+enum e_offrel {
+	OR_PACKET,		/* full packet data */
+	OR_LINKHDR,		/* link-layer header */
+	OR_PREVLINKHDR,		/* previous link-layer header */
+	OR_LLC,			/* 802.2 LLC header */
+	OR_PREVMPLSHDR,		/* previous MPLS header */
+	OR_LINKTYPE,		/* link-layer type */
+	OR_LINKPL,		/* link-layer payload */
+	OR_LINKPL_NOSNAP,	/* link-layer payload, with no SNAP header at the link layer */
+	OR_TRAN_IPV4,		/* transport-layer header, with IPv4 network layer */
+	OR_TRAN_IPV6		/* transport-layer header, with IPv6 network layer */
+};
+
+/*
+ * We divy out chunks of memory rather than call malloc each time so
+ * we don't have to worry about leaking memory.  It's probably
+ * not a big deal if all this memory was wasted but if this ever
+ * goes into a library that would probably not be a good idea.
+ *
+ * XXX - this *is* in a library....
+ */
+#define NCHUNKS 16
+#define CHUNK0SIZE 1024
+struct chunk {
+	size_t n_left;
+	void *m;
+};
+
+/* Code generator state */
+
+struct _compiler_state {
+	jmp_buf top_ctx;
+	pcap_t *bpf_pcap;
+	int error_set;
+
+	struct icode ic;
+
+	int snaplen;
+
+	int linktype;
+	int prevlinktype;
+	int outermostlinktype;
+
+	bpf_u_int32 netmask;
+	int no_optimize;
+
+	/* Hack for handling VLAN and MPLS stacks. */
+	u_int label_stack_depth;
+	u_int vlan_stack_depth;
+
+	/* XXX */
+	u_int pcap_fddipad;
+
+	/*
+	 * As errors are handled by a longjmp, anything allocated must
+	 * be freed in the longjmp handler, so it must be reachable
+	 * from that handler.
+	 *
+	 * One thing that's allocated is the result of pcap_nametoaddrinfo();
+	 * it must be freed with freeaddrinfo().  This variable points to
+	 * any addrinfo structure that would need to be freed.
+	 */
+	struct addrinfo *ai;
+
+	/*
+	 * Another thing that's allocated is the result of pcap_ether_aton();
+	 * it must be freed with free().  This variable points to any
+	 * address that would need to be freed.
+	 */
+	u_char *e;
+
+	/*
+	 * Various code constructs need to know the layout of the packet.
+	 * These values give the necessary offsets from the beginning
+	 * of the packet data.
+	 */
+
+	/*
+	 * Absolute offset of the beginning of the link-layer header.
+	 */
+	bpf_abs_offset off_linkhdr;
+
+	/*
+	 * If we're checking a link-layer header for a packet encapsulated
+	 * in another protocol layer, this is the equivalent information
+	 * for the previous layers' link-layer header from the beginning
+	 * of the raw packet data.
+	 */
+	bpf_abs_offset off_prevlinkhdr;
+
+	/*
+	 * This is the equivalent information for the outermost layers'
+	 * link-layer header.
+	 */
+	bpf_abs_offset off_outermostlinkhdr;
+
+	/*
+	 * Absolute offset of the beginning of the link-layer payload.
+	 */
+	bpf_abs_offset off_linkpl;
+
+	/*
+	 * "off_linktype" is the offset to information in the link-layer
+	 * header giving the packet type. This is an absolute offset
+	 * from the beginning of the packet.
+	 *
+	 * For Ethernet, it's the offset of the Ethernet type field; this
+	 * means that it must have a value that skips VLAN tags.
+	 *
+	 * For link-layer types that always use 802.2 headers, it's the
+	 * offset of the LLC header; this means that it must have a value
+	 * that skips VLAN tags.
+	 *
+	 * For PPP, it's the offset of the PPP type field.
+	 *
+	 * For Cisco HDLC, it's the offset of the CHDLC type field.
+	 *
+	 * For BSD loopback, it's the offset of the AF_ value.
+	 *
+	 * For Linux cooked sockets, it's the offset of the type field.
+	 *
+	 * off_linktype.constant_part is set to OFFSET_NOT_SET for no
+	 * encapsulation, in which case, IP is assumed.
+	 */
+	bpf_abs_offset off_linktype;
+
+	/*
+	 * TRUE if the link layer includes an ATM pseudo-header.
+	 */
+	int is_atm;
+
+	/*
+	 * TRUE if "geneve" appeared in the filter; it causes us to
+	 * generate code that checks for a Geneve header and assume
+	 * that later filters apply to the encapsulated payload.
+	 */
+	int is_geneve;
+
+	/*
+	 * TRUE if we need variable length part of VLAN offset
+	 */
+	int is_vlan_vloffset;
+
+	/*
+	 * These are offsets for the ATM pseudo-header.
+	 */
+	u_int off_vpi;
+	u_int off_vci;
+	u_int off_proto;
+
+	/*
+	 * These are offsets for the MTP2 fields.
+	 */
+	u_int off_li;
+	u_int off_li_hsl;
+
+	/*
+	 * These are offsets for the MTP3 fields.
+	 */
+	u_int off_sio;
+	u_int off_opc;
+	u_int off_dpc;
+	u_int off_sls;
+
+	/*
+	 * This is the offset of the first byte after the ATM pseudo_header,
+	 * or -1 if there is no ATM pseudo-header.
+	 */
+	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 payload
+	 * (i.e., they don't include off_linkhdr.constant_part or
+	 * off_linkpl.constant_part).
+	 *
+	 * If the link layer never uses 802.2 LLC:
+	 *
+	 *	"off_nl" and "off_nl_nosnap" are the same.
+	 *
+	 * If the link layer always uses 802.2 LLC:
+	 *
+	 *	"off_nl" is the offset if there's a SNAP header following
+	 *	the 802.2 header;
+	 *
+	 *	"off_nl_nosnap" is the offset if there's no SNAP header.
+	 *
+	 * If the link layer is Ethernet:
+	 *
+	 *	"off_nl" is the offset if the packet is an Ethernet II packet
+	 *	(we assume no 802.3+802.2+SNAP);
+	 *
+	 *	"off_nl_nosnap" is the offset if the packet is an 802.3 packet
+	 *	with an 802.2 header following it.
+	 */
+	u_int off_nl;
+	u_int off_nl_nosnap;
+
+	/*
+	 * Here we handle simple allocation of the scratch registers.
+	 * If too many registers are alloc'd, the allocator punts.
+	 */
+	int regused[BPF_MEMWORDS];
+	int curreg;
+
+	/*
+	 * Memory chunks.
+	 */
+	struct chunk chunks[NCHUNKS];
+	int cur_chunk;
+};
+
+/*
+ * For use by routines outside this file.
+ */
+/* VARARGS */
+void
+bpf_set_error(compiler_state_t *cstate, const char *fmt, ...)
+{
+	va_list ap;
+
+	/*
+	 * If we've already set an error, don't override it.
+	 * The lexical analyzer reports some errors by setting
+	 * the error and then returning a LEX_ERROR token, which
+	 * is not recognized by any grammar rule, and thus forces
+	 * the parse to stop.  We don't want the error reported
+	 * by the lexical analyzer to be overwritten by the syntax
+	 * error.
+	 */
+	if (!cstate->error_set) {
+		va_start(ap, fmt);
+		(void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+		    fmt, ap);
+		va_end(ap);
+		cstate->error_set = 1;
+	}
+}
+
+/*
+ * For use *ONLY* in routines in this file.
+ */
+static void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...)
+    PCAP_PRINTFLIKE(2, 3);
+
+/* VARARGS */
+static void PCAP_NORETURN
+bpf_error(compiler_state_t *cstate, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+	    fmt, ap);
+	va_end(ap);
+	longjmp(cstate->top_ctx, 1);
+	/*NOTREACHED*/
+}
+
+static int init_linktype(compiler_state_t *, pcap_t *);
+
+static void init_regs(compiler_state_t *);
+static int alloc_reg(compiler_state_t *);
+static void free_reg(compiler_state_t *, int);
+
+static void initchunks(compiler_state_t *cstate);
+static void *newchunk_nolongjmp(compiler_state_t *cstate, size_t);
+static void *newchunk(compiler_state_t *cstate, size_t);
+static void freechunks(compiler_state_t *cstate);
+static inline struct block *new_block(compiler_state_t *cstate, int);
+static inline struct slist *new_stmt(compiler_state_t *cstate, int);
+static struct block *gen_retblk(compiler_state_t *cstate, int);
+static inline void syntax(compiler_state_t *cstate);
+
+static void backpatch(struct block *, struct block *);
+static void merge(struct block *, struct block *);
+static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32);
+static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32);
+static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32);
+static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32);
+static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32);
+static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32, bpf_u_int32);
+static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int,
+    u_int, const u_char *);
+static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, u_int,
+    u_int, bpf_u_int32, int, int, bpf_u_int32);
+static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *,
+    u_int, u_int);
+static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int,
+    u_int);
+static struct slist *gen_loadx_iphdrlen(compiler_state_t *);
+static struct block *gen_uncond(compiler_state_t *, int);
+static inline struct block *gen_true(compiler_state_t *);
+static inline struct block *gen_false(compiler_state_t *);
+static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32);
+static struct slist *gen_load_prism_llprefixlen(compiler_state_t *);
+static struct slist *gen_load_avs_llprefixlen(compiler_state_t *);
+static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *);
+static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *);
+static void insert_compute_vloffsets(compiler_state_t *, struct block *);
+static struct slist *gen_abs_offset_varpart(compiler_state_t *,
+    bpf_abs_offset *);
+static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32);
+static struct block *gen_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32);
+static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32,
+    int, bpf_u_int32, u_int, u_int);
+#ifdef INET6
+static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *,
+    struct in6_addr *, int, bpf_u_int32, u_int, u_int);
+#endif
+static struct block *gen_ahostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_ehostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_fhostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_thostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int);
+static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32,
+    int, int, int);
+#ifdef INET6
+static struct block *gen_host6(compiler_state_t *, struct in6_addr *,
+    struct in6_addr *, int, int, int);
+#endif
+#ifndef INET6
+static struct block *gen_gateway(compiler_state_t *, const u_char *,
+    struct addrinfo *, int, int);
+#endif
+static struct block *gen_ipfrag(compiler_state_t *);
+static struct block *gen_portatom(compiler_state_t *, int, bpf_u_int32);
+static struct block *gen_portrangeatom(compiler_state_t *, u_int, bpf_u_int32,
+    bpf_u_int32);
+static struct block *gen_portatom6(compiler_state_t *, int, bpf_u_int32);
+static struct block *gen_portrangeatom6(compiler_state_t *, u_int, bpf_u_int32,
+    bpf_u_int32);
+static struct block *gen_portop(compiler_state_t *, u_int, u_int, int);
+static struct block *gen_port(compiler_state_t *, u_int, int, int);
+static struct block *gen_portrangeop(compiler_state_t *, u_int, u_int,
+    bpf_u_int32, int);
+static struct block *gen_portrange(compiler_state_t *, u_int, u_int, int, int);
+struct block *gen_portop6(compiler_state_t *, u_int, u_int, int);
+static struct block *gen_port6(compiler_state_t *, u_int, int, int);
+static struct block *gen_portrangeop6(compiler_state_t *, u_int, u_int,
+    bpf_u_int32, int);
+static struct block *gen_portrange6(compiler_state_t *, u_int, u_int, int, int);
+static int lookup_proto(compiler_state_t *, const char *, int);
+static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int);
+static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int, int);
+static struct slist *xfer_to_x(compiler_state_t *, struct arth *);
+static struct slist *xfer_to_a(compiler_state_t *, struct arth *);
+static struct block *gen_mac_multicast(compiler_state_t *, int);
+static struct block *gen_len(compiler_state_t *, int, int);
+static struct block *gen_check_802_11_data_frame(compiler_state_t *);
+static struct block *gen_geneve_ll_check(compiler_state_t *cstate);
+
+static struct block *gen_ppi_dlt_check(compiler_state_t *);
+static struct block *gen_atmfield_code_internal(compiler_state_t *, int,
+    bpf_u_int32, int, int);
+static struct block *gen_atmtype_llc(compiler_state_t *);
+static struct block *gen_msg_abbrev(compiler_state_t *, int type);
+
+static void
+initchunks(compiler_state_t *cstate)
+{
+	int i;
+
+	for (i = 0; i < NCHUNKS; i++) {
+		cstate->chunks[i].n_left = 0;
+		cstate->chunks[i].m = NULL;
+	}
+	cstate->cur_chunk = 0;
+}
+
+static void *
+newchunk_nolongjmp(compiler_state_t *cstate, size_t n)
+{
+	struct chunk *cp;
+	int k;
+	size_t size;
+
+#ifndef __NetBSD__
+	/* XXX Round up to nearest long. */
+	n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
+#else
+	/* XXX Round up to structure boundary. */
+	n = ALIGN(n);
+#endif
+
+	cp = &cstate->chunks[cstate->cur_chunk];
+	if (n > cp->n_left) {
+		++cp;
+		k = ++cstate->cur_chunk;
+		if (k >= NCHUNKS) {
+			bpf_set_error(cstate, "out of memory");
+			return (NULL);
+		}
+		size = CHUNK0SIZE << k;
+		cp->m = (void *)malloc(size);
+		if (cp->m == NULL) {
+			bpf_set_error(cstate, "out of memory");
+			return (NULL);
+		}
+		memset((char *)cp->m, 0, size);
+		cp->n_left = size;
+		if (n > size) {
+			bpf_set_error(cstate, "out of memory");
+			return (NULL);
+		}
+	}
+	cp->n_left -= n;
+	return (void *)((char *)cp->m + cp->n_left);
+}
+
+static void *
+newchunk(compiler_state_t *cstate, size_t n)
+{
+	void *p;
+
+	p = newchunk_nolongjmp(cstate, n);
+	if (p == NULL) {
+		longjmp(cstate->top_ctx, 1);
+		/*NOTREACHED*/
+	}
+	return (p);
+}
+
+static void
+freechunks(compiler_state_t *cstate)
+{
+	int i;
+
+	for (i = 0; i < NCHUNKS; ++i)
+		if (cstate->chunks[i].m != NULL)
+			free(cstate->chunks[i].m);
+}
+
+/*
+ * A strdup whose allocations are freed after code generation is over.
+ * This is used by the lexical analyzer, so it can't longjmp; it just
+ * returns NULL on an allocation error, and the callers must check
+ * for it.
+ */
+char *
+sdup(compiler_state_t *cstate, const char *s)
+{
+	size_t n = strlen(s) + 1;
+	char *cp = newchunk_nolongjmp(cstate, n);
+
+	if (cp == NULL)
+		return (NULL);
+	pcap_strlcpy(cp, s, n);
+	return (cp);
+}
+
+static inline struct block *
+new_block(compiler_state_t *cstate, int code)
+{
+	struct block *p;
+
+	p = (struct block *)newchunk(cstate, sizeof(*p));
+	p->s.code = code;
+	p->head = p;
+
+	return p;
+}
+
+static inline struct slist *
+new_stmt(compiler_state_t *cstate, int code)
+{
+	struct slist *p;
+
+	p = (struct slist *)newchunk(cstate, sizeof(*p));
+	p->s.code = code;
+
+	return p;
+}
+
+static struct block *
+gen_retblk(compiler_state_t *cstate, int v)
+{
+	struct block *b = new_block(cstate, BPF_RET|BPF_K);
+
+	b->s.k = v;
+	return b;
+}
+
+static inline PCAP_NORETURN_DEF void
+syntax(compiler_state_t *cstate)
+{
+	bpf_error(cstate, "syntax error in filter expression");
+}
+
+int
+pcap_compile(pcap_t *p, struct bpf_program *program,
+	     const char *buf, int optimize, bpf_u_int32 mask)
+{
+#ifdef _WIN32
+	static int done = 0;
+#endif
+	compiler_state_t cstate;
+	const char * volatile xbuf = buf;
+	yyscan_t scanner = NULL;
+	volatile YY_BUFFER_STATE in_buffer = NULL;
+	u_int len;
+	int  rc;
+
+	/*
+	 * If this pcap_t hasn't been activated, it doesn't have a
+	 * link-layer type, so we can't use it.
+	 */
+	if (!p->activated) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "not-yet-activated pcap_t passed to pcap_compile");
+		return (-1);
+	}
+
+#ifdef _WIN32
+	if (!done)
+		pcap_wsockinit();
+	done = 1;
+#endif
+
+#ifdef ENABLE_REMOTE
+	/*
+	 * If the device on which we're capturing need to be notified
+	 * that a new filter is being compiled, do so.
+	 *
+	 * This allows them to save a copy of it, in case, for example,
+	 * they're implementing a form of remote packet capture, and
+	 * want the remote machine to filter out the packets in which
+	 * it's sending the packets it's captured.
+	 *
+	 * XXX - the fact that we happen to be compiling a filter
+	 * doesn't necessarily mean we'll be installing it as the
+	 * filter for this pcap_t; we might be running it from userland
+	 * on captured packets to do packet classification.  We really
+	 * need a better way of handling this, but this is all that
+	 * the WinPcap remote capture code did.
+	 */
+	if (p->save_current_filter_op != NULL)
+		(p->save_current_filter_op)(p, buf);
+#endif
+
+	initchunks(&cstate);
+	cstate.no_optimize = 0;
+#ifdef INET6
+	cstate.ai = NULL;
+#endif
+	cstate.e = NULL;
+	cstate.ic.root = NULL;
+	cstate.ic.cur_mark = 0;
+	cstate.bpf_pcap = p;
+	cstate.error_set = 0;
+	init_regs(&cstate);
+
+	cstate.netmask = mask;
+
+	cstate.snaplen = pcap_snapshot(p);
+	if (cstate.snaplen == 0) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			 "snaplen of 0 rejects all packets");
+		rc = -1;
+		goto quit;
+	}
+
+	if (pcap_lex_init(&scanner) != 0)
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "can't initialize scanner");
+	in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner);
+
+	/*
+	 * Associate the compiler state with the lexical analyzer
+	 * state.
+	 */
+	pcap_set_extra(&cstate, scanner);
+
+	if (init_linktype(&cstate, p) == -1) {
+		rc = -1;
+		goto quit;
+	}
+	if (pcap_parse(scanner, &cstate) != 0) {
+#ifdef INET6
+		if (cstate.ai != NULL)
+			freeaddrinfo(cstate.ai);
+#endif
+		if (cstate.e != NULL)
+			free(cstate.e);
+		rc = -1;
+		goto quit;
+	}
+
+	if (cstate.ic.root == NULL) {
+		/*
+		 * Catch errors reported by gen_retblk().
+		 */
+		if (setjmp(cstate.top_ctx)) {
+			rc = -1;
+			goto quit;
+		}
+		cstate.ic.root = gen_retblk(&cstate, cstate.snaplen);
+	}
+
+	if (optimize && !cstate.no_optimize) {
+		if (bpf_optimize(&cstate.ic, p->errbuf) == -1) {
+			/* Failure */
+			rc = -1;
+			goto quit;
+		}
+		if (cstate.ic.root == NULL ||
+		    (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) {
+			(void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "expression rejects all packets");
+			rc = -1;
+			goto quit;
+		}
+	}
+	program->bf_insns = icode_to_fcode(&cstate.ic,
+	    cstate.ic.root, &len, p->errbuf);
+	if (program->bf_insns == NULL) {
+		/* Failure */
+		rc = -1;
+		goto quit;
+	}
+	program->bf_len = len;
+
+	rc = 0;  /* We're all okay */
+
+quit:
+	/*
+	 * Clean up everything for the lexical analyzer.
+	 */
+	if (in_buffer != NULL)
+		pcap__delete_buffer(in_buffer, scanner);
+	if (scanner != NULL)
+		pcap_lex_destroy(scanner);
+
+	/*
+	 * Clean up our own allocated memory.
+	 */
+	freechunks(&cstate);
+
+	return (rc);
+}
+
+/*
+ * entry point for using the compiler with no pcap open
+ * pass in all the stuff that is needed explicitly instead.
+ */
+int
+pcap_compile_nopcap(int snaplen_arg, int linktype_arg,
+		    struct bpf_program *program,
+	     const char *buf, int optimize, bpf_u_int32 mask)
+{
+	pcap_t *p;
+	int ret;
+
+	p = pcap_open_dead(linktype_arg, snaplen_arg);
+	if (p == NULL)
+		return (-1);
+	ret = pcap_compile(p, program, buf, optimize, mask);
+	pcap_close(p);
+	return (ret);
+}
+
+/*
+ * Clean up a "struct bpf_program" by freeing all the memory allocated
+ * in it.
+ */
+void
+pcap_freecode(struct bpf_program *program)
+{
+	program->bf_len = 0;
+	if (program->bf_insns != NULL) {
+		free((char *)program->bf_insns);
+		program->bf_insns = NULL;
+	}
+}
+
+/*
+ * Backpatch the blocks in 'list' to 'target'.  The 'sense' field indicates
+ * which of the jt and jf fields has been resolved and which is a pointer
+ * back to another unresolved block (or nil).  At least one of the fields
+ * in each block is already resolved.
+ */
+static void
+backpatch(struct block *list, struct block *target)
+{
+	struct block *next;
+
+	while (list) {
+		if (!list->sense) {
+			next = JT(list);
+			JT(list) = target;
+		} else {
+			next = JF(list);
+			JF(list) = target;
+		}
+		list = next;
+	}
+}
+
+/*
+ * Merge the lists in b0 and b1, using the 'sense' field to indicate
+ * which of jt and jf is the link.
+ */
+static void
+merge(struct block *b0, struct block *b1)
+{
+	register struct block **p = &b0;
+
+	/* Find end of list. */
+	while (*p)
+		p = !((*p)->sense) ? &JT(*p) : &JF(*p);
+
+	/* Concatenate the lists. */
+	*p = b1;
+}
+
+int
+finish_parse(compiler_state_t *cstate, struct block *p)
+{
+	struct block *ppi_dlt_check;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return -1
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (-1);
+
+	/*
+	 * Insert before the statements of the first (root) block any
+	 * statements needed to load the lengths of any variable-length
+	 * headers into registers.
+	 *
+	 * XXX - a fancier strategy would be to insert those before the
+	 * 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, 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(cstate, p->head);
+
+	/*
+	 * For DLT_PPI captures, generate a check of the per-packet
+	 * DLT value to make sure it's DLT_IEEE802_11.
+	 *
+	 * XXX - TurboCap cards use DLT_PPI for Ethernet.
+	 * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header
+	 * with appropriate Ethernet information and use that rather
+	 * than using something such as DLT_PPI where you don't know
+	 * the link-layer header type until runtime, which, in the
+	 * general case, would force us to generate both Ethernet *and*
+	 * 802.11 code (*and* anything else for which PPI is used)
+	 * and choose between them early in the BPF program?
+	 */
+	ppi_dlt_check = gen_ppi_dlt_check(cstate);
+	if (ppi_dlt_check != NULL)
+		gen_and(ppi_dlt_check, p);
+
+	backpatch(p, gen_retblk(cstate, cstate->snaplen));
+	p->sense = !p->sense;
+	backpatch(p, gen_retblk(cstate, 0));
+	cstate->ic.root = p->head;
+	return (0);
+}
+
+void
+gen_and(struct block *b0, struct block *b1)
+{
+	backpatch(b0, b1->head);
+	b0->sense = !b0->sense;
+	b1->sense = !b1->sense;
+	merge(b1, b0);
+	b1->sense = !b1->sense;
+	b1->head = b0->head;
+}
+
+void
+gen_or(struct block *b0, struct block *b1)
+{
+	b0->sense = !b0->sense;
+	backpatch(b0, b1->head);
+	b0->sense = !b0->sense;
+	merge(b1, b0);
+	b1->head = b0->head;
+}
+
+void
+gen_not(struct block *b)
+{
+	b->sense = !b->sense;
+}
+
+static struct block *
+gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v)
+{
+	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v);
+}
+
+static struct block *
+gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v)
+{
+	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v);
+}
+
+static struct block *
+gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v)
+{
+	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v);
+}
+
+static struct block *
+gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v)
+{
+	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v);
+}
+
+static struct block *
+gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v)
+{
+	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v);
+}
+
+static struct block *
+gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 v, bpf_u_int32 mask)
+{
+	return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v);
+}
+
+static struct block *
+gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, const u_char *v)
+{
+	register struct block *b, *tmp;
+
+	b = NULL;
+	while (size >= 4) {
+		register const u_char *p = &v[size - 4];
+
+		tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W,
+		    EXTRACT_BE_U_4(p));
+		if (b != NULL)
+			gen_and(b, tmp);
+		b = tmp;
+		size -= 4;
+	}
+	while (size >= 2) {
+		register const u_char *p = &v[size - 2];
+
+		tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H,
+		    EXTRACT_BE_U_2(p));
+		if (b != NULL)
+			gen_and(b, tmp);
+		b = tmp;
+		size -= 2;
+	}
+	if (size > 0) {
+		tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]);
+		if (b != NULL)
+			gen_and(b, tmp);
+		b = tmp;
+	}
+	return b;
+}
+
+/*
+ * AND the field of size "size" at offset "offset" relative to the header
+ * specified by "offrel" with "mask", and compare it with the value "v"
+ * with the test specified by "jtype"; if "reverse" is true, the test
+ * should test the opposite of "jtype".
+ */
+static struct block *
+gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 mask, int jtype, int reverse,
+    bpf_u_int32 v)
+{
+	struct slist *s, *s2;
+	struct block *b;
+
+	s = gen_load_a(cstate, offrel, offset, size);
+
+	if (mask != 0xffffffff) {
+		s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+		s2->s.k = mask;
+		sappend(s, s2);
+	}
+
+	b = new_block(cstate, JMP(jtype));
+	b->stmts = s;
+	b->s.k = v;
+	if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE))
+		gen_not(b);
+	return b;
+}
+
+static int
+init_linktype(compiler_state_t *cstate, pcap_t *p)
+{
+	cstate->pcap_fddipad = p->fddipad;
+
+	/*
+	 * We start out with only one link-layer header.
+	 */
+	cstate->outermostlinktype = pcap_datalink(p);
+	cstate->off_outermostlinkhdr.constant_part = 0;
+	cstate->off_outermostlinkhdr.is_variable = 0;
+	cstate->off_outermostlinkhdr.reg = -1;
+
+	cstate->prevlinktype = cstate->outermostlinktype;
+	cstate->off_prevlinkhdr.constant_part = 0;
+	cstate->off_prevlinkhdr.is_variable = 0;
+	cstate->off_prevlinkhdr.reg = -1;
+
+	cstate->linktype = cstate->outermostlinktype;
+	cstate->off_linkhdr.constant_part = 0;
+	cstate->off_linkhdr.is_variable = 0;
+	cstate->off_linkhdr.reg = -1;
+
+	/*
+	 * XXX
+	 */
+	cstate->off_linkpl.constant_part = 0;
+	cstate->off_linkpl.is_variable = 0;
+	cstate->off_linkpl.reg = -1;
+
+	cstate->off_linktype.constant_part = 0;
+	cstate->off_linktype.is_variable = 0;
+	cstate->off_linktype.reg = -1;
+
+	/*
+	 * Assume it's not raw ATM with a pseudo-header, for now.
+	 */
+	cstate->is_atm = 0;
+	cstate->off_vpi = OFFSET_NOT_SET;
+	cstate->off_vci = OFFSET_NOT_SET;
+	cstate->off_proto = OFFSET_NOT_SET;
+	cstate->off_payload = OFFSET_NOT_SET;
+
+	/*
+	 * And not Geneve.
+	 */
+	cstate->is_geneve = 0;
+
+	/*
+	 * No variable length VLAN offset by default
+	 */
+	cstate->is_vlan_vloffset = 0;
+
+	/*
+	 * And assume we're not doing SS7.
+	 */
+	cstate->off_li = OFFSET_NOT_SET;
+	cstate->off_li_hsl = OFFSET_NOT_SET;
+	cstate->off_sio = OFFSET_NOT_SET;
+	cstate->off_opc = OFFSET_NOT_SET;
+	cstate->off_dpc = OFFSET_NOT_SET;
+	cstate->off_sls = OFFSET_NOT_SET;
+
+	cstate->label_stack_depth = 0;
+	cstate->vlan_stack_depth = 0;
+
+	switch (cstate->linktype) {
+
+	case DLT_ARCNET:
+		cstate->off_linktype.constant_part = 2;
+		cstate->off_linkpl.constant_part = 6;
+		cstate->off_nl = 0;		/* XXX in reality, variable! */
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_ARCNET_LINUX:
+		cstate->off_linktype.constant_part = 4;
+		cstate->off_linkpl.constant_part = 8;
+		cstate->off_nl = 0;		/* XXX in reality, variable! */
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_EN10MB:
+		cstate->off_linktype.constant_part = 12;
+		cstate->off_linkpl.constant_part = 14;	/* Ethernet header length */
+		cstate->off_nl = 0;		/* Ethernet II */
+		cstate->off_nl_nosnap = 3;	/* 802.3+802.2 */
+		break;
+
+	case DLT_SLIP:
+		/*
+		 * SLIP doesn't have a link level type.  The 16 byte
+		 * header is hacked into our SLIP driver.
+		 */
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = 16;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_SLIP_BSDOS:
+		/* XXX this may be the same as the DLT_PPP_BSDOS case */
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		/* XXX end */
+		cstate->off_linkpl.constant_part = 24;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_NULL:
+	case DLT_LOOP:
+		cstate->off_linktype.constant_part = 0;
+		cstate->off_linkpl.constant_part = 4;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_ENC:
+		cstate->off_linktype.constant_part = 0;
+		cstate->off_linkpl.constant_part = 12;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_PPP:
+	case DLT_PPP_PPPD:
+	case DLT_C_HDLC:		/* BSD/OS Cisco HDLC */
+	case DLT_PPP_SERIAL:		/* NetBSD sync/async serial PPP */
+		cstate->off_linktype.constant_part = 2;	/* skip HDLC-like framing */
+		cstate->off_linkpl.constant_part = 4;	/* skip HDLC-like framing and protocol field */
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_PPP_ETHER:
+		/*
+		 * This does no include the Ethernet header, and
+		 * only covers session state.
+		 */
+		cstate->off_linktype.constant_part = 6;
+		cstate->off_linkpl.constant_part = 8;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_PPP_BSDOS:
+		cstate->off_linktype.constant_part = 5;
+		cstate->off_linkpl.constant_part = 24;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_FDDI:
+		/*
+		 * FDDI doesn't really have a link-level type field.
+		 * We set "off_linktype" to the offset of the LLC header.
+		 *
+		 * To check for Ethernet types, we assume that SSAP = SNAP
+		 * is being used and pick out the encapsulated Ethernet type.
+		 * XXX - should we generate code to check for SNAP?
+		 */
+		cstate->off_linktype.constant_part = 13;
+		cstate->off_linktype.constant_part += cstate->pcap_fddipad;
+		cstate->off_linkpl.constant_part = 13;	/* FDDI MAC header length */
+		cstate->off_linkpl.constant_part += cstate->pcap_fddipad;
+		cstate->off_nl = 8;		/* 802.2+SNAP */
+		cstate->off_nl_nosnap = 3;	/* 802.2 */
+		break;
+
+	case DLT_IEEE802:
+		/*
+		 * Token Ring doesn't really have a link-level type field.
+		 * We set "off_linktype" to the offset of the LLC header.
+		 *
+		 * To check for Ethernet types, we assume that SSAP = SNAP
+		 * 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.
+		 * Some various Linux patched versions gave 38
+		 * as "off_linktype" and 40 as "off_nl"; however,
+		 * if a token ring packet has *no* routing
+		 * information, i.e. is not source-routed, the correct
+		 * values are 20 and 22, as they are in the vanilla code.
+		 *
+		 * A packet is source-routed iff the uppermost bit
+		 * of the first byte of the source address, at an
+		 * offset of 8, has the uppermost bit set.  If the
+		 * packet is source-routed, the total number of bytes
+		 * of routing information is 2 plus bits 0x1F00 of
+		 * the 16-bit value at an offset of 14 (shifted right
+		 * 8 - figure out which byte that is).
+		 */
+		cstate->off_linktype.constant_part = 14;
+		cstate->off_linkpl.constant_part = 14;	/* Token Ring MAC header length */
+		cstate->off_nl = 8;		/* 802.2+SNAP */
+		cstate->off_nl_nosnap = 3;	/* 802.2 */
+		break;
+
+	case DLT_PRISM_HEADER:
+	case DLT_IEEE802_11_RADIO_AVS:
+	case DLT_IEEE802_11_RADIO:
+		cstate->off_linkhdr.is_variable = 1;
+		/* Fall through, 802.11 doesn't have a variable link
+		 * prefix but is otherwise the same. */
+		/* FALLTHROUGH */
+
+	case DLT_IEEE802_11:
+		/*
+		 * 802.11 doesn't really have a link-level type field.
+		 * We set "off_linktype.constant_part" to the offset of
+		 * the LLC header.
+		 *
+		 * To check for Ethernet types, we assume that SSAP = SNAP
+		 * is being used and pick out the encapsulated Ethernet type.
+		 * XXX - should we generate code to check for SNAP?
+		 *
+		 * 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.
+		 */
+		cstate->off_linktype.constant_part = 24;
+		cstate->off_linkpl.constant_part = 0;	/* link-layer header is variable-length */
+		cstate->off_linkpl.is_variable = 1;
+		cstate->off_nl = 8;		/* 802.2+SNAP */
+		cstate->off_nl_nosnap = 3;	/* 802.2 */
+		break;
+
+	case DLT_PPI:
+		/*
+		 * 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.
+		 */
+		cstate->off_linktype.constant_part = 24;
+		cstate->off_linkpl.constant_part = 0;	/* link-layer header is variable-length */
+		cstate->off_linkpl.is_variable = 1;
+		cstate->off_linkhdr.is_variable = 1;
+		cstate->off_nl = 8;		/* 802.2+SNAP */
+		cstate->off_nl_nosnap = 3;	/* 802.2 */
+		break;
+
+	case DLT_ATM_RFC1483:
+	case DLT_ATM_CLIP:	/* Linux ATM defines this */
+		/*
+		 * assume routed, non-ISO PDUs
+		 * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00)
+		 *
+		 * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS,
+		 * or PPP with the PPP NLPID (e.g., PPPoA)?  The
+		 * latter would presumably be treated the way PPPoE
+		 * should be, so you can do "pppoe and udp port 2049"
+		 * or "pppoa and tcp port 80" and have it check for
+		 * PPPo{A,E} and a PPP protocol of IP and....
+		 */
+		cstate->off_linktype.constant_part = 0;
+		cstate->off_linkpl.constant_part = 0;	/* packet begins with LLC header */
+		cstate->off_nl = 8;		/* 802.2+SNAP */
+		cstate->off_nl_nosnap = 3;	/* 802.2 */
+		break;
+
+	case DLT_SUNATM:
+		/*
+		 * Full Frontal ATM; you get AALn PDUs with an ATM
+		 * pseudo-header.
+		 */
+		cstate->is_atm = 1;
+		cstate->off_vpi = SUNATM_VPI_POS;
+		cstate->off_vci = SUNATM_VCI_POS;
+		cstate->off_proto = PROTO_POS;
+		cstate->off_payload = SUNATM_PKT_BEGIN_POS;
+		cstate->off_linktype.constant_part = cstate->off_payload;
+		cstate->off_linkpl.constant_part = cstate->off_payload;	/* if LLC-encapsulated */
+		cstate->off_nl = 8;		/* 802.2+SNAP */
+		cstate->off_nl_nosnap = 3;	/* 802.2 */
+		break;
+
+	case DLT_RAW:
+	case DLT_IPV4:
+	case DLT_IPV6:
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = 0;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_LINUX_SLL:	/* fake header for Linux cooked socket v1 */
+		cstate->off_linktype.constant_part = 14;
+		cstate->off_linkpl.constant_part = 16;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_LINUX_SLL2:	/* fake header for Linux cooked socket v2 */
+		cstate->off_linktype.constant_part = 0;
+		cstate->off_linkpl.constant_part = 20;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_LTALK:
+		/*
+		 * LocalTalk does have a 1-byte type field in the LLAP header,
+		 * but really it just indicates whether there is a "short" or
+		 * "long" DDP packet following.
+		 */
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = 0;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_IP_OVER_FC:
+		/*
+		 * RFC 2625 IP-over-Fibre-Channel doesn't really have a
+		 * link-level type field.  We set "off_linktype" to the
+		 * offset of the LLC header.
+		 *
+		 * To check for Ethernet types, we assume that SSAP = SNAP
+		 * is being used and pick out the encapsulated Ethernet type.
+		 * XXX - should we generate code to check for SNAP? RFC
+		 * 2625 says SNAP should be used.
+		 */
+		cstate->off_linktype.constant_part = 16;
+		cstate->off_linkpl.constant_part = 16;
+		cstate->off_nl = 8;		/* 802.2+SNAP */
+		cstate->off_nl_nosnap = 3;	/* 802.2 */
+		break;
+
+	case DLT_FRELAY:
+		/*
+		 * XXX - we should set this to handle SNAP-encapsulated
+		 * frames (NLPID of 0x80).
+		 */
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = 0;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+                /*
+                 * the only BPF-interesting FRF.16 frames are non-control frames;
+                 * Frame Relay has a variable length link-layer
+                 * so lets start with offset 4 for now and increments later on (FIXME);
+                 */
+	case DLT_MFR:
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = 0;
+		cstate->off_nl = 4;
+		cstate->off_nl_nosnap = 0;	/* XXX - for now -> no 802.2 LLC */
+		break;
+
+	case DLT_APPLE_IP_OVER_IEEE1394:
+		cstate->off_linktype.constant_part = 16;
+		cstate->off_linkpl.constant_part = 18;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+
+	case DLT_SYMANTEC_FIREWALL:
+		cstate->off_linktype.constant_part = 6;
+		cstate->off_linkpl.constant_part = 44;
+		cstate->off_nl = 0;		/* Ethernet II */
+		cstate->off_nl_nosnap = 0;	/* XXX - what does it do with 802.3 packets? */
+		break;
+
+#ifdef HAVE_NET_PFVAR_H
+	case DLT_PFLOG:
+		cstate->off_linktype.constant_part = 0;
+		cstate->off_linkpl.constant_part = PFLOG_HDRLEN;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+		break;
+#endif
+
+        case DLT_JUNIPER_MFR:
+        case DLT_JUNIPER_MLFR:
+        case DLT_JUNIPER_MLPPP:
+        case DLT_JUNIPER_PPP:
+        case DLT_JUNIPER_CHDLC:
+        case DLT_JUNIPER_FRELAY:
+		cstate->off_linktype.constant_part = 4;
+		cstate->off_linkpl.constant_part = 4;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;	/* no 802.2 LLC */
+                break;
+
+	case DLT_JUNIPER_ATM1:
+		cstate->off_linktype.constant_part = 4;		/* in reality variable between 4-8 */
+		cstate->off_linkpl.constant_part = 4;	/* in reality variable between 4-8 */
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 10;
+		break;
+
+	case DLT_JUNIPER_ATM2:
+		cstate->off_linktype.constant_part = 8;		/* in reality variable between 8-12 */
+		cstate->off_linkpl.constant_part = 8;	/* in reality variable between 8-12 */
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 10;
+		break;
+
+		/* frames captured on a Juniper PPPoE service PIC
+		 * contain raw ethernet frames */
+	case DLT_JUNIPER_PPPOE:
+        case DLT_JUNIPER_ETHER:
+		cstate->off_linkpl.constant_part = 14;
+		cstate->off_linktype.constant_part = 16;
+		cstate->off_nl = 18;		/* Ethernet II */
+		cstate->off_nl_nosnap = 21;	/* 802.3+802.2 */
+		break;
+
+	case DLT_JUNIPER_PPPOE_ATM:
+		cstate->off_linktype.constant_part = 4;
+		cstate->off_linkpl.constant_part = 6;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;	/* no 802.2 LLC */
+		break;
+
+	case DLT_JUNIPER_GGSN:
+		cstate->off_linktype.constant_part = 6;
+		cstate->off_linkpl.constant_part = 12;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;	/* no 802.2 LLC */
+		break;
+
+	case DLT_JUNIPER_ES:
+		cstate->off_linktype.constant_part = 6;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;	/* not really a network layer but raw IP addresses */
+		cstate->off_nl = OFFSET_NOT_SET;	/* not really a network layer but raw IP addresses */
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;	/* no 802.2 LLC */
+		break;
+
+	case DLT_JUNIPER_MONITOR:
+		cstate->off_linktype.constant_part = 12;
+		cstate->off_linkpl.constant_part = 12;
+		cstate->off_nl = 0;			/* raw IP/IP6 header */
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;	/* no 802.2 LLC */
+		break;
+
+	case DLT_BACNET_MS_TP:
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_JUNIPER_SERVICES:
+		cstate->off_linktype.constant_part = 12;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;	/* L3 proto location dep. on cookie type */
+		cstate->off_nl = OFFSET_NOT_SET;	/* L3 proto location dep. on cookie type */
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;	/* no 802.2 LLC */
+		break;
+
+	case DLT_JUNIPER_VP:
+		cstate->off_linktype.constant_part = 18;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_JUNIPER_ST:
+		cstate->off_linktype.constant_part = 18;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_JUNIPER_ISM:
+		cstate->off_linktype.constant_part = 8;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_JUNIPER_VS:
+	case DLT_JUNIPER_SRX_E2E:
+	case DLT_JUNIPER_FIBRECHANNEL:
+	case DLT_JUNIPER_ATM_CEMIC:
+		cstate->off_linktype.constant_part = 8;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_MTP2:
+		cstate->off_li = 2;
+		cstate->off_li_hsl = 4;
+		cstate->off_sio = 3;
+		cstate->off_opc = 4;
+		cstate->off_dpc = 4;
+		cstate->off_sls = 7;
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_MTP2_WITH_PHDR:
+		cstate->off_li = 6;
+		cstate->off_li_hsl = 8;
+		cstate->off_sio = 7;
+		cstate->off_opc = 8;
+		cstate->off_dpc = 8;
+		cstate->off_sls = 11;
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_ERF:
+		cstate->off_li = 22;
+		cstate->off_li_hsl = 24;
+		cstate->off_sio = 23;
+		cstate->off_opc = 24;
+		cstate->off_dpc = 24;
+		cstate->off_sls = 27;
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_PFSYNC:
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+		cstate->off_linkpl.constant_part = 4;
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = 0;
+		break;
+
+	case DLT_AX25_KISS:
+		/*
+		 * Currently, only raw "link[N:M]" filtering is supported.
+		 */
+		cstate->off_linktype.constant_part = OFFSET_NOT_SET;	/* variable, min 15, max 71 steps of 7 */
+		cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+		cstate->off_nl = OFFSET_NOT_SET;	/* variable, min 16, max 71 steps of 7 */
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;	/* no 802.2 LLC */
+		break;
+
+	case DLT_IPNET:
+		cstate->off_linktype.constant_part = 1;
+		cstate->off_linkpl.constant_part = 24;	/* ipnet header length */
+		cstate->off_nl = 0;
+		cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		break;
+
+	case DLT_NETANALYZER:
+		cstate->off_linkhdr.constant_part = 4;	/* Ethernet header is past 4-byte pseudo-header */
+		cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
+		cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14;	/* pseudo-header+Ethernet header length */
+		cstate->off_nl = 0;		/* Ethernet II */
+		cstate->off_nl_nosnap = 3;	/* 802.3+802.2 */
+		break;
+
+	case DLT_NETANALYZER_TRANSPARENT:
+		cstate->off_linkhdr.constant_part = 12;	/* MAC header is past 4-byte pseudo-header, preamble, and SFD */
+		cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
+		cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14;	/* pseudo-header+preamble+SFD+Ethernet header length */
+		cstate->off_nl = 0;		/* Ethernet II */
+		cstate->off_nl_nosnap = 3;	/* 802.3+802.2 */
+		break;
+
+	default:
+		/*
+		 * For values in the range in which we've assigned new
+		 * DLT_ values, only raw "link[N:M]" filtering is supported.
+		 */
+		if (cstate->linktype >= DLT_MATCHING_MIN &&
+		    cstate->linktype <= DLT_MATCHING_MAX) {
+			cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+			cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+			cstate->off_nl = OFFSET_NOT_SET;
+			cstate->off_nl_nosnap = OFFSET_NOT_SET;
+		} else {
+			bpf_set_error(cstate, "unknown data link type %d", cstate->linktype);
+			return (-1);
+		}
+		break;
+	}
+
+	cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr;
+	return (0);
+}
+
+/*
+ * Load a value relative to the specified absolute offset.
+ */
+static struct slist *
+gen_load_absoffsetrel(compiler_state_t *cstate, bpf_abs_offset *abs_offset,
+    u_int offset, u_int size)
+{
+	struct slist *s, *s2;
+
+	s = gen_abs_offset_varpart(cstate, abs_offset);
+
+	/*
+	 * If "s" is non-null, it has code to arrange that the X register
+	 * contains the variable part of the absolute offset, so we
+	 * generate a load relative to that, with an offset of
+	 * abs_offset->constant_part + offset.
+	 *
+	 * Otherwise, we can do an absolute load with an offset of
+	 * abs_offset->constant_part + offset.
+	 */
+	if (s != NULL) {
+		/*
+		 * "s" points to a list of statements that puts the
+		 * variable part of the absolute offset into the X register.
+		 * Do an indirect load, to use the X register as an offset.
+		 */
+		s2 = new_stmt(cstate, BPF_LD|BPF_IND|size);
+		s2->s.k = abs_offset->constant_part + offset;
+		sappend(s, s2);
+	} else {
+		/*
+		 * There is no variable part of the absolute offset, so
+		 * just do an absolute load.
+		 */
+		s = new_stmt(cstate, BPF_LD|BPF_ABS|size);
+		s->s.k = abs_offset->constant_part + offset;
+	}
+	return s;
+}
+
+/*
+ * Load a value relative to the beginning of the specified header.
+ */
+static struct slist *
+gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size)
+{
+	struct slist *s, *s2;
+
+	/*
+	 * Squelch warnings from compilers that *don't* assume that
+	 * offrel always has a valid enum value and therefore don't
+	 * assume that we'll always go through one of the case arms.
+	 *
+	 * If we have a default case, compilers that *do* assume that
+	 * will then complain about the default case code being
+	 * unreachable.
+	 *
+	 * Damned if you do, damned if you don't.
+	 */
+	s = NULL;
+
+	switch (offrel) {
+
+	case OR_PACKET:
+                s = new_stmt(cstate, BPF_LD|BPF_ABS|size);
+                s->s.k = offset;
+		break;
+
+	case OR_LINKHDR:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_linkhdr, offset, size);
+		break;
+
+	case OR_PREVLINKHDR:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_prevlinkhdr, offset, size);
+		break;
+
+	case OR_LLC:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, offset, size);
+		break;
+
+	case OR_PREVMPLSHDR:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl - 4 + offset, size);
+		break;
+
+	case OR_LINKPL:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + offset, size);
+		break;
+
+	case OR_LINKPL_NOSNAP:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl_nosnap + offset, size);
+		break;
+
+	case OR_LINKTYPE:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_linktype, offset, size);
+		break;
+
+	case OR_TRAN_IPV4:
+		/*
+		 * Load the X register with the length of the IPv4 header
+		 * (plus the offset of the link-layer header, if it's
+		 * preceded by a variable-length header such as a radio
+		 * header), in bytes.
+		 */
+		s = gen_loadx_iphdrlen(cstate);
+
+		/*
+		 * Load the item at {offset of the link-layer payload} +
+		 * {offset, relative to the start of the link-layer
+		 * paylod, of the IPv4 header} + {length of the IPv4 header} +
+		 * {specified offset}.
+		 *
+		 * If the offset of the link-layer payload is variable,
+		 * the variable part of that offset is included in the
+		 * value in the X register, and we include the constant
+		 * part in the offset of the load.
+		 */
+		s2 = new_stmt(cstate, BPF_LD|BPF_IND|size);
+		s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + offset;
+		sappend(s, s2);
+		break;
+
+	case OR_TRAN_IPV6:
+		s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size);
+		break;
+	}
+	return s;
+}
+
+/*
+ * Generate code to load into the X register the sum of the length of
+ * the IPv4 header and the variable part of the offset of the link-layer
+ * payload.
+ */
+static struct slist *
+gen_loadx_iphdrlen(compiler_state_t *cstate)
+{
+	struct slist *s, *s2;
+
+	s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+	if (s != NULL) {
+		/*
+		 * The offset of the link-layer payload has a variable
+		 * part.  "s" points to a list of statements that put
+		 * the variable part of that offset 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
+		 * the value from the X register.
+		 */
+		s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+		s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+		sappend(s, s2);
+		s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+		s2->s.k = 0xf;
+		sappend(s, s2);
+		s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
+		s2->s.k = 2;
+		sappend(s, s2);
+
+		/*
+		 * The A register now contains the length of the IP header.
+		 * We need to add to it the variable part of the offset of
+		 * the link-layer payload, which is still in the X
+		 * register, and move the result into the X register.
+		 */
+		sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+		sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+	} else {
+		/*
+		 * The offset of the link-layer payload is a constant,
+		 * so no code was generated to load the (non-existent)
+		 * variable part of that offset.
+		 *
+		 * This means we can use the 4*([k]&0xf) addressing
+		 * mode.  Load the length of the IPv4 header, which
+		 * is at an offset of cstate->off_nl from the beginning of
+		 * the link-layer payload, and thus at an offset of
+		 * cstate->off_linkpl.constant_part + cstate->off_nl from the beginning
+		 * of the raw packet data, using that addressing mode.
+		 */
+		s = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B);
+		s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+	}
+	return s;
+}
+
+
+static struct block *
+gen_uncond(compiler_state_t *cstate, int rsense)
+{
+	struct block *b;
+	struct slist *s;
+
+	s = new_stmt(cstate, BPF_LD|BPF_IMM);
+	s->s.k = !rsense;
+	b = new_block(cstate, JMP(BPF_JEQ));
+	b->stmts = s;
+
+	return b;
+}
+
+static inline struct block *
+gen_true(compiler_state_t *cstate)
+{
+	return gen_uncond(cstate, 1);
+}
+
+static inline struct block *
+gen_false(compiler_state_t *cstate)
+{
+	return gen_uncond(cstate, 0);
+}
+
+/*
+ * Byte-swap a 32-bit number.
+ * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on
+ * big-endian platforms.)
+ */
+#define	SWAPLONG(y) \
+((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
+
+/*
+ * Generate code to match a particular packet type.
+ *
+ * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU.  We use that to determine whether to
+ * match the type/length field or to check the type/length field for
+ * a value <= ETHERMTU to see whether it's a type field and then do
+ * the appropriate test.
+ */
+static struct block *
+gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+	struct block *b0, *b1;
+
+	switch (ll_proto) {
+
+	case LLCSAP_ISONS:
+	case LLCSAP_IP:
+	case LLCSAP_NETBEUI:
+		/*
+		 * OSI protocols and NetBEUI always use 802.2 encapsulation,
+		 * so we check the DSAP and SSAP.
+		 *
+		 * LLCSAP_IP checks for IP-over-802.2, rather
+		 * than IP-over-Ethernet or IP-over-SNAP.
+		 *
+		 * XXX - should we check both the DSAP and the
+		 * SSAP, like this, or should we check just the
+		 * DSAP, as we do for other types <= ETHERMTU
+		 * (i.e., other SAP values)?
+		 */
+		b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+		gen_not(b0);
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
+		gen_and(b0, b1);
+		return b1;
+
+	case LLCSAP_IPX:
+		/*
+		 * Check for;
+		 *
+		 *	Ethernet_II frames, which are Ethernet
+		 *	frames with a frame type of ETHERTYPE_IPX;
+		 *
+		 *	Ethernet_802.3 frames, which are 802.3
+		 *	frames (i.e., the type/length field is
+		 *	a length field, <= ETHERMTU, rather than
+		 *	a type field) with the first two bytes
+		 *	after the Ethernet/802.3 header being
+		 *	0xFFFF;
+		 *
+		 *	Ethernet_802.2 frames, which are 802.3
+		 *	frames with an 802.2 LLC header and
+		 *	with the IPX LSAP as the DSAP in the LLC
+		 *	header;
+		 *
+		 *	Ethernet_SNAP frames, which are 802.3
+		 *	frames with an LLC header and a SNAP
+		 *	header and with an OUI of 0x000000
+		 *	(encapsulated Ethernet) and a protocol
+		 *	ID of ETHERTYPE_IPX in the SNAP header.
+		 *
+		 * XXX - should we generate the same code both
+		 * for tests for LLCSAP_IPX and for ETHERTYPE_IPX?
+		 */
+
+		/*
+		 * This generates code to check both for the
+		 * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
+		 */
+		b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
+		gen_or(b0, b1);
+
+		/*
+		 * Now we add code to check for SNAP frames with
+		 * ETHERTYPE_IPX, i.e. Ethernet_SNAP.
+		 */
+		b0 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX);
+		gen_or(b0, b1);
+
+		/*
+		 * Now we generate code to check for 802.3
+		 * frames in general.
+		 */
+		b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+		gen_not(b0);
+
+		/*
+		 * Now add the check for 802.3 frames before the
+		 * check for Ethernet_802.2 and Ethernet_802.3,
+		 * as those checks should only be done on 802.3
+		 * frames, not on Ethernet frames.
+		 */
+		gen_and(b0, b1);
+
+		/*
+		 * Now add the check for Ethernet_II frames, and
+		 * do that before checking for the other frame
+		 * types.
+		 */
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
+		gen_or(b0, b1);
+		return b1;
+
+	case ETHERTYPE_ATALK:
+	case ETHERTYPE_AARP:
+		/*
+		 * EtherTalk (AppleTalk protocols on Ethernet link
+		 * layer) may use 802.2 encapsulation.
+		 */
+
+		/*
+		 * Check for 802.2 encapsulation (EtherTalk phase 2?);
+		 * we check for an Ethernet type field less than
+		 * 1500, which means it's an 802.3 length field.
+		 */
+		b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+		gen_not(b0);
+
+		/*
+		 * 802.2-encapsulated ETHERTYPE_ATALK packets are
+		 * SNAP packets with an organization code of
+		 * 0x080007 (Apple, for Appletalk) and a protocol
+		 * type of ETHERTYPE_ATALK (Appletalk).
+		 *
+		 * 802.2-encapsulated ETHERTYPE_AARP packets are
+		 * SNAP packets with an organization code of
+		 * 0x000000 (encapsulated Ethernet) and a protocol
+		 * type of ETHERTYPE_AARP (Appletalk ARP).
+		 */
+		if (ll_proto == ETHERTYPE_ATALK)
+			b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
+		else	/* ll_proto == ETHERTYPE_AARP */
+			b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
+		gen_and(b0, b1);
+
+		/*
+		 * Check for Ethernet encapsulation (Ethertalk
+		 * phase 1?); we just check for the Ethernet
+		 * protocol type.
+		 */
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+
+		gen_or(b0, b1);
+		return b1;
+
+	default:
+		if (ll_proto <= ETHERMTU) {
+			/*
+			 * This is an LLC SAP value, so the frames
+			 * that match would be 802.2 frames.
+			 * Check that the frame is an 802.2 frame
+			 * (i.e., that the length/type field is
+			 * a length field, <= ETHERMTU) and
+			 * then check the DSAP.
+			 */
+			b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+			gen_not(b0);
+			b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, ll_proto);
+			gen_and(b0, b1);
+			return b1;
+		} else {
+			/*
+			 * This is an Ethernet type, so compare
+			 * the length/type field with it (if
+			 * the frame is an 802.2 frame, the length
+			 * field will be <= ETHERMTU, and, as
+			 * "ll_proto" is > ETHERMTU, this test
+			 * will fail and the frame won't match,
+			 * which is what we want).
+			 */
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+		}
+	}
+}
+
+static struct block *
+gen_loopback_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+	/*
+	 * For DLT_NULL, the link-layer header is a 32-bit word
+	 * containing an AF_ value in *host* byte order, and for
+	 * DLT_ENC, the link-layer header begins with a 32-bit
+	 * word containing an AF_ value in host byte order.
+	 *
+	 * In addition, if we're reading a saved capture file,
+	 * the host byte order in the capture may not be the
+	 * same as the host byte order on this machine.
+	 *
+	 * For DLT_LOOP, the link-layer header is a 32-bit
+	 * word containing an AF_ value in *network* byte order.
+	 */
+	if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) {
+		/*
+		 * The AF_ value is in host byte order, but the BPF
+		 * interpreter will convert it to network byte order.
+		 *
+		 * If this is a save file, and it's from a machine
+		 * with the opposite byte order to ours, we byte-swap
+		 * the AF_ value.
+		 *
+		 * Then we run it through "htonl()", and generate
+		 * code to compare against the result.
+		 */
+		if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
+			ll_proto = SWAPLONG(ll_proto);
+		ll_proto = htonl(ll_proto);
+	}
+	return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, ll_proto));
+}
+
+/*
+ * "proto" is an Ethernet type value and for IPNET, if it is not IPv4
+ * or IPv6 then we have an error.
+ */
+static struct block *
+gen_ipnet_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+	switch (ll_proto) {
+
+	case ETHERTYPE_IP:
+		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET);
+		/*NOTREACHED*/
+
+	case ETHERTYPE_IPV6:
+		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET6);
+		/*NOTREACHED*/
+
+	default:
+		break;
+	}
+
+	return gen_false(cstate);
+}
+
+/*
+ * Generate code to match a particular packet type.
+ *
+ * "ll_proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU.  We use that to determine whether to
+ * match the type field or to check the type field for the special
+ * LINUX_SLL_P_802_2 value and then do the appropriate test.
+ */
+static struct block *
+gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+	struct block *b0, *b1;
+
+	switch (ll_proto) {
+
+	case LLCSAP_ISONS:
+	case LLCSAP_IP:
+	case LLCSAP_NETBEUI:
+		/*
+		 * OSI protocols and NetBEUI always use 802.2 encapsulation,
+		 * so we check the DSAP and SSAP.
+		 *
+		 * LLCSAP_IP checks for IP-over-802.2, rather
+		 * than IP-over-Ethernet or IP-over-SNAP.
+		 *
+		 * XXX - should we check both the DSAP and the
+		 * SSAP, like this, or should we check just the
+		 * DSAP, as we do for other types <= ETHERMTU
+		 * (i.e., other SAP values)?
+		 */
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
+		gen_and(b0, b1);
+		return b1;
+
+	case LLCSAP_IPX:
+		/*
+		 *	Ethernet_II frames, which are Ethernet
+		 *	frames with a frame type of ETHERTYPE_IPX;
+		 *
+		 *	Ethernet_802.3 frames, which have a frame
+		 *	type of LINUX_SLL_P_802_3;
+		 *
+		 *	Ethernet_802.2 frames, which are 802.3
+		 *	frames with an 802.2 LLC header (i.e, have
+		 *	a frame type of LINUX_SLL_P_802_2) and
+		 *	with the IPX LSAP as the DSAP in the LLC
+		 *	header;
+		 *
+		 *	Ethernet_SNAP frames, which are 802.3
+		 *	frames with an LLC header and a SNAP
+		 *	header and with an OUI of 0x000000
+		 *	(encapsulated Ethernet) and a protocol
+		 *	ID of ETHERTYPE_IPX in the SNAP header.
+		 *
+		 * First, do the checks on LINUX_SLL_P_802_2
+		 * frames; generate the check for either
+		 * Ethernet_802.2 or Ethernet_SNAP frames, and
+		 * then put a check for LINUX_SLL_P_802_2 frames
+		 * before it.
+		 */
+		b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+		b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX);
+		gen_or(b0, b1);
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+		gen_and(b0, b1);
+
+		/*
+		 * Now check for 802.3 frames and OR that with
+		 * the previous test.
+		 */
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3);
+		gen_or(b0, b1);
+
+		/*
+		 * Now add the check for Ethernet_II frames, and
+		 * do that before checking for the other frame
+		 * types.
+		 */
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
+		gen_or(b0, b1);
+		return b1;
+
+	case ETHERTYPE_ATALK:
+	case ETHERTYPE_AARP:
+		/*
+		 * EtherTalk (AppleTalk protocols on Ethernet link
+		 * layer) may use 802.2 encapsulation.
+		 */
+
+		/*
+		 * Check for 802.2 encapsulation (EtherTalk phase 2?);
+		 * we check for the 802.2 protocol type in the
+		 * "Ethernet type" field.
+		 */
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+
+		/*
+		 * 802.2-encapsulated ETHERTYPE_ATALK packets are
+		 * SNAP packets with an organization code of
+		 * 0x080007 (Apple, for Appletalk) and a protocol
+		 * type of ETHERTYPE_ATALK (Appletalk).
+		 *
+		 * 802.2-encapsulated ETHERTYPE_AARP packets are
+		 * SNAP packets with an organization code of
+		 * 0x000000 (encapsulated Ethernet) and a protocol
+		 * type of ETHERTYPE_AARP (Appletalk ARP).
+		 */
+		if (ll_proto == ETHERTYPE_ATALK)
+			b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
+		else	/* ll_proto == ETHERTYPE_AARP */
+			b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
+		gen_and(b0, b1);
+
+		/*
+		 * Check for Ethernet encapsulation (Ethertalk
+		 * phase 1?); we just check for the Ethernet
+		 * protocol type.
+		 */
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+
+		gen_or(b0, b1);
+		return b1;
+
+	default:
+		if (ll_proto <= ETHERMTU) {
+			/*
+			 * This is an LLC SAP value, so the frames
+			 * that match would be 802.2 frames.
+			 * Check for the 802.2 protocol type
+			 * in the "Ethernet type" field, and
+			 * then check the DSAP.
+			 */
+			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+			b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B,
+			     ll_proto);
+			gen_and(b0, b1);
+			return b1;
+		} else {
+			/*
+			 * This is an Ethernet type, so compare
+			 * the length/type field with it (if
+			 * the frame is an 802.2 frame, the length
+			 * field will be <= ETHERMTU, and, as
+			 * "ll_proto" is > ETHERMTU, this test
+			 * will fail and the frame won't match,
+			 * which is what we want).
+			 */
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+		}
+	}
+}
+
+static struct slist *
+gen_load_prism_llprefixlen(compiler_state_t *cstate)
+{
+	struct slist *s1, *s2;
+	struct slist *sjeq_avs_cookie;
+	struct slist *sjcommon;
+
+	/*
+	 * This code is not compatible with the optimizer, as
+	 * we are generating jmp instructions within a normal
+	 * slist of instructions
+	 */
+	cstate->no_optimize = 1;
+
+	/*
+	 * Generate code to load the length of the radio header into
+	 * the register assigned to hold that length, if one has been
+	 * assigned.  (If one hasn't been assigned, no code we've
+	 * generated uses that prefix, so we don't need to generate any
+	 * 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 (cstate->off_linkhdr.reg != -1) {
+		/*
+		 * Load the cookie.
+		 */
+		s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS);
+		s1->s.k = 0;
+
+		/*
+		 * AND it with 0xFFFFF000.
+		 */
+		s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+		s2->s.k = 0xFFFFF000;
+		sappend(s1, s2);
+
+		/*
+		 * Compare with 0x80211000.
+		 */
+		sjeq_avs_cookie = new_stmt(cstate, 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(cstate, 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(cstate, 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(cstate, 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(cstate, BPF_ST);
+		s2->s.k = cstate->off_linkhdr.reg;
+		sappend(s1, s2);
+		sjcommon->s.jf = s2;
+
+		/*
+		 * Now move it into the X register.
+		 */
+		s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+		sappend(s1, s2);
+
+		return (s1);
+	} else
+		return (NULL);
+}
+
+static struct slist *
+gen_load_avs_llprefixlen(compiler_state_t *cstate)
+{
+	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 (cstate->off_linkhdr.reg != -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(cstate, BPF_LD|BPF_W|BPF_ABS);
+		s1->s.k = 4;
+
+		/*
+		 * Now allocate a register to hold that value and store
+		 * it.
+		 */
+		s2 = new_stmt(cstate, BPF_ST);
+		s2->s.k = cstate->off_linkhdr.reg;
+		sappend(s1, s2);
+
+		/*
+		 * Now move it into the X register.
+		 */
+		s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+		sappend(s1, s2);
+
+		return (s1);
+	} else
+		return (NULL);
+}
+
+static struct slist *
+gen_load_radiotap_llprefixlen(compiler_state_t *cstate)
+{
+	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 (cstate->off_linkhdr.reg != -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
+		 * to load it a byte at a time and construct the value.
+		 */
+
+		/*
+		 * Load the high-order byte, at an offset of 3, shift it
+		 * left a byte, and put the result in the X register.
+		 */
+		s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+		s1->s.k = 3;
+		s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
+		sappend(s1, s2);
+		s2->s.k = 8;
+		s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+		sappend(s1, s2);
+
+		/*
+		 * Load the next byte, at an offset of 2, and OR the
+		 * value from the X register into it.
+		 */
+		s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+		sappend(s1, s2);
+		s2->s.k = 2;
+		s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X);
+		sappend(s1, s2);
+
+		/*
+		 * Now allocate a register to hold that value and store
+		 * it.
+		 */
+		s2 = new_stmt(cstate, BPF_ST);
+		s2->s.k = cstate->off_linkhdr.reg;
+		sappend(s1, s2);
+
+		/*
+		 * Now move it into the X register.
+		 */
+		s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+		sappend(s1, s2);
+
+		return (s1);
+	} else
+		return (NULL);
+}
+
+/*
+ * 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;
+ * that's done in finish_parse().
+ */
+static struct slist *
+gen_load_ppi_llprefixlen(compiler_state_t *cstate)
+{
+	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 (cstate->off_linkhdr.reg != -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
+		 * to load it a byte at a time and construct the value.
+		 */
+
+		/*
+		 * Load the high-order byte, at an offset of 3, shift it
+		 * left a byte, and put the result in the X register.
+		 */
+		s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+		s1->s.k = 3;
+		s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
+		sappend(s1, s2);
+		s2->s.k = 8;
+		s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+		sappend(s1, s2);
+
+		/*
+		 * Load the next byte, at an offset of 2, and OR the
+		 * value from the X register into it.
+		 */
+		s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+		sappend(s1, s2);
+		s2->s.k = 2;
+		s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X);
+		sappend(s1, s2);
+
+		/*
+		 * Now allocate a register to hold that value and store
+		 * it.
+		 */
+		s2 = new_stmt(cstate, BPF_ST);
+		s2->s.k = cstate->off_linkhdr.reg;
+		sappend(s1, s2);
+
+		/*
+		 * Now move it into the X register.
+		 */
+		s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+		sappend(s1, s2);
+
+		return (s1);
+	} else
+		return (NULL);
+}
+
+/*
+ * 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(compiler_state_t *cstate, 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_present;
+	struct slist *sjset_radiotap_ext_present;
+	struct slist *sjset_radiotap_tsft_present;
+	struct slist *sjset_tsft_datapad, *sjset_notsft_datapad;
+	struct slist *s_roundup;
+
+	if (cstate->off_linkpl.reg == -1) {
+		/*
+		 * No register has been assigned to the offset of
+		 * the link-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
+	 */
+	cstate->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_outermostlinkhdr.constant_part".
+	 */
+	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 cstate->off_linkpl.reg register.
+		 * That length is off_outermostlinkhdr.constant_part.
+		 */
+		s = new_stmt(cstate, BPF_LDX|BPF_IMM);
+		s->s.k = cstate->off_outermostlinkhdr.constant_part;
+	}
+
+	/*
+	 * 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 cstate->off_linkpl.reg, and then load the Frame Control field,
+	 * which is at the offset in the X register, with an indexed load.
+	 */
+	s2 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+	sappend(s, s2);
+	s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s2->s.k = 24;
+	sappend(s, s2);
+	s2 = new_stmt(cstate, BPF_ST);
+	s2->s.k = cstate->off_linkpl.reg;
+	sappend(s, s2);
+
+	s2 = new_stmt(cstate, 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(cstate, 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(cstate, 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(cstate, JMP(BPF_JSET));
+	sjset_qos->s.k = 0x80;	/* QoS bit */
+	sappend(s, sjset_qos);
+
+	/*
+	 * If it's set, add 2 to cstate->off_linkpl.reg, to skip the QoS
+	 * field.
+	 * Otherwise, go to the first statement of the rest of the
+	 * program.
+	 */
+	sjset_qos->s.jt = s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
+	s2->s.k = cstate->off_linkpl.reg;
+	sappend(s, s2);
+	s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+	s2->s.k = 2;
+	sappend(s, s2);
+	s2 = new_stmt(cstate, BPF_ST);
+	s2->s.k = cstate->off_linkpl.reg;
+	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.
+	 *
+	 * XXX - in the general case, we would have to scan through
+	 * *all* the presence bits, if there's more than one word of
+	 * presence bits.  That would require a loop, meaning that
+	 * we wouldn't be able to run the filter in the kernel.
+	 *
+	 * We assume here that the Atheros adapters that insert the
+	 * annoying padding don't have multiple antennae and therefore
+	 * do not generate radiotap headers with multiple presence words.
+	 */
+	if (cstate->linktype == DLT_IEEE802_11_RADIO) {
+		/*
+		 * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set
+		 * in the first presence flag word?
+		 */
+		sjset_qos->s.jf = s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_W);
+		s2->s.k = 4;
+		sappend(s, s2);
+
+		sjset_radiotap_flags_present = new_stmt(cstate, JMP(BPF_JSET));
+		sjset_radiotap_flags_present->s.k = SWAPLONG(0x00000002);
+		sappend(s, sjset_radiotap_flags_present);
+
+		/*
+		 * If not, skip all of this.
+		 */
+		sjset_radiotap_flags_present->s.jf = snext;
+
+		/*
+		 * Otherwise, is the "extension" bit set in that word?
+		 */
+		sjset_radiotap_ext_present = new_stmt(cstate, JMP(BPF_JSET));
+		sjset_radiotap_ext_present->s.k = SWAPLONG(0x80000000);
+		sappend(s, sjset_radiotap_ext_present);
+		sjset_radiotap_flags_present->s.jt = sjset_radiotap_ext_present;
+
+		/*
+		 * If so, skip all of this.
+		 */
+		sjset_radiotap_ext_present->s.jt = snext;
+
+		/*
+		 * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set?
+		 */
+		sjset_radiotap_tsft_present = new_stmt(cstate, JMP(BPF_JSET));
+		sjset_radiotap_tsft_present->s.k = SWAPLONG(0x00000001);
+		sappend(s, sjset_radiotap_tsft_present);
+		sjset_radiotap_ext_present->s.jf = sjset_radiotap_tsft_present;
+
+		/*
+		 * 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.
+		 */
+		s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+		s2->s.k = 16;
+		sappend(s, s2);
+		sjset_radiotap_tsft_present->s.jt = s2;
+
+		sjset_tsft_datapad = new_stmt(cstate, 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.
+		 */
+		s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+		s2->s.k = 8;
+		sappend(s, s2);
+		sjset_radiotap_tsft_present->s.jf = s2;
+
+		sjset_notsft_datapad = new_stmt(cstate, 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(cstate, BPF_LD|BPF_MEM);
+		s_roundup->s.k = cstate->off_linkpl.reg;
+		sappend(s, s_roundup);
+		s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+		s2->s.k = 3;
+		sappend(s, s2);
+		s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM);
+		s2->s.k = (bpf_u_int32)~3;
+		sappend(s, s2);
+		s2 = new_stmt(cstate, BPF_ST);
+		s2->s.k = cstate->off_linkpl.reg;
+		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(compiler_state_t *cstate, struct block *b)
+{
+	struct slist *s;
+
+	/* There is an implicit dependency between the link
+	 * payload and link header since the payload computation
+	 * includes the variable part of the header. Therefore,
+	 * if nobody else has allocated a register for the link
+	 * header and we need it, do it now. */
+	if (cstate->off_linkpl.reg != -1 && cstate->off_linkhdr.is_variable &&
+	    cstate->off_linkhdr.reg == -1)
+		cstate->off_linkhdr.reg = alloc_reg(cstate);
+
+	/*
+	 * 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.
+	 *
+	 * XXX - this, and the next switch statement, won't handle
+	 * encapsulation of 802.11 or 802.11+radio information in
+	 * some other protocol stack.  That's significantly more
+	 * complicated.
+	 */
+	switch (cstate->outermostlinktype) {
+
+	case DLT_PRISM_HEADER:
+		s = gen_load_prism_llprefixlen(cstate);
+		break;
+
+	case DLT_IEEE802_11_RADIO_AVS:
+		s = gen_load_avs_llprefixlen(cstate);
+		break;
+
+	case DLT_IEEE802_11_RADIO:
+		s = gen_load_radiotap_llprefixlen(cstate);
+		break;
+
+	case DLT_PPI:
+		s = gen_load_ppi_llprefixlen(cstate);
+		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 link-layer
+	 * payload into the register assigned to that offset, if any.
+	 */
+	switch (cstate->outermostlinktype) {
+
+	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(cstate, s, b->stmts);
+		break;
+	}
+
+	/*
+	 * If there is no initialization yet and we need variable
+	 * length offsets for VLAN, initialize them to zero
+	 */
+	if (s == NULL && cstate->is_vlan_vloffset) {
+		struct slist *s2;
+
+		if (cstate->off_linkpl.reg == -1)
+			cstate->off_linkpl.reg = alloc_reg(cstate);
+		if (cstate->off_linktype.reg == -1)
+			cstate->off_linktype.reg = alloc_reg(cstate);
+
+		s = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM);
+		s->s.k = 0;
+		s2 = new_stmt(cstate, BPF_ST);
+		s2->s.k = cstate->off_linkpl.reg;
+		sappend(s, s2);
+		s2 = new_stmt(cstate, BPF_ST);
+		s2->s.k = cstate->off_linktype.reg;
+		sappend(s, s2);
+	}
+
+	/*
+	 * 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(compiler_state_t *cstate)
+{
+	struct slist *s_load_dlt;
+	struct block *b;
+
+	if (cstate->linktype == DLT_PPI)
+	{
+		/* Create the statements that check for the DLT
+		 */
+		s_load_dlt = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS);
+		s_load_dlt->s.k = 4;
+
+		b = new_block(cstate, JMP(BPF_JEQ));
+
+		b->stmts = s_load_dlt;
+		b->s.k = SWAPLONG(DLT_IEEE802_11);
+	}
+	else
+	{
+		b = NULL;
+	}
+
+	return b;
+}
+
+/*
+ * Take an absolute offset, and:
+ *
+ *    if it has no variable part, return NULL;
+ *
+ *    if it has a variable part, generate code to load the register
+ *    containing that variable part into the X register, returning
+ *    a pointer to that code - if no register for that offset has
+ *    been allocated, allocate it first.
+ *
+ * (The code to set that register will be generated later, but will
+ * be placed earlier in the code sequence.)
+ */
+static struct slist *
+gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off)
+{
+	struct slist *s;
+
+	if (off->is_variable) {
+		if (off->reg == -1) {
+			/*
+			 * We haven't yet assigned a register for the
+			 * variable part of the offset of the link-layer
+			 * header; allocate one.
+			 */
+			off->reg = alloc_reg(cstate);
+		}
+
+		/*
+		 * Load the register containing the variable part of the
+		 * offset of the link-layer header into the X register.
+		 */
+		s = new_stmt(cstate, BPF_LDX|BPF_MEM);
+		s->s.k = off->reg;
+		return s;
+	} else {
+		/*
+		 * That offset isn't variable, there's no variable part,
+		 * so we don't need to generate any code.
+		 */
+		return NULL;
+	}
+}
+
+/*
+ * Map an Ethernet type to the equivalent PPP type.
+ */
+static bpf_u_int32
+ethertype_to_ppptype(bpf_u_int32 ll_proto)
+{
+	switch (ll_proto) {
+
+	case ETHERTYPE_IP:
+		ll_proto = PPP_IP;
+		break;
+
+	case ETHERTYPE_IPV6:
+		ll_proto = PPP_IPV6;
+		break;
+
+	case ETHERTYPE_DN:
+		ll_proto = PPP_DECNET;
+		break;
+
+	case ETHERTYPE_ATALK:
+		ll_proto = PPP_APPLE;
+		break;
+
+	case ETHERTYPE_NS:
+		ll_proto = PPP_NS;
+		break;
+
+	case LLCSAP_ISONS:
+		ll_proto = PPP_OSI;
+		break;
+
+	case LLCSAP_8021D:
+		/*
+		 * I'm assuming the "Bridging PDU"s that go
+		 * over PPP are Spanning Tree Protocol
+		 * Bridging PDUs.
+		 */
+		ll_proto = PPP_BRPDU;
+		break;
+
+	case LLCSAP_IPX:
+		ll_proto = PPP_IPX;
+		break;
+	}
+	return (ll_proto);
+}
+
+/*
+ * Generate any tests that, for encapsulation of a link-layer packet
+ * inside another protocol stack, need to be done to check for those
+ * link-layer packets (and that haven't already been done by a check
+ * for that encapsulation).
+ */
+static struct block *
+gen_prevlinkhdr_check(compiler_state_t *cstate)
+{
+	struct block *b0;
+
+	if (cstate->is_geneve)
+		return gen_geneve_ll_check(cstate);
+
+	switch (cstate->prevlinktype) {
+
+	case DLT_SUNATM:
+		/*
+		 * This is LANE-encapsulated Ethernet; check that the LANE
+		 * packet doesn't begin with an LE Control marker, i.e.
+		 * that it's data, not a control message.
+		 *
+		 * (We've already generated a test for LANE.)
+		 */
+		b0 = gen_cmp(cstate, OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00);
+		gen_not(b0);
+		return b0;
+
+	default:
+		/*
+		 * No such tests are necessary.
+		 */
+		return NULL;
+	}
+	/*NOTREACHED*/
+}
+
+/*
+ * The three different values we should check for when checking for an
+ * IPv6 packet with DLT_NULL.
+ */
+#define BSD_AFNUM_INET6_BSD	24	/* NetBSD, OpenBSD, BSD/OS, Npcap */
+#define BSD_AFNUM_INET6_FREEBSD	28	/* FreeBSD */
+#define BSD_AFNUM_INET6_DARWIN	30	/* macOS, iOS, other Darwin-based OSes */
+
+/*
+ * Generate code to match a particular packet type by matching the
+ * link-layer type field or fields in the 802.2 LLC header.
+ *
+ * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU.
+ */
+static struct block *
+gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+	struct block *b0, *b1, *b2;
+	const char *description;
+
+	/* are we checking MPLS-encapsulated packets? */
+	if (cstate->label_stack_depth > 0)
+		return gen_mpls_linktype(cstate, ll_proto);
+
+	switch (cstate->linktype) {
+
+	case DLT_EN10MB:
+	case DLT_NETANALYZER:
+	case DLT_NETANALYZER_TRANSPARENT:
+		/* Geneve has an EtherType regardless of whether there is an
+		 * L2 header. */
+		if (!cstate->is_geneve)
+			b0 = gen_prevlinkhdr_check(cstate);
+		else
+			b0 = NULL;
+
+		b1 = gen_ether_linktype(cstate, ll_proto);
+		if (b0 != NULL)
+			gen_and(b0, b1);
+		return b1;
+		/*NOTREACHED*/
+
+	case DLT_C_HDLC:
+		switch (ll_proto) {
+
+		case LLCSAP_ISONS:
+			ll_proto = (ll_proto << 8 | LLCSAP_ISONS);
+			/* fall through */
+
+		default:
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+			/*NOTREACHED*/
+		}
+
+	case DLT_IEEE802_11:
+	case DLT_PRISM_HEADER:
+	case DLT_IEEE802_11_RADIO_AVS:
+	case DLT_IEEE802_11_RADIO:
+	case DLT_PPI:
+		/*
+		 * Check that we have a data frame.
+		 */
+		b0 = gen_check_802_11_data_frame(cstate);
+
+		/*
+		 * Now check for the specified link-layer type.
+		 */
+		b1 = gen_llc_linktype(cstate, ll_proto);
+		gen_and(b0, b1);
+		return b1;
+		/*NOTREACHED*/
+
+	case DLT_FDDI:
+		/*
+		 * XXX - check for LLC frames.
+		 */
+		return gen_llc_linktype(cstate, ll_proto);
+		/*NOTREACHED*/
+
+	case DLT_IEEE802:
+		/*
+		 * XXX - check for LLC PDUs, as per IEEE 802.5.
+		 */
+		return gen_llc_linktype(cstate, ll_proto);
+		/*NOTREACHED*/
+
+	case DLT_ATM_RFC1483:
+	case DLT_ATM_CLIP:
+	case DLT_IP_OVER_FC:
+		return gen_llc_linktype(cstate, ll_proto);
+		/*NOTREACHED*/
+
+	case DLT_SUNATM:
+		/*
+		 * Check for an LLC-encapsulated version of this protocol;
+		 * if we were checking for LANE, linktype would no longer
+		 * be DLT_SUNATM.
+		 *
+		 * Check for LLC encapsulation and then check the protocol.
+		 */
+		b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+		b1 = gen_llc_linktype(cstate, ll_proto);
+		gen_and(b0, b1);
+		return b1;
+		/*NOTREACHED*/
+
+	case DLT_LINUX_SLL:
+		return gen_linux_sll_linktype(cstate, ll_proto);
+		/*NOTREACHED*/
+
+	case DLT_SLIP:
+	case DLT_SLIP_BSDOS:
+	case DLT_RAW:
+		/*
+		 * These types don't provide any type field; packets
+		 * are always IPv4 or IPv6.
+		 *
+		 * XXX - for IPv4, check for a version number of 4, and,
+		 * for IPv6, check for a version number of 6?
+		 */
+		switch (ll_proto) {
+
+		case ETHERTYPE_IP:
+			/* Check for a version number of 4. */
+			return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x40, 0xF0);
+
+		case ETHERTYPE_IPV6:
+			/* Check for a version number of 6. */
+			return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x60, 0xF0);
+
+		default:
+			return gen_false(cstate);	/* always false */
+		}
+		/*NOTREACHED*/
+
+	case DLT_IPV4:
+		/*
+		 * Raw IPv4, so no type field.
+		 */
+		if (ll_proto == ETHERTYPE_IP)
+			return gen_true(cstate);	/* always true */
+
+		/* Checking for something other than IPv4; always false */
+		return gen_false(cstate);
+		/*NOTREACHED*/
+
+	case DLT_IPV6:
+		/*
+		 * Raw IPv6, so no type field.
+		 */
+		if (ll_proto == ETHERTYPE_IPV6)
+			return gen_true(cstate);	/* always true */
+
+		/* Checking for something other than IPv6; always false */
+		return gen_false(cstate);
+		/*NOTREACHED*/
+
+	case DLT_PPP:
+	case DLT_PPP_PPPD:
+	case DLT_PPP_SERIAL:
+	case DLT_PPP_ETHER:
+		/*
+		 * We use Ethernet protocol types inside libpcap;
+		 * map them to the corresponding PPP protocol types.
+		 */
+		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
+		    ethertype_to_ppptype(ll_proto));
+		/*NOTREACHED*/
+
+	case DLT_PPP_BSDOS:
+		/*
+		 * We use Ethernet protocol types inside libpcap;
+		 * map them to the corresponding PPP protocol types.
+		 */
+		switch (ll_proto) {
+
+		case ETHERTYPE_IP:
+			/*
+			 * Also check for Van Jacobson-compressed IP.
+			 * XXX - do this for other forms of PPP?
+			 */
+			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_IP);
+			b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJC);
+			gen_or(b0, b1);
+			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJNC);
+			gen_or(b1, b0);
+			return b0;
+
+		default:
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
+			    ethertype_to_ppptype(ll_proto));
+		}
+		/*NOTREACHED*/
+
+	case DLT_NULL:
+	case DLT_LOOP:
+	case DLT_ENC:
+		switch (ll_proto) {
+
+		case ETHERTYPE_IP:
+			return (gen_loopback_linktype(cstate, AF_INET));
+
+		case ETHERTYPE_IPV6:
+			/*
+			 * AF_ values may, unfortunately, be platform-
+			 * dependent; AF_INET isn't, because everybody
+			 * used 4.2BSD's value, but AF_INET6 is, because
+			 * 4.2BSD didn't have a value for it (given that
+			 * IPv6 didn't exist back in the early 1980's),
+			 * and they all picked their own values.
+			 *
+			 * This means that, if we're reading from a
+			 * savefile, we need to check for all the
+			 * possible values.
+			 *
+			 * If we're doing a live capture, we only need
+			 * to check for this platform's value; however,
+			 * Npcap uses 24, which isn't Windows's AF_INET6
+			 * value.  (Given the multiple different values,
+			 * programs that read pcap files shouldn't be
+			 * checking for their platform's AF_INET6 value
+			 * anyway, they should check for all of the
+			 * possible values. and they might as well do
+			 * that even for live captures.)
+			 */
+			if (cstate->bpf_pcap->rfile != NULL) {
+				/*
+				 * Savefile - check for all three
+				 * possible IPv6 values.
+				 */
+				b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_BSD);
+				b1 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_FREEBSD);
+				gen_or(b0, b1);
+				b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_DARWIN);
+				gen_or(b0, b1);
+				return (b1);
+			} else {
+				/*
+				 * Live capture, so we only need to
+				 * check for the value used on this
+				 * platform.
+				 */
+#ifdef _WIN32
+				/*
+				 * Npcap doesn't use Windows's AF_INET6,
+				 * as that collides with AF_IPX on
+				 * some BSDs (both have the value 23).
+				 * Instead, it uses 24.
+				 */
+				return (gen_loopback_linktype(cstate, 24));
+#else /* _WIN32 */
+#ifdef AF_INET6
+				return (gen_loopback_linktype(cstate, AF_INET6));
+#else /* AF_INET6 */
+				/*
+				 * I guess this platform doesn't support
+				 * IPv6, so we just reject all packets.
+				 */
+				return gen_false(cstate);
+#endif /* AF_INET6 */
+#endif /* _WIN32 */
+			}
+
+		default:
+			/*
+			 * Not a type on which we support filtering.
+			 * XXX - support those that have AF_ values
+			 * #defined on this platform, at least?
+			 */
+			return gen_false(cstate);
+		}
+
+#ifdef HAVE_NET_PFVAR_H
+	case DLT_PFLOG:
+		/*
+		 * af field is host byte order in contrast to the rest of
+		 * the packet.
+		 */
+		if (ll_proto == ETHERTYPE_IP)
+			return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
+			    BPF_B, AF_INET));
+		else if (ll_proto == ETHERTYPE_IPV6)
+			return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
+			    BPF_B, AF_INET6));
+		else
+			return gen_false(cstate);
+		/*NOTREACHED*/
+#endif /* HAVE_NET_PFVAR_H */
+
+	case DLT_ARCNET:
+	case DLT_ARCNET_LINUX:
+		/*
+		 * XXX should we check for first fragment if the protocol
+		 * uses PHDS?
+		 */
+		switch (ll_proto) {
+
+		default:
+			return gen_false(cstate);
+
+		case ETHERTYPE_IPV6:
+			return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+				ARCTYPE_INET6));
+
+		case ETHERTYPE_IP:
+			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+			    ARCTYPE_IP);
+			b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+			    ARCTYPE_IP_OLD);
+			gen_or(b0, b1);
+			return (b1);
+
+		case ETHERTYPE_ARP:
+			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+			    ARCTYPE_ARP);
+			b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+			    ARCTYPE_ARP_OLD);
+			gen_or(b0, b1);
+			return (b1);
+
+		case ETHERTYPE_REVARP:
+			return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+			    ARCTYPE_REVARP));
+
+		case ETHERTYPE_ATALK:
+			return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+			    ARCTYPE_ATALK));
+		}
+		/*NOTREACHED*/
+
+	case DLT_LTALK:
+		switch (ll_proto) {
+		case ETHERTYPE_ATALK:
+			return gen_true(cstate);
+		default:
+			return gen_false(cstate);
+		}
+		/*NOTREACHED*/
+
+	case DLT_FRELAY:
+		/*
+		 * XXX - assumes a 2-byte Frame Relay header with
+		 * DLCI and flags.  What if the address is longer?
+		 */
+		switch (ll_proto) {
+
+		case ETHERTYPE_IP:
+			/*
+			 * Check for the special NLPID for IP.
+			 */
+			return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0xcc);
+
+		case ETHERTYPE_IPV6:
+			/*
+			 * Check for the special NLPID for IPv6.
+			 */
+			return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e);
+
+		case LLCSAP_ISONS:
+			/*
+			 * Check for several OSI protocols.
+			 *
+			 * Frame Relay packets typically have an OSI
+			 * NLPID at the beginning; we check for each
+			 * of them.
+			 *
+			 * What we check for is the NLPID and a frame
+			 * control field of UI, i.e. 0x03 followed
+			 * by the NLPID.
+			 */
+			b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO8473_CLNP);
+			b1 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO9542_ESIS);
+			b2 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO10589_ISIS);
+			gen_or(b1, b2);
+			gen_or(b0, b2);
+			return b2;
+
+		default:
+			return gen_false(cstate);
+		}
+		/*NOTREACHED*/
+
+	case DLT_MFR:
+		bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented");
+
+        case DLT_JUNIPER_MFR:
+        case DLT_JUNIPER_MLFR:
+        case DLT_JUNIPER_MLPPP:
+	case DLT_JUNIPER_ATM1:
+	case DLT_JUNIPER_ATM2:
+	case DLT_JUNIPER_PPPOE:
+	case DLT_JUNIPER_PPPOE_ATM:
+        case DLT_JUNIPER_GGSN:
+        case DLT_JUNIPER_ES:
+        case DLT_JUNIPER_MONITOR:
+        case DLT_JUNIPER_SERVICES:
+        case DLT_JUNIPER_ETHER:
+        case DLT_JUNIPER_PPP:
+        case DLT_JUNIPER_FRELAY:
+        case DLT_JUNIPER_CHDLC:
+        case DLT_JUNIPER_VP:
+        case DLT_JUNIPER_ST:
+        case DLT_JUNIPER_ISM:
+        case DLT_JUNIPER_VS:
+        case DLT_JUNIPER_SRX_E2E:
+        case DLT_JUNIPER_FIBRECHANNEL:
+	case DLT_JUNIPER_ATM_CEMIC:
+
+		/* just lets verify the magic number for now -
+		 * on ATM we may have up to 6 different encapsulations on the wire
+		 * and need a lot of heuristics to figure out that the payload
+		 * might be;
+		 *
+		 * FIXME encapsulation specific BPF_ filters
+		 */
+		return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */
+
+	case DLT_BACNET_MS_TP:
+		return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000);
+
+	case DLT_IPNET:
+		return gen_ipnet_linktype(cstate, ll_proto);
+
+	case DLT_LINUX_IRDA:
+		bpf_error(cstate, "IrDA link-layer type filtering not implemented");
+
+	case DLT_DOCSIS:
+		bpf_error(cstate, "DOCSIS link-layer type filtering not implemented");
+
+	case DLT_MTP2:
+	case DLT_MTP2_WITH_PHDR:
+		bpf_error(cstate, "MTP2 link-layer type filtering not implemented");
+
+	case DLT_ERF:
+		bpf_error(cstate, "ERF link-layer type filtering not implemented");
+
+	case DLT_PFSYNC:
+		bpf_error(cstate, "PFSYNC link-layer type filtering not implemented");
+
+	case DLT_LINUX_LAPD:
+		bpf_error(cstate, "LAPD link-layer type filtering not implemented");
+
+	case DLT_USB_FREEBSD:
+	case DLT_USB_LINUX:
+	case DLT_USB_LINUX_MMAPPED:
+	case DLT_USBPCAP:
+		bpf_error(cstate, "USB link-layer type filtering not implemented");
+
+	case DLT_BLUETOOTH_HCI_H4:
+	case DLT_BLUETOOTH_HCI_H4_WITH_PHDR:
+		bpf_error(cstate, "Bluetooth link-layer type filtering not implemented");
+
+	case DLT_CAN20B:
+	case DLT_CAN_SOCKETCAN:
+		bpf_error(cstate, "CAN link-layer type filtering not implemented");
+
+	case DLT_IEEE802_15_4:
+	case DLT_IEEE802_15_4_LINUX:
+	case DLT_IEEE802_15_4_NONASK_PHY:
+	case DLT_IEEE802_15_4_NOFCS:
+	case DLT_IEEE802_15_4_TAP:
+		bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented");
+
+	case DLT_IEEE802_16_MAC_CPS_RADIO:
+		bpf_error(cstate, "IEEE 802.16 link-layer type filtering not implemented");
+
+	case DLT_SITA:
+		bpf_error(cstate, "SITA link-layer type filtering not implemented");
+
+	case DLT_RAIF1:
+		bpf_error(cstate, "RAIF1 link-layer type filtering not implemented");
+
+	case DLT_IPMB_KONTRON:
+	case DLT_IPMB_LINUX:
+		bpf_error(cstate, "IPMB link-layer type filtering not implemented");
+
+	case DLT_AX25_KISS:
+		bpf_error(cstate, "AX.25 link-layer type filtering not implemented");
+
+	case DLT_NFLOG:
+		/* Using the fixed-size NFLOG header it is possible to tell only
+		 * the address family of the packet, other meaningful data is
+		 * either missing or behind TLVs.
+		 */
+		bpf_error(cstate, "NFLOG link-layer type filtering not implemented");
+
+	default:
+		/*
+		 * Does this link-layer header type have a field
+		 * indicating the type of the next protocol?  If
+		 * so, off_linktype.constant_part will be the offset of that
+		 * field in the packet; if not, it will be OFFSET_NOT_SET.
+		 */
+		if (cstate->off_linktype.constant_part != OFFSET_NOT_SET) {
+			/*
+			 * Yes; assume it's an Ethernet type.  (If
+			 * it's not, it needs to be handled specially
+			 * above.)
+			 */
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+			/*NOTREACHED */
+		} else {
+			/*
+			 * No; report an error.
+			 */
+			description = pcap_datalink_val_to_description_or_dlt(cstate->linktype);
+			bpf_error(cstate, "%s link-layer type filtering not implemented",
+			    description);
+			/*NOTREACHED */
+		}
+	}
+}
+
+/*
+ * Check for an LLC SNAP packet with a given organization code and
+ * protocol type; we check the entire contents of the 802.2 LLC and
+ * snap headers, checking for DSAP and SSAP of SNAP and a control
+ * field of 0x03 in the LLC header, and for the specified organization
+ * code and protocol type in the SNAP header.
+ */
+static struct block *
+gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype)
+{
+	u_char snapblock[8];
+
+	snapblock[0] = LLCSAP_SNAP;		/* DSAP = SNAP */
+	snapblock[1] = LLCSAP_SNAP;		/* SSAP = SNAP */
+	snapblock[2] = 0x03;			/* control = UI */
+	snapblock[3] = (u_char)(orgcode >> 16);	/* upper 8 bits of organization code */
+	snapblock[4] = (u_char)(orgcode >> 8);	/* middle 8 bits of organization code */
+	snapblock[5] = (u_char)(orgcode >> 0);	/* lower 8 bits of organization code */
+	snapblock[6] = (u_char)(ptype >> 8);	/* upper 8 bits of protocol type */
+	snapblock[7] = (u_char)(ptype >> 0);	/* lower 8 bits of protocol type */
+	return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock);
+}
+
+/*
+ * Generate code to match frames with an LLC header.
+ */
+static struct block *
+gen_llc_internal(compiler_state_t *cstate)
+{
+	struct block *b0, *b1;
+
+	switch (cstate->linktype) {
+
+	case DLT_EN10MB:
+		/*
+		 * We check for an Ethernet type field less than
+		 * 1500, which means it's an 802.3 length field.
+		 */
+		b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+		gen_not(b0);
+
+		/*
+		 * Now check for the purported DSAP and SSAP not being
+		 * 0xFF, to rule out NetWare-over-802.3.
+		 */
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
+		gen_not(b1);
+		gen_and(b0, b1);
+		return b1;
+
+	case DLT_SUNATM:
+		/*
+		 * We check for LLC traffic.
+		 */
+		b0 = gen_atmtype_llc(cstate);
+		return b0;
+
+	case DLT_IEEE802:	/* Token Ring */
+		/*
+		 * XXX - check for LLC frames.
+		 */
+		return gen_true(cstate);
+
+	case DLT_FDDI:
+		/*
+		 * XXX - check for LLC frames.
+		 */
+		return gen_true(cstate);
+
+	case DLT_ATM_RFC1483:
+		/*
+		 * For LLC encapsulation, these are defined to have an
+		 * 802.2 LLC header.
+		 *
+		 * For VC encapsulation, they don't, but there's no
+		 * way to check for that; the protocol used on the VC
+		 * is negotiated out of band.
+		 */
+		return gen_true(cstate);
+
+	case DLT_IEEE802_11:
+	case DLT_PRISM_HEADER:
+	case DLT_IEEE802_11_RADIO:
+	case DLT_IEEE802_11_RADIO_AVS:
+	case DLT_PPI:
+		/*
+		 * Check that we have a data frame.
+		 */
+		b0 = gen_check_802_11_data_frame(cstate);
+		return b0;
+
+	default:
+		bpf_error(cstate, "'llc' not supported for %s",
+			  pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+		/*NOTREACHED*/
+	}
+}
+
+struct block *
+gen_llc(compiler_state_t *cstate)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	return gen_llc_internal(cstate);
+}
+
+struct block *
+gen_llc_i(compiler_state_t *cstate)
+{
+	struct block *b0, *b1;
+	struct slist *s;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Check whether this is an LLC frame.
+	 */
+	b0 = gen_llc_internal(cstate);
+
+	/*
+	 * Load the control byte and test the low-order bit; it must
+	 * be clear for I frames.
+	 */
+	s = gen_load_a(cstate, OR_LLC, 2, BPF_B);
+	b1 = new_block(cstate, JMP(BPF_JSET));
+	b1->s.k = 0x01;
+	b1->stmts = s;
+	gen_not(b1);
+	gen_and(b0, b1);
+	return b1;
+}
+
+struct block *
+gen_llc_s(compiler_state_t *cstate)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Check whether this is an LLC frame.
+	 */
+	b0 = gen_llc_internal(cstate);
+
+	/*
+	 * Now compare the low-order 2 bit of the control byte against
+	 * the appropriate value for S frames.
+	 */
+	b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_S_FMT, 0x03);
+	gen_and(b0, b1);
+	return b1;
+}
+
+struct block *
+gen_llc_u(compiler_state_t *cstate)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Check whether this is an LLC frame.
+	 */
+	b0 = gen_llc_internal(cstate);
+
+	/*
+	 * Now compare the low-order 2 bit of the control byte against
+	 * the appropriate value for U frames.
+	 */
+	b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_U_FMT, 0x03);
+	gen_and(b0, b1);
+	return b1;
+}
+
+struct block *
+gen_llc_s_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Check whether this is an LLC frame.
+	 */
+	b0 = gen_llc_internal(cstate);
+
+	/*
+	 * Now check for an S frame with the appropriate type.
+	 */
+	b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_S_CMD_MASK);
+	gen_and(b0, b1);
+	return b1;
+}
+
+struct block *
+gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Check whether this is an LLC frame.
+	 */
+	b0 = gen_llc_internal(cstate);
+
+	/*
+	 * Now check for a U frame with the appropriate type.
+	 */
+	b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_U_CMD_MASK);
+	gen_and(b0, b1);
+	return b1;
+}
+
+/*
+ * Generate code to match a particular packet type, for link-layer types
+ * using 802.2 LLC headers.
+ *
+ * This is *NOT* used for Ethernet; "gen_ether_linktype()" is used
+ * for that - it handles the D/I/X Ethernet vs. 802.3+802.2 issues.
+ *
+ * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU.  We use that to determine whether to
+ * match the DSAP or both DSAP and LSAP or to check the OUI and
+ * protocol ID in a SNAP header.
+ */
+static struct block *
+gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+	/*
+	 * XXX - handle token-ring variable-length header.
+	 */
+	switch (ll_proto) {
+
+	case LLCSAP_IP:
+	case LLCSAP_ISONS:
+	case LLCSAP_NETBEUI:
+		/*
+		 * XXX - should we check both the DSAP and the
+		 * SSAP, like this, or should we check just the
+		 * DSAP, as we do for other SAP values?
+		 */
+		return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32)
+			     ((ll_proto << 8) | ll_proto));
+
+	case LLCSAP_IPX:
+		/*
+		 * XXX - are there ever SNAP frames for IPX on
+		 * non-Ethernet 802.x networks?
+		 */
+		return gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+
+	case ETHERTYPE_ATALK:
+		/*
+		 * 802.2-encapsulated ETHERTYPE_ATALK packets are
+		 * SNAP packets with an organization code of
+		 * 0x080007 (Apple, for Appletalk) and a protocol
+		 * type of ETHERTYPE_ATALK (Appletalk).
+		 *
+		 * XXX - check for an organization code of
+		 * encapsulated Ethernet as well?
+		 */
+		return gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
+
+	default:
+		/*
+		 * XXX - we don't have to check for IPX 802.3
+		 * here, but should we check for the IPX Ethertype?
+		 */
+		if (ll_proto <= ETHERMTU) {
+			/*
+			 * This is an LLC SAP value, so check
+			 * the DSAP.
+			 */
+			return gen_cmp(cstate, OR_LLC, 0, BPF_B, ll_proto);
+		} else {
+			/*
+			 * This is an Ethernet type; we assume that it's
+			 * unlikely that it'll appear in the right place
+			 * at random, and therefore check only the
+			 * location that would hold the Ethernet type
+			 * in a SNAP frame with an organization code of
+			 * 0x000000 (encapsulated Ethernet).
+			 *
+			 * XXX - if we were to check for the SNAP DSAP and
+			 * LSAP, as per XXX, and were also to check for an
+			 * organization code of 0x000000 (encapsulated
+			 * Ethernet), we'd do
+			 *
+			 *	return gen_snap(cstate, 0x000000, ll_proto);
+			 *
+			 * here; for now, we don't, as per the above.
+			 * I don't know whether it's worth the extra CPU
+			 * time to do the right check or not.
+			 */
+			return gen_cmp(cstate, OR_LLC, 6, BPF_H, ll_proto);
+		}
+	}
+}
+
+static struct block *
+gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
+    int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off)
+{
+	struct block *b0, *b1;
+	u_int offset;
+
+	switch (dir) {
+
+	case Q_SRC:
+		offset = src_off;
+		break;
+
+	case Q_DST:
+		offset = dst_off;
+		break;
+
+	case Q_AND:
+		b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+		b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+		b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	default:
+		abort();
+		/*NOTREACHED*/
+	}
+	b0 = gen_linktype(cstate, ll_proto);
+	b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask);
+	gen_and(b0, b1);
+	return b1;
+}
+
+#ifdef INET6
+static struct block *
+gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
+    struct in6_addr *mask, int dir, bpf_u_int32 ll_proto, u_int src_off,
+    u_int dst_off)
+{
+	struct block *b0, *b1;
+	u_int offset;
+	uint32_t *a, *m;
+
+	switch (dir) {
+
+	case Q_SRC:
+		offset = src_off;
+		break;
+
+	case Q_DST:
+		offset = dst_off;
+		break;
+
+	case Q_AND:
+		b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+		b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+		b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	default:
+		abort();
+		/*NOTREACHED*/
+	}
+	/* this order is important */
+	a = (uint32_t *)addr;
+	m = (uint32_t *)mask;
+	b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
+	b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
+	gen_and(b0, b1);
+	b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1]));
+	gen_and(b0, b1);
+	b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
+	gen_and(b0, b1);
+	b0 = gen_linktype(cstate, ll_proto);
+	gen_and(b0, b1);
+	return b1;
+}
+#endif
+
+static struct block *
+gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+	register struct block *b0, *b1;
+
+	switch (dir) {
+	case Q_SRC:
+		return gen_bcmp(cstate, OR_LINKHDR, 6, 6, eaddr);
+
+	case Q_DST:
+		return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr);
+
+	case Q_AND:
+		b0 = gen_ehostop(cstate, eaddr, Q_SRC);
+		b1 = gen_ehostop(cstate, eaddr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_ehostop(cstate, eaddr, Q_SRC);
+		b1 = gen_ehostop(cstate, eaddr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers");
+		/*NOTREACHED*/
+	}
+	abort();
+	/*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for DLT_FDDI
+ */
+static struct block *
+gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+	struct block *b0, *b1;
+
+	switch (dir) {
+	case Q_SRC:
+		return gen_bcmp(cstate, OR_LINKHDR, 6 + 1 + cstate->pcap_fddipad, 6, eaddr);
+
+	case Q_DST:
+		return gen_bcmp(cstate, OR_LINKHDR, 0 + 1 + cstate->pcap_fddipad, 6, eaddr);
+
+	case Q_AND:
+		b0 = gen_fhostop(cstate, eaddr, Q_SRC);
+		b1 = gen_fhostop(cstate, eaddr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_fhostop(cstate, eaddr, Q_SRC);
+		b1 = gen_fhostop(cstate, eaddr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is only supported on 802.11");
+		/*NOTREACHED*/
+	}
+	abort();
+	/*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for DLT_IEEE802 (Token Ring)
+ */
+static struct block *
+gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+	register struct block *b0, *b1;
+
+	switch (dir) {
+	case Q_SRC:
+		return gen_bcmp(cstate, OR_LINKHDR, 8, 6, eaddr);
+
+	case Q_DST:
+		return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr);
+
+	case Q_AND:
+		b0 = gen_thostop(cstate, eaddr, Q_SRC);
+		b1 = gen_thostop(cstate, eaddr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_thostop(cstate, eaddr, Q_SRC);
+		b1 = gen_thostop(cstate, eaddr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is only supported on 802.11");
+		/*NOTREACHED*/
+	}
+	abort();
+	/*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and
+ * various 802.11 + radio headers.
+ */
+static struct block *
+gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+	register struct block *b0, *b1, *b2;
+	register struct slist *s;
+
+#ifdef ENABLE_WLAN_FILTERING_PATCH
+	/*
+	 * TODO GV 20070613
+	 * We need to disable the optimizer because the optimizer is buggy
+	 * and wipes out some LD instructions generated by the below
+	 * code to validate the Frame Control bits
+	 */
+	cstate->no_optimize = 1;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
+
+	switch (dir) {
+	case Q_SRC:
+		/*
+		 * Oh, yuk.
+		 *
+		 *	For control frames, there is no SA.
+		 *
+		 *	For management frames, SA is at an
+		 *	offset of 10 from the beginning of
+		 *	the packet.
+		 *
+		 *	For data frames, SA is at an offset
+		 *	of 10 from the beginning of the packet
+		 *	if From DS is clear, at an offset of
+		 *	16 from the beginning of the packet
+		 *	if From DS is set and To DS is clear,
+		 *	and an offset of 24 from the beginning
+		 *	of the packet if From DS is set and To DS
+		 *	is set.
+		 */
+
+		/*
+		 * Generate the tests to be done for data frames
+		 * with From DS set.
+		 *
+		 * First, check for To DS set, i.e. check "link[1] & 0x01".
+		 */
+		s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+		b1 = new_block(cstate, JMP(BPF_JSET));
+		b1->s.k = 0x01;	/* To DS */
+		b1->stmts = s;
+
+		/*
+		 * If To DS is set, the SA is at 24.
+		 */
+		b0 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
+		gen_and(b1, b0);
+
+		/*
+		 * Now, check for To DS not set, i.e. check
+		 * "!(link[1] & 0x01)".
+		 */
+		s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+		b2 = new_block(cstate, JMP(BPF_JSET));
+		b2->s.k = 0x01;	/* To DS */
+		b2->stmts = s;
+		gen_not(b2);
+
+		/*
+		 * If To DS is not set, the SA is at 16.
+		 */
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+		gen_and(b2, b1);
+
+		/*
+		 * Now OR together the last two checks.  That gives
+		 * the complete set of checks for data frames with
+		 * From DS set.
+		 */
+		gen_or(b1, b0);
+
+		/*
+		 * Now check for From DS being set, and AND that with
+		 * the ORed-together checks.
+		 */
+		s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+		b1 = new_block(cstate, JMP(BPF_JSET));
+		b1->s.k = 0x02;	/* From DS */
+		b1->stmts = s;
+		gen_and(b1, b0);
+
+		/*
+		 * Now check for data frames with From DS not set.
+		 */
+		s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+		b2 = new_block(cstate, JMP(BPF_JSET));
+		b2->s.k = 0x02;	/* From DS */
+		b2->stmts = s;
+		gen_not(b2);
+
+		/*
+		 * If From DS isn't set, the SA is at 10.
+		 */
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+		gen_and(b2, b1);
+
+		/*
+		 * Now OR together the checks for data frames with
+		 * From DS not set and for data frames with From DS
+		 * set; that gives the checks done for data frames.
+		 */
+		gen_or(b1, b0);
+
+		/*
+		 * Now check for a data frame.
+		 * I.e, check "link[0] & 0x08".
+		 */
+		s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+		b1 = new_block(cstate, JMP(BPF_JSET));
+		b1->s.k = 0x08;
+		b1->stmts = s;
+
+		/*
+		 * 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(cstate, OR_LINKHDR, 0, BPF_B);
+		b2 = new_block(cstate, JMP(BPF_JSET));
+		b2->s.k = 0x08;
+		b2->stmts = s;
+		gen_not(b2);
+
+		/*
+		 * For management frames, the SA is at 10.
+		 */
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+		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(cstate, OR_LINKHDR, 0, BPF_B);
+		b1 = new_block(cstate, 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 Q_DST:
+		/*
+		 * 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(cstate, OR_LINKHDR, 1, BPF_B);
+		b1 = new_block(cstate, JMP(BPF_JSET));
+		b1->s.k = 0x01;	/* To DS */
+		b1->stmts = s;
+
+		/*
+		 * If To DS is set, the DA is at 16.
+		 */
+		b0 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+		gen_and(b1, b0);
+
+		/*
+		 * Now, check for To DS not set, i.e. check
+		 * "!(link[1] & 0x01)".
+		 */
+		s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+		b2 = new_block(cstate, JMP(BPF_JSET));
+		b2->s.k = 0x01;	/* To DS */
+		b2->stmts = s;
+		gen_not(b2);
+
+		/*
+		 * If To DS is not set, the DA is at 4.
+		 */
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr);
+		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(cstate, OR_LINKHDR, 0, BPF_B);
+		b1 = new_block(cstate, 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(cstate, OR_LINKHDR, 0, BPF_B);
+		b2 = new_block(cstate, JMP(BPF_JSET));
+		b2->s.k = 0x08;
+		b2->stmts = s;
+		gen_not(b2);
+
+		/*
+		 * For management frames, the DA is at 4.
+		 */
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr);
+		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(cstate, OR_LINKHDR, 0, BPF_B);
+		b1 = new_block(cstate, 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 Q_AND:
+		b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
+		b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
+		b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+
+	/*
+	 * XXX - add BSSID keyword?
+	 */
+	case Q_ADDR1:
+		return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr));
+
+	case Q_ADDR2:
+		/*
+		 * Not present in CTS or ACK control frames.
+		 */
+		b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+			IEEE80211_FC0_TYPE_MASK);
+		gen_not(b0);
+		b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+			IEEE80211_FC0_SUBTYPE_MASK);
+		gen_not(b1);
+		b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+			IEEE80211_FC0_SUBTYPE_MASK);
+		gen_not(b2);
+		gen_and(b1, b2);
+		gen_or(b0, b2);
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+		gen_and(b2, b1);
+		return b1;
+
+	case Q_ADDR3:
+		/*
+		 * Not present in control frames.
+		 */
+		b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+			IEEE80211_FC0_TYPE_MASK);
+		gen_not(b0);
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_ADDR4:
+		/*
+		 * Present only if the direction mask has both "From DS"
+		 * and "To DS" set.  Neither control frames nor management
+		 * frames should have both of those set, so we don't
+		 * check the frame type.
+		 */
+		b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B,
+			IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK);
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_RA:
+		/*
+		 * Not present in management frames; addr1 in other
+		 * frames.
+		 */
+
+		/*
+		 * If the high-order bit of the type value is 0, this
+		 * is a management frame.
+		 * I.e, check "(link[0] & 0x08)".
+		 */
+		s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+		b1 = new_block(cstate, JMP(BPF_JSET));
+		b1->s.k = 0x08;
+		b1->stmts = s;
+
+		/*
+		 * Check addr1.
+		 */
+		b0 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr);
+
+		/*
+		 * AND that with the check of addr1.
+		 */
+		gen_and(b1, b0);
+		return (b0);
+
+	case Q_TA:
+		/*
+		 * Not present in management frames; addr2, if present,
+		 * in other frames.
+		 */
+
+		/*
+		 * Not present in CTS or ACK control frames.
+		 */
+		b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+			IEEE80211_FC0_TYPE_MASK);
+		gen_not(b0);
+		b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+			IEEE80211_FC0_SUBTYPE_MASK);
+		gen_not(b1);
+		b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+			IEEE80211_FC0_SUBTYPE_MASK);
+		gen_not(b2);
+		gen_and(b1, b2);
+		gen_or(b0, b2);
+
+		/*
+		 * 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(cstate, OR_LINKHDR, 0, BPF_B);
+		b1 = new_block(cstate, JMP(BPF_JSET));
+		b1->s.k = 0x08;
+		b1->stmts = s;
+
+		/*
+		 * AND that with the check for frames other than
+		 * CTS and ACK frames.
+		 */
+		gen_and(b1, b2);
+
+		/*
+		 * Check addr2.
+		 */
+		b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+		gen_and(b2, b1);
+		return b1;
+	}
+	abort();
+	/*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel.
+ * (We assume that the addresses are IEEE 48-bit MAC addresses,
+ * as the RFC states.)
+ */
+static struct block *
+gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+	register struct block *b0, *b1;
+
+	switch (dir) {
+	case Q_SRC:
+		return gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+
+	case Q_DST:
+		return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr);
+
+	case Q_AND:
+		b0 = gen_ipfchostop(cstate, eaddr, Q_SRC);
+		b1 = gen_ipfchostop(cstate, eaddr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_ipfchostop(cstate, eaddr, Q_SRC);
+		b1 = gen_ipfchostop(cstate, eaddr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is only supported on 802.11");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is only supported on 802.11");
+		/*NOTREACHED*/
+	}
+	abort();
+	/*NOTREACHED*/
+}
+
+/*
+ * This is quite tricky because there may be pad bytes in front of the
+ * DECNET header, and then there are two possible data packet formats that
+ * carry both src and dst addresses, plus 5 packet types in a format that
+ * carries only the src node, plus 2 types that use a different format and
+ * also carry just the src node.
+ *
+ * Yuck.
+ *
+ * Instead of doing those all right, we just look for data packets with
+ * 0 or 1 bytes of padding.  If you want to look at other packets, that
+ * will require a lot more hacking.
+ *
+ * To add support for filtering on DECNET "areas" (network numbers)
+ * one would want to add a "mask" argument to this routine.  That would
+ * make the filter even more inefficient, although one could be clever
+ * and not generate masking instructions if the mask is 0xFFFF.
+ */
+static struct block *
+gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir)
+{
+	struct block *b0, *b1, *b2, *tmp;
+	u_int offset_lh;	/* offset if long header is received */
+	u_int offset_sh;	/* offset if short header is received */
+
+	switch (dir) {
+
+	case Q_DST:
+		offset_sh = 1;	/* follows flags */
+		offset_lh = 7;	/* flgs,darea,dsubarea,HIORD */
+		break;
+
+	case Q_SRC:
+		offset_sh = 3;	/* follows flags, dstnode */
+		offset_lh = 15;	/* flgs,darea,dsubarea,did,sarea,ssub,HIORD */
+		break;
+
+	case Q_AND:
+		/* Inefficient because we do our Calvinball dance twice */
+		b0 = gen_dnhostop(cstate, addr, Q_SRC);
+		b1 = gen_dnhostop(cstate, addr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		/* Inefficient because we do our Calvinball dance twice */
+		b0 = gen_dnhostop(cstate, addr, Q_SRC);
+		b1 = gen_dnhostop(cstate, addr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+		/*NOTREACHED*/
+
+	default:
+		abort();
+		/*NOTREACHED*/
+	}
+	b0 = gen_linktype(cstate, ETHERTYPE_DN);
+	/* Check for pad = 1, long header case */
+	tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
+	    (bpf_u_int32)ntohs(0x0681), (bpf_u_int32)ntohs(0x07FF));
+	b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh,
+	    BPF_H, (bpf_u_int32)ntohs((u_short)addr));
+	gen_and(tmp, b1);
+	/* Check for pad = 0, long header case */
+	tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x06,
+	    (bpf_u_int32)0x7);
+	b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H,
+	    (bpf_u_int32)ntohs((u_short)addr));
+	gen_and(tmp, b2);
+	gen_or(b2, b1);
+	/* Check for pad = 1, short header case */
+	tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
+	    (bpf_u_int32)ntohs(0x0281), (bpf_u_int32)ntohs(0x07FF));
+	b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H,
+	    (bpf_u_int32)ntohs((u_short)addr));
+	gen_and(tmp, b2);
+	gen_or(b2, b1);
+	/* Check for pad = 0, short header case */
+	tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x02,
+	    (bpf_u_int32)0x7);
+	b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H,
+	    (bpf_u_int32)ntohs((u_short)addr));
+	gen_and(tmp, b2);
+	gen_or(b2, b1);
+
+	/* Combine with test for cstate->linktype */
+	gen_and(b0, b1);
+	return b1;
+}
+
+/*
+ * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets;
+ * test the bottom-of-stack bit, and then check the version number
+ * field in the IP header.
+ */
+static struct block *
+gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+	struct block *b0, *b1;
+
+        switch (ll_proto) {
+
+        case ETHERTYPE_IP:
+                /* match the bottom-of-stack bit */
+                b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
+                /* match the IPv4 version number */
+                b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0);
+                gen_and(b0, b1);
+                return b1;
+
+        case ETHERTYPE_IPV6:
+                /* match the bottom-of-stack bit */
+                b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
+                /* match the IPv4 version number */
+                b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0);
+                gen_and(b0, b1);
+                return b1;
+
+        default:
+               /* FIXME add other L3 proto IDs */
+               bpf_error(cstate, "unsupported protocol over mpls");
+               /*NOTREACHED*/
+        }
+}
+
+static struct block *
+gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
+    int proto, int dir, int type)
+{
+	struct block *b0, *b1;
+	const char *typestr;
+
+	if (type == Q_NET)
+		typestr = "net";
+	else
+		typestr = "host";
+
+	switch (proto) {
+
+	case Q_DEFAULT:
+		b0 = gen_host(cstate, addr, mask, Q_IP, dir, type);
+		/*
+		 * Only check for non-IPv4 addresses if we're not
+		 * checking MPLS-encapsulated packets.
+		 */
+		if (cstate->label_stack_depth == 0) {
+			b1 = gen_host(cstate, addr, mask, Q_ARP, dir, type);
+			gen_or(b0, b1);
+			b0 = gen_host(cstate, addr, mask, Q_RARP, dir, type);
+			gen_or(b1, b0);
+		}
+		return b0;
+
+	case Q_LINK:
+		bpf_error(cstate, "link-layer modifier applied to %s", typestr);
+
+	case Q_IP:
+		return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16);
+
+	case Q_RARP:
+		return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_REVARP, 14, 24);
+
+	case Q_ARP:
+		return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24);
+
+	case Q_SCTP:
+		bpf_error(cstate, "'sctp' modifier applied to %s", typestr);
+
+	case Q_TCP:
+		bpf_error(cstate, "'tcp' modifier applied to %s", typestr);
+
+	case Q_UDP:
+		bpf_error(cstate, "'udp' modifier applied to %s", typestr);
+
+	case Q_ICMP:
+		bpf_error(cstate, "'icmp' modifier applied to %s", typestr);
+
+	case Q_IGMP:
+		bpf_error(cstate, "'igmp' modifier applied to %s", typestr);
+
+	case Q_IGRP:
+		bpf_error(cstate, "'igrp' modifier applied to %s", typestr);
+
+	case Q_ATALK:
+		bpf_error(cstate, "AppleTalk host filtering not implemented");
+
+	case Q_DECNET:
+		return gen_dnhostop(cstate, addr, dir);
+
+	case Q_LAT:
+		bpf_error(cstate, "LAT host filtering not implemented");
+
+	case Q_SCA:
+		bpf_error(cstate, "SCA host filtering not implemented");
+
+	case Q_MOPRC:
+		bpf_error(cstate, "MOPRC host filtering not implemented");
+
+	case Q_MOPDL:
+		bpf_error(cstate, "MOPDL host filtering not implemented");
+
+	case Q_IPV6:
+		bpf_error(cstate, "'ip6' modifier applied to ip host");
+
+	case Q_ICMPV6:
+		bpf_error(cstate, "'icmp6' modifier applied to %s", typestr);
+
+	case Q_AH:
+		bpf_error(cstate, "'ah' modifier applied to %s", typestr);
+
+	case Q_ESP:
+		bpf_error(cstate, "'esp' modifier applied to %s", typestr);
+
+	case Q_PIM:
+		bpf_error(cstate, "'pim' modifier applied to %s", typestr);
+
+	case Q_VRRP:
+		bpf_error(cstate, "'vrrp' modifier applied to %s", typestr);
+
+	case Q_AARP:
+		bpf_error(cstate, "AARP host filtering not implemented");
+
+	case Q_ISO:
+		bpf_error(cstate, "ISO host filtering not implemented");
+
+	case Q_ESIS:
+		bpf_error(cstate, "'esis' modifier applied to %s", typestr);
+
+	case Q_ISIS:
+		bpf_error(cstate, "'isis' modifier applied to %s", typestr);
+
+	case Q_CLNP:
+		bpf_error(cstate, "'clnp' modifier applied to %s", typestr);
+
+	case Q_STP:
+		bpf_error(cstate, "'stp' modifier applied to %s", typestr);
+
+	case Q_IPX:
+		bpf_error(cstate, "IPX host filtering not implemented");
+
+	case Q_NETBEUI:
+		bpf_error(cstate, "'netbeui' modifier applied to %s", typestr);
+
+	case Q_ISIS_L1:
+		bpf_error(cstate, "'l1' modifier applied to %s", typestr);
+
+	case Q_ISIS_L2:
+		bpf_error(cstate, "'l2' modifier applied to %s", typestr);
+
+	case Q_ISIS_IIH:
+		bpf_error(cstate, "'iih' modifier applied to %s", typestr);
+
+	case Q_ISIS_SNP:
+		bpf_error(cstate, "'snp' modifier applied to %s", typestr);
+
+	case Q_ISIS_CSNP:
+		bpf_error(cstate, "'csnp' modifier applied to %s", typestr);
+
+	case Q_ISIS_PSNP:
+		bpf_error(cstate, "'psnp' modifier applied to %s", typestr);
+
+	case Q_ISIS_LSP:
+		bpf_error(cstate, "'lsp' modifier applied to %s", typestr);
+
+	case Q_RADIO:
+		bpf_error(cstate, "'radio' modifier applied to %s", typestr);
+
+	case Q_CARP:
+		bpf_error(cstate, "'carp' modifier applied to %s", typestr);
+
+	default:
+		abort();
+	}
+	/*NOTREACHED*/
+}
+
+#ifdef INET6
+static struct block *
+gen_host6(compiler_state_t *cstate, struct in6_addr *addr,
+    struct in6_addr *mask, int proto, int dir, int type)
+{
+	const char *typestr;
+
+	if (type == Q_NET)
+		typestr = "net";
+	else
+		typestr = "host";
+
+	switch (proto) {
+
+	case Q_DEFAULT:
+		return gen_host6(cstate, addr, mask, Q_IPV6, dir, type);
+
+	case Q_LINK:
+		bpf_error(cstate, "link-layer modifier applied to ip6 %s", typestr);
+
+	case Q_IP:
+		bpf_error(cstate, "'ip' modifier applied to ip6 %s", typestr);
+
+	case Q_RARP:
+		bpf_error(cstate, "'rarp' modifier applied to ip6 %s", typestr);
+
+	case Q_ARP:
+		bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr);
+
+	case Q_SCTP:
+		bpf_error(cstate, "'sctp' modifier applied to ip6 %s", typestr);
+
+	case Q_TCP:
+		bpf_error(cstate, "'tcp' modifier applied to ip6 %s", typestr);
+
+	case Q_UDP:
+		bpf_error(cstate, "'udp' modifier applied to ip6 %s", typestr);
+
+	case Q_ICMP:
+		bpf_error(cstate, "'icmp' modifier applied to ip6 %s", typestr);
+
+	case Q_IGMP:
+		bpf_error(cstate, "'igmp' modifier applied to ip6 %s", typestr);
+
+	case Q_IGRP:
+		bpf_error(cstate, "'igrp' modifier applied to ip6 %s", typestr);
+
+	case Q_ATALK:
+		bpf_error(cstate, "AppleTalk modifier applied to ip6 %s", typestr);
+
+	case Q_DECNET:
+		bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr);
+
+	case Q_LAT:
+		bpf_error(cstate, "'lat' modifier applied to ip6 %s", typestr);
+
+	case Q_SCA:
+		bpf_error(cstate, "'sca' modifier applied to ip6 %s", typestr);
+
+	case Q_MOPRC:
+		bpf_error(cstate, "'moprc' modifier applied to ip6 %s", typestr);
+
+	case Q_MOPDL:
+		bpf_error(cstate, "'mopdl' modifier applied to ip6 %s", typestr);
+
+	case Q_IPV6:
+		return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24);
+
+	case Q_ICMPV6:
+		bpf_error(cstate, "'icmp6' modifier applied to ip6 %s", typestr);
+
+	case Q_AH:
+		bpf_error(cstate, "'ah' modifier applied to ip6 %s", typestr);
+
+	case Q_ESP:
+		bpf_error(cstate, "'esp' modifier applied to ip6 %s", typestr);
+
+	case Q_PIM:
+		bpf_error(cstate, "'pim' modifier applied to ip6 %s", typestr);
+
+	case Q_VRRP:
+		bpf_error(cstate, "'vrrp' modifier applied to ip6 %s", typestr);
+
+	case Q_AARP:
+		bpf_error(cstate, "'aarp' modifier applied to ip6 %s", typestr);
+
+	case Q_ISO:
+		bpf_error(cstate, "'iso' modifier applied to ip6 %s", typestr);
+
+	case Q_ESIS:
+		bpf_error(cstate, "'esis' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS:
+		bpf_error(cstate, "'isis' modifier applied to ip6 %s", typestr);
+
+	case Q_CLNP:
+		bpf_error(cstate, "'clnp' modifier applied to ip6 %s", typestr);
+
+	case Q_STP:
+		bpf_error(cstate, "'stp' modifier applied to ip6 %s", typestr);
+
+	case Q_IPX:
+		bpf_error(cstate, "'ipx' modifier applied to ip6 %s", typestr);
+
+	case Q_NETBEUI:
+		bpf_error(cstate, "'netbeui' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS_L1:
+		bpf_error(cstate, "'l1' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS_L2:
+		bpf_error(cstate, "'l2' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS_IIH:
+		bpf_error(cstate, "'iih' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS_SNP:
+		bpf_error(cstate, "'snp' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS_CSNP:
+		bpf_error(cstate, "'csnp' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS_PSNP:
+		bpf_error(cstate, "'psnp' modifier applied to ip6 %s", typestr);
+
+	case Q_ISIS_LSP:
+		bpf_error(cstate, "'lsp' modifier applied to ip6 %s", typestr);
+
+	case Q_RADIO:
+		bpf_error(cstate, "'radio' modifier applied to ip6 %s", typestr);
+
+	case Q_CARP:
+		bpf_error(cstate, "'carp' modifier applied to ip6 %s", typestr);
+
+	default:
+		abort();
+	}
+	/*NOTREACHED*/
+}
+#endif
+
+#ifndef INET6
+static struct block *
+gen_gateway(compiler_state_t *cstate, const u_char *eaddr,
+    struct addrinfo *alist, int proto, int dir)
+{
+	struct block *b0, *b1, *tmp;
+	struct addrinfo *ai;
+	struct sockaddr_in *sin;
+
+	if (dir != 0)
+		bpf_error(cstate, "direction applied to 'gateway'");
+
+	switch (proto) {
+	case Q_DEFAULT:
+	case Q_IP:
+	case Q_ARP:
+	case Q_RARP:
+		switch (cstate->linktype) {
+		case DLT_EN10MB:
+		case DLT_NETANALYZER:
+		case DLT_NETANALYZER_TRANSPARENT:
+			b1 = gen_prevlinkhdr_check(cstate);
+			b0 = gen_ehostop(cstate, eaddr, Q_OR);
+			if (b1 != NULL)
+				gen_and(b1, b0);
+			break;
+		case DLT_FDDI:
+			b0 = gen_fhostop(cstate, eaddr, Q_OR);
+			break;
+		case DLT_IEEE802:
+			b0 = gen_thostop(cstate, eaddr, Q_OR);
+			break;
+		case DLT_IEEE802_11:
+		case DLT_PRISM_HEADER:
+		case DLT_IEEE802_11_RADIO_AVS:
+		case DLT_IEEE802_11_RADIO:
+		case DLT_PPI:
+			b0 = gen_wlanhostop(cstate, eaddr, Q_OR);
+			break;
+		case DLT_SUNATM:
+			/*
+			 * This is LLC-multiplexed traffic; if it were
+			 * LANE, cstate->linktype would have been set to
+			 * DLT_EN10MB.
+			 */
+			bpf_error(cstate,
+			    "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+			break;
+		case DLT_IP_OVER_FC:
+			b0 = gen_ipfchostop(cstate, eaddr, Q_OR);
+			break;
+		default:
+			bpf_error(cstate,
+			    "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+		}
+		b1 = NULL;
+		for (ai = alist; ai != NULL; ai = ai->ai_next) {
+			/*
+			 * Does it have an address?
+			 */
+			if (ai->ai_addr != NULL) {
+				/*
+				 * Yes.  Is it an IPv4 address?
+				 */
+				if (ai->ai_addr->sa_family == AF_INET) {
+					/*
+					 * Generate an entry for it.
+					 */
+					sin = (struct sockaddr_in *)ai->ai_addr;
+					tmp = gen_host(cstate,
+					    ntohl(sin->sin_addr.s_addr),
+					    0xffffffff, proto, Q_OR, Q_HOST);
+					/*
+					 * Is it the *first* IPv4 address?
+					 */
+					if (b1 == NULL) {
+						/*
+						 * Yes, so start with it.
+						 */
+						b1 = tmp;
+					} else {
+						/*
+						 * No, so OR it into the
+						 * existing set of
+						 * addresses.
+						 */
+						gen_or(b1, tmp);
+						b1 = tmp;
+					}
+				}
+			}
+		}
+		if (b1 == NULL) {
+			/*
+			 * No IPv4 addresses found.
+			 */
+			return (NULL);
+		}
+		gen_not(b1);
+		gen_and(b0, b1);
+		return b1;
+	}
+	bpf_error(cstate, "illegal modifier of 'gateway'");
+	/*NOTREACHED*/
+}
+#endif
+
+static struct block *
+gen_proto_abbrev_internal(compiler_state_t *cstate, int proto)
+{
+	struct block *b0;
+	struct block *b1;
+
+	switch (proto) {
+
+	case Q_SCTP:
+		b1 = gen_proto(cstate, IPPROTO_SCTP, Q_IP, Q_DEFAULT);
+		b0 = gen_proto(cstate, IPPROTO_SCTP, Q_IPV6, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_TCP:
+		b1 = gen_proto(cstate, IPPROTO_TCP, Q_IP, Q_DEFAULT);
+		b0 = gen_proto(cstate, IPPROTO_TCP, Q_IPV6, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_UDP:
+		b1 = gen_proto(cstate, IPPROTO_UDP, Q_IP, Q_DEFAULT);
+		b0 = gen_proto(cstate, IPPROTO_UDP, Q_IPV6, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ICMP:
+		b1 = gen_proto(cstate, IPPROTO_ICMP, Q_IP, Q_DEFAULT);
+		break;
+
+#ifndef	IPPROTO_IGMP
+#define	IPPROTO_IGMP	2
+#endif
+
+	case Q_IGMP:
+		b1 = gen_proto(cstate, IPPROTO_IGMP, Q_IP, Q_DEFAULT);
+		break;
+
+#ifndef	IPPROTO_IGRP
+#define	IPPROTO_IGRP	9
+#endif
+	case Q_IGRP:
+		b1 = gen_proto(cstate, IPPROTO_IGRP, Q_IP, Q_DEFAULT);
+		break;
+
+#ifndef IPPROTO_PIM
+#define IPPROTO_PIM	103
+#endif
+
+	case Q_PIM:
+		b1 = gen_proto(cstate, IPPROTO_PIM, Q_IP, Q_DEFAULT);
+		b0 = gen_proto(cstate, IPPROTO_PIM, Q_IPV6, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+#ifndef IPPROTO_VRRP
+#define IPPROTO_VRRP	112
+#endif
+
+	case Q_VRRP:
+		b1 = gen_proto(cstate, IPPROTO_VRRP, Q_IP, Q_DEFAULT);
+		break;
+
+#ifndef IPPROTO_CARP
+#define IPPROTO_CARP	112
+#endif
+
+	case Q_CARP:
+		b1 = gen_proto(cstate, IPPROTO_CARP, Q_IP, Q_DEFAULT);
+		break;
+
+	case Q_IP:
+		b1 = gen_linktype(cstate, ETHERTYPE_IP);
+		break;
+
+	case Q_ARP:
+		b1 = gen_linktype(cstate, ETHERTYPE_ARP);
+		break;
+
+	case Q_RARP:
+		b1 = gen_linktype(cstate, ETHERTYPE_REVARP);
+		break;
+
+	case Q_LINK:
+		bpf_error(cstate, "link layer applied in wrong context");
+
+	case Q_ATALK:
+		b1 = gen_linktype(cstate, ETHERTYPE_ATALK);
+		break;
+
+	case Q_AARP:
+		b1 = gen_linktype(cstate, ETHERTYPE_AARP);
+		break;
+
+	case Q_DECNET:
+		b1 = gen_linktype(cstate, ETHERTYPE_DN);
+		break;
+
+	case Q_SCA:
+		b1 = gen_linktype(cstate, ETHERTYPE_SCA);
+		break;
+
+	case Q_LAT:
+		b1 = gen_linktype(cstate, ETHERTYPE_LAT);
+		break;
+
+	case Q_MOPDL:
+		b1 = gen_linktype(cstate, ETHERTYPE_MOPDL);
+		break;
+
+	case Q_MOPRC:
+		b1 = gen_linktype(cstate, ETHERTYPE_MOPRC);
+		break;
+
+	case Q_IPV6:
+		b1 = gen_linktype(cstate, ETHERTYPE_IPV6);
+		break;
+
+#ifndef IPPROTO_ICMPV6
+#define IPPROTO_ICMPV6	58
+#endif
+	case Q_ICMPV6:
+		b1 = gen_proto(cstate, IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT);
+		break;
+
+#ifndef IPPROTO_AH
+#define IPPROTO_AH	51
+#endif
+	case Q_AH:
+		b1 = gen_proto(cstate, IPPROTO_AH, Q_IP, Q_DEFAULT);
+		b0 = gen_proto(cstate, IPPROTO_AH, Q_IPV6, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+#ifndef IPPROTO_ESP
+#define IPPROTO_ESP	50
+#endif
+	case Q_ESP:
+		b1 = gen_proto(cstate, IPPROTO_ESP, Q_IP, Q_DEFAULT);
+		b0 = gen_proto(cstate, IPPROTO_ESP, Q_IPV6, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ISO:
+		b1 = gen_linktype(cstate, LLCSAP_ISONS);
+		break;
+
+	case Q_ESIS:
+		b1 = gen_proto(cstate, ISO9542_ESIS, Q_ISO, Q_DEFAULT);
+		break;
+
+	case Q_ISIS:
+		b1 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT);
+		break;
+
+	case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */
+		b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT);
+		b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */
+		b0 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT);
+		b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */
+		b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT);
+		b1 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ISIS_LSP:
+		b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT);
+		b1 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ISIS_SNP:
+		b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+		b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ISIS_CSNP:
+		b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+		b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_ISIS_PSNP:
+		b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+		b1 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+		gen_or(b0, b1);
+		break;
+
+	case Q_CLNP:
+		b1 = gen_proto(cstate, ISO8473_CLNP, Q_ISO, Q_DEFAULT);
+		break;
+
+	case Q_STP:
+		b1 = gen_linktype(cstate, LLCSAP_8021D);
+		break;
+
+	case Q_IPX:
+		b1 = gen_linktype(cstate, LLCSAP_IPX);
+		break;
+
+	case Q_NETBEUI:
+		b1 = gen_linktype(cstate, LLCSAP_NETBEUI);
+		break;
+
+	case Q_RADIO:
+		bpf_error(cstate, "'radio' is not a valid protocol type");
+
+	default:
+		abort();
+	}
+	return b1;
+}
+
+struct block *
+gen_proto_abbrev(compiler_state_t *cstate, int proto)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	return gen_proto_abbrev_internal(cstate, proto);
+}
+
+static struct block *
+gen_ipfrag(compiler_state_t *cstate)
+{
+	struct slist *s;
+	struct block *b;
+
+	/* not IPv4 frag other than the first frag */
+	s = gen_load_a(cstate, OR_LINKPL, 6, BPF_H);
+	b = new_block(cstate, JMP(BPF_JSET));
+	b->s.k = 0x1fff;
+	b->stmts = s;
+	gen_not(b);
+
+	return b;
+}
+
+/*
+ * Generate a comparison to a port value in the transport-layer header
+ * at the specified offset from the beginning of that header.
+ *
+ * XXX - this handles a variable-length prefix preceding the link-layer
+ * header, such as the radiotap or AVS radio prefix, but doesn't handle
+ * variable-length link-layer headers (such as Token Ring or 802.11
+ * headers).
+ */
+static struct block *
+gen_portatom(compiler_state_t *cstate, int off, bpf_u_int32 v)
+{
+	return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v);
+}
+
+static struct block *
+gen_portatom6(compiler_state_t *cstate, int off, bpf_u_int32 v)
+{
+	return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v);
+}
+
+static struct block *
+gen_portop(compiler_state_t *cstate, u_int port, u_int proto, int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/* ip proto 'proto' and not a fragment other than the first fragment */
+	tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
+	b0 = gen_ipfrag(cstate);
+	gen_and(tmp, b0);
+
+	switch (dir) {
+	case Q_SRC:
+		b1 = gen_portatom(cstate, 0, port);
+		break;
+
+	case Q_DST:
+		b1 = gen_portatom(cstate, 2, port);
+		break;
+
+	case Q_AND:
+		tmp = gen_portatom(cstate, 0, port);
+		b1 = gen_portatom(cstate, 2, port);
+		gen_and(tmp, b1);
+		break;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		tmp = gen_portatom(cstate, 0, port);
+		b1 = gen_portatom(cstate, 2, port);
+		gen_or(tmp, b1);
+		break;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for ports");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for ports");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for ports");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for ports");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is not a valid qualifier for ports");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is not a valid qualifier for ports");
+		/*NOTREACHED*/
+
+	default:
+		abort();
+		/*NOTREACHED*/
+	}
+	gen_and(b0, b1);
+
+	return b1;
+}
+
+static struct block *
+gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/*
+	 * ether proto ip
+	 *
+	 * For FDDI, RFC 1188 says that SNAP encapsulation is used,
+	 * not LLC encapsulation with LLCSAP_IP.
+	 *
+	 * For IEEE 802 networks - which includes 802.5 token ring
+	 * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042
+	 * says that SNAP encapsulation is used, not LLC encapsulation
+	 * with LLCSAP_IP.
+	 *
+	 * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and
+	 * RFC 2225 say that SNAP encapsulation is used, not LLC
+	 * encapsulation with LLCSAP_IP.
+	 *
+	 * So we always check for ETHERTYPE_IP.
+	 */
+	b0 = gen_linktype(cstate, ETHERTYPE_IP);
+
+	switch (ip_proto) {
+	case IPPROTO_UDP:
+	case IPPROTO_TCP:
+	case IPPROTO_SCTP:
+		b1 = gen_portop(cstate, port, (u_int)ip_proto, dir);
+		break;
+
+	case PROTO_UNDEF:
+		tmp = gen_portop(cstate, port, IPPROTO_TCP, dir);
+		b1 = gen_portop(cstate, port, IPPROTO_UDP, dir);
+		gen_or(tmp, b1);
+		tmp = gen_portop(cstate, port, IPPROTO_SCTP, dir);
+		gen_or(tmp, b1);
+		break;
+
+	default:
+		abort();
+	}
+	gen_and(b0, b1);
+	return b1;
+}
+
+struct block *
+gen_portop6(compiler_state_t *cstate, u_int port, u_int proto, int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/* ip6 proto 'proto' */
+	/* XXX - catch the first fragment of a fragmented packet? */
+	b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
+
+	switch (dir) {
+	case Q_SRC:
+		b1 = gen_portatom6(cstate, 0, port);
+		break;
+
+	case Q_DST:
+		b1 = gen_portatom6(cstate, 2, port);
+		break;
+
+	case Q_AND:
+		tmp = gen_portatom6(cstate, 0, port);
+		b1 = gen_portatom6(cstate, 2, port);
+		gen_and(tmp, b1);
+		break;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		tmp = gen_portatom6(cstate, 0, port);
+		b1 = gen_portatom6(cstate, 2, port);
+		gen_or(tmp, b1);
+		break;
+
+	default:
+		abort();
+	}
+	gen_and(b0, b1);
+
+	return b1;
+}
+
+static struct block *
+gen_port6(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/* link proto ip6 */
+	b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+
+	switch (ip_proto) {
+	case IPPROTO_UDP:
+	case IPPROTO_TCP:
+	case IPPROTO_SCTP:
+		b1 = gen_portop6(cstate, port, (u_int)ip_proto, dir);
+		break;
+
+	case PROTO_UNDEF:
+		tmp = gen_portop6(cstate, port, IPPROTO_TCP, dir);
+		b1 = gen_portop6(cstate, port, IPPROTO_UDP, dir);
+		gen_or(tmp, b1);
+		tmp = gen_portop6(cstate, port, IPPROTO_SCTP, dir);
+		gen_or(tmp, b1);
+		break;
+
+	default:
+		abort();
+	}
+	gen_and(b0, b1);
+	return b1;
+}
+
+/* gen_portrange code */
+static struct block *
+gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+    bpf_u_int32 v2)
+{
+	struct block *b1, *b2;
+
+	if (v1 > v2) {
+		/*
+		 * Reverse the order of the ports, so v1 is the lower one.
+		 */
+		bpf_u_int32 vtemp;
+
+		vtemp = v1;
+		v1 = v2;
+		v2 = vtemp;
+	}
+
+	b1 = gen_cmp_ge(cstate, OR_TRAN_IPV4, off, BPF_H, v1);
+	b2 = gen_cmp_le(cstate, OR_TRAN_IPV4, off, BPF_H, v2);
+
+	gen_and(b1, b2);
+
+	return b2;
+}
+
+static struct block *
+gen_portrangeop(compiler_state_t *cstate, u_int port1, u_int port2,
+    bpf_u_int32 proto, int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/* ip proto 'proto' and not a fragment other than the first fragment */
+	tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
+	b0 = gen_ipfrag(cstate);
+	gen_and(tmp, b0);
+
+	switch (dir) {
+	case Q_SRC:
+		b1 = gen_portrangeatom(cstate, 0, port1, port2);
+		break;
+
+	case Q_DST:
+		b1 = gen_portrangeatom(cstate, 2, port1, port2);
+		break;
+
+	case Q_AND:
+		tmp = gen_portrangeatom(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom(cstate, 2, port1, port2);
+		gen_and(tmp, b1);
+		break;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		tmp = gen_portrangeatom(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom(cstate, 2, port1, port2);
+		gen_or(tmp, b1);
+		break;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for port ranges");
+		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for port ranges");
+		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for port ranges");
+		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for port ranges");
+		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is not a valid qualifier for port ranges");
+		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is not a valid qualifier for port ranges");
+		/*NOTREACHED*/
+
+	default:
+		abort();
+		/*NOTREACHED*/
+	}
+	gen_and(b0, b1);
+
+	return b1;
+}
+
+static struct block *
+gen_portrange(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
+    int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/* link proto ip */
+	b0 = gen_linktype(cstate, ETHERTYPE_IP);
+
+	switch (ip_proto) {
+	case IPPROTO_UDP:
+	case IPPROTO_TCP:
+	case IPPROTO_SCTP:
+		b1 = gen_portrangeop(cstate, port1, port2, (bpf_u_int32)ip_proto,
+		    dir);
+		break;
+
+	case PROTO_UNDEF:
+		tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_TCP, dir);
+		b1 = gen_portrangeop(cstate, port1, port2, IPPROTO_UDP, dir);
+		gen_or(tmp, b1);
+		tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_SCTP, dir);
+		gen_or(tmp, b1);
+		break;
+
+	default:
+		abort();
+	}
+	gen_and(b0, b1);
+	return b1;
+}
+
+static struct block *
+gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+    bpf_u_int32 v2)
+{
+	struct block *b1, *b2;
+
+	if (v1 > v2) {
+		/*
+		 * Reverse the order of the ports, so v1 is the lower one.
+		 */
+		bpf_u_int32 vtemp;
+
+		vtemp = v1;
+		v1 = v2;
+		v2 = vtemp;
+	}
+
+	b1 = gen_cmp_ge(cstate, OR_TRAN_IPV6, off, BPF_H, v1);
+	b2 = gen_cmp_le(cstate, OR_TRAN_IPV6, off, BPF_H, v2);
+
+	gen_and(b1, b2);
+
+	return b2;
+}
+
+static struct block *
+gen_portrangeop6(compiler_state_t *cstate, u_int port1, u_int port2,
+    bpf_u_int32 proto, int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/* ip6 proto 'proto' */
+	/* XXX - catch the first fragment of a fragmented packet? */
+	b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
+
+	switch (dir) {
+	case Q_SRC:
+		b1 = gen_portrangeatom6(cstate, 0, port1, port2);
+		break;
+
+	case Q_DST:
+		b1 = gen_portrangeatom6(cstate, 2, port1, port2);
+		break;
+
+	case Q_AND:
+		tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom6(cstate, 2, port1, port2);
+		gen_and(tmp, b1);
+		break;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom6(cstate, 2, port1, port2);
+		gen_or(tmp, b1);
+		break;
+
+	default:
+		abort();
+	}
+	gen_and(b0, b1);
+
+	return b1;
+}
+
+static struct block *
+gen_portrange6(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
+    int dir)
+{
+	struct block *b0, *b1, *tmp;
+
+	/* link proto ip6 */
+	b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+
+	switch (ip_proto) {
+	case IPPROTO_UDP:
+	case IPPROTO_TCP:
+	case IPPROTO_SCTP:
+		b1 = gen_portrangeop6(cstate, port1, port2, (bpf_u_int32)ip_proto,
+		    dir);
+		break;
+
+	case PROTO_UNDEF:
+		tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_TCP, dir);
+		b1 = gen_portrangeop6(cstate, port1, port2, IPPROTO_UDP, dir);
+		gen_or(tmp, b1);
+		tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_SCTP, dir);
+		gen_or(tmp, b1);
+		break;
+
+	default:
+		abort();
+	}
+	gen_and(b0, b1);
+	return b1;
+}
+
+static int
+lookup_proto(compiler_state_t *cstate, const char *name, int proto)
+{
+	register int v;
+
+	switch (proto) {
+
+	case Q_DEFAULT:
+	case Q_IP:
+	case Q_IPV6:
+		v = pcap_nametoproto(name);
+		if (v == PROTO_UNDEF)
+			bpf_error(cstate, "unknown ip proto '%s'", name);
+		break;
+
+	case Q_LINK:
+		/* XXX should look up h/w protocol type based on cstate->linktype */
+		v = pcap_nametoeproto(name);
+		if (v == PROTO_UNDEF) {
+			v = pcap_nametollc(name);
+			if (v == PROTO_UNDEF)
+				bpf_error(cstate, "unknown ether proto '%s'", name);
+		}
+		break;
+
+	case Q_ISO:
+		if (strcmp(name, "esis") == 0)
+			v = ISO9542_ESIS;
+		else if (strcmp(name, "isis") == 0)
+			v = ISO10589_ISIS;
+		else if (strcmp(name, "clnp") == 0)
+			v = ISO8473_CLNP;
+		else
+			bpf_error(cstate, "unknown osi proto '%s'", name);
+		break;
+
+	default:
+		v = PROTO_UNDEF;
+		break;
+	}
+	return v;
+}
+
+#if 0
+struct stmt *
+gen_joinsp(struct stmt **s, int n)
+{
+	return NULL;
+}
+#endif
+
+static struct block *
+gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
+{
+#ifdef NO_PROTOCHAIN
+	return gen_proto(cstate, v, proto);
+#else
+	struct block *b0, *b;
+	struct slist *s[100];
+	int fix2, fix3, fix4, fix5;
+	int ahcheck, again, end;
+	int i, max;
+	int reg2 = alloc_reg(cstate);
+
+	memset(s, 0, sizeof(s));
+	fix3 = fix4 = fix5 = 0;
+
+	switch (proto) {
+	case Q_IP:
+	case Q_IPV6:
+		break;
+	case Q_DEFAULT:
+		b0 = gen_protochain(cstate, v, Q_IP);
+		b = gen_protochain(cstate, v, Q_IPV6);
+		gen_or(b0, b);
+		return b;
+	default:
+		bpf_error(cstate, "bad protocol applied for 'protochain'");
+		/*NOTREACHED*/
+	}
+
+	/*
+	 * 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
+	 * be done in the kernel.  (We already require a modified BPF
+	 * engine to do the protochain stuff, to support backward
+	 * branches, and backward branch support is unlikely to appear
+	 * in kernel BPF engines.)
+	 */
+	if (cstate->off_linkpl.is_variable)
+		bpf_error(cstate, "'protochain' not supported with variable length headers");
+
+	/*
+	 * To quote a comment in optimize.c:
+	 *
+	 * "These data structures are used in a Cocke and Shwarz style
+	 * value numbering scheme.  Since the flowgraph is acyclic,
+	 * exit values can be propagated from a node's predecessors
+	 * provided it is uniquely defined."
+	 *
+	 * "Acyclic" means "no backward branches", which means "no
+	 * loops", so we have to turn the optimizer off.
+	 */
+	cstate->no_optimize = 1;
+
+	/*
+	 * s[0] is a dummy entry to protect other BPF insn from damage
+	 * by s[fix] = foo with uninitialized variable "fix".  It is somewhat
+	 * hard to find interdependency made by jump table fixup.
+	 */
+	i = 0;
+	s[i] = new_stmt(cstate, 0);	/*dummy*/
+	i++;
+
+	switch (proto) {
+	case Q_IP:
+		b0 = gen_linktype(cstate, ETHERTYPE_IP);
+
+		/* A = ip->ip_p */
+		s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+		s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 9;
+		i++;
+		/* X = ip->ip_hl << 2 */
+		s[i] = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B);
+		s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+		i++;
+		break;
+
+	case Q_IPV6:
+		b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+
+		/* A = ip6->ip_nxt */
+		s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+		s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 6;
+		i++;
+		/* X = sizeof(struct ip6_hdr) */
+		s[i] = new_stmt(cstate, BPF_LDX|BPF_IMM);
+		s[i]->s.k = 40;
+		i++;
+		break;
+
+	default:
+		bpf_error(cstate, "unsupported proto to gen_protochain");
+		/*NOTREACHED*/
+	}
+
+	/* again: if (A == v) goto end; else fall through; */
+	again = i;
+	s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+	s[i]->s.k = v;
+	s[i]->s.jt = NULL;		/*later*/
+	s[i]->s.jf = NULL;		/*update in next stmt*/
+	fix5 = i;
+	i++;
+
+#ifndef IPPROTO_NONE
+#define IPPROTO_NONE	59
+#endif
+	/* if (A == IPPROTO_NONE) goto end */
+	s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+	s[i]->s.jt = NULL;	/*later*/
+	s[i]->s.jf = NULL;	/*update in next stmt*/
+	s[i]->s.k = IPPROTO_NONE;
+	s[fix5]->s.jf = s[i];
+	fix2 = i;
+	i++;
+
+	if (proto == Q_IPV6) {
+		int v6start, v6end, v6advance, j;
+
+		v6start = i;
+		/* if (A == IPPROTO_HOPOPTS) goto v6advance */
+		s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+		s[i]->s.jt = NULL;	/*later*/
+		s[i]->s.jf = NULL;	/*update in next stmt*/
+		s[i]->s.k = IPPROTO_HOPOPTS;
+		s[fix2]->s.jf = s[i];
+		i++;
+		/* if (A == IPPROTO_DSTOPTS) goto v6advance */
+		s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+		s[i]->s.jt = NULL;	/*later*/
+		s[i]->s.jf = NULL;	/*update in next stmt*/
+		s[i]->s.k = IPPROTO_DSTOPTS;
+		i++;
+		/* if (A == IPPROTO_ROUTING) goto v6advance */
+		s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+		s[i]->s.jt = NULL;	/*later*/
+		s[i]->s.jf = NULL;	/*update in next stmt*/
+		s[i]->s.k = IPPROTO_ROUTING;
+		i++;
+		/* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */
+		s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+		s[i]->s.jt = NULL;	/*later*/
+		s[i]->s.jf = NULL;	/*later*/
+		s[i]->s.k = IPPROTO_FRAGMENT;
+		fix3 = i;
+		v6end = i;
+		i++;
+
+		/* v6advance: */
+		v6advance = i;
+
+		/*
+		 * in short,
+		 * A = P[X + packet head];
+		 * X = X + (P[X + packet head + 1] + 1) * 8;
+		 */
+		/* A = P[X + packet head] */
+		s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+		s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+		i++;
+		/* MEM[reg2] = A */
+		s[i] = new_stmt(cstate, BPF_ST);
+		s[i]->s.k = reg2;
+		i++;
+		/* A = P[X + packet head + 1]; */
+		s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+		s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 1;
+		i++;
+		/* A += 1 */
+		s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+		s[i]->s.k = 1;
+		i++;
+		/* A *= 8 */
+		s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
+		s[i]->s.k = 8;
+		i++;
+		/* A += X */
+		s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+		s[i]->s.k = 0;
+		i++;
+		/* X = A; */
+		s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX);
+		i++;
+		/* A = MEM[reg2] */
+		s[i] = new_stmt(cstate, BPF_LD|BPF_MEM);
+		s[i]->s.k = reg2;
+		i++;
+
+		/* goto again; (must use BPF_JA for backward jump) */
+		s[i] = new_stmt(cstate, BPF_JMP|BPF_JA);
+		s[i]->s.k = again - i - 1;
+		s[i - 1]->s.jf = s[i];
+		i++;
+
+		/* fixup */
+		for (j = v6start; j <= v6end; j++)
+			s[j]->s.jt = s[v6advance];
+	} else {
+		/* nop */
+		s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+		s[i]->s.k = 0;
+		s[fix2]->s.jf = s[i];
+		i++;
+	}
+
+	/* ahcheck: */
+	ahcheck = i;
+	/* if (A == IPPROTO_AH) then fall through; else goto end; */
+	s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+	s[i]->s.jt = NULL;	/*later*/
+	s[i]->s.jf = NULL;	/*later*/
+	s[i]->s.k = IPPROTO_AH;
+	if (fix3)
+		s[fix3]->s.jf = s[ahcheck];
+	fix4 = i;
+	i++;
+
+	/*
+	 * in short,
+	 * A = P[X];
+	 * X = X + (P[X + 1] + 2) * 4;
+	 */
+	/* A = X */
+	s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA);
+	i++;
+	/* A = P[X + packet head]; */
+	s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+	s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+	i++;
+	/* MEM[reg2] = A */
+	s[i] = new_stmt(cstate, BPF_ST);
+	s[i]->s.k = reg2;
+	i++;
+	/* A = X */
+	s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA);
+	i++;
+	/* A += 1 */
+	s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s[i]->s.k = 1;
+	i++;
+	/* X = A */
+	s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX);
+	i++;
+	/* A = P[X + packet head] */
+	s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+	s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+	i++;
+	/* A += 2 */
+	s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s[i]->s.k = 2;
+	i++;
+	/* A *= 4 */
+	s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
+	s[i]->s.k = 4;
+	i++;
+	/* X = A; */
+	s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX);
+	i++;
+	/* A = MEM[reg2] */
+	s[i] = new_stmt(cstate, BPF_LD|BPF_MEM);
+	s[i]->s.k = reg2;
+	i++;
+
+	/* goto again; (must use BPF_JA for backward jump) */
+	s[i] = new_stmt(cstate, BPF_JMP|BPF_JA);
+	s[i]->s.k = again - i - 1;
+	i++;
+
+	/* end: nop */
+	end = i;
+	s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s[i]->s.k = 0;
+	s[fix2]->s.jt = s[end];
+	s[fix4]->s.jf = s[end];
+	s[fix5]->s.jt = s[end];
+	i++;
+
+	/*
+	 * make slist chain
+	 */
+	max = i;
+	for (i = 0; i < max - 1; i++)
+		s[i]->next = s[i + 1];
+	s[max - 1]->next = NULL;
+
+	/*
+	 * emit final check
+	 */
+	b = new_block(cstate, JMP(BPF_JEQ));
+	b->stmts = s[1];	/*remember, s[0] is dummy*/
+	b->s.k = v;
+
+	free_reg(cstate, reg2);
+
+	gen_and(b0, b);
+	return b;
+#endif
+}
+
+static struct block *
+gen_check_802_11_data_frame(compiler_state_t *cstate)
+{
+	struct slist *s;
+	struct block *b0, *b1;
+
+	/*
+	 * A data frame has the 0x08 bit (b3) in the frame control field set
+	 * and the 0x04 bit (b2) clear.
+	 */
+	s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+	b0 = new_block(cstate, JMP(BPF_JSET));
+	b0->s.k = 0x08;
+	b0->stmts = s;
+
+	s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+	b1 = new_block(cstate, JMP(BPF_JSET));
+	b1->s.k = 0x04;
+	b1->stmts = s;
+	gen_not(b1);
+
+	gen_and(b1, b0);
+
+	return b0;
+}
+
+/*
+ * Generate code that checks whether the packet is a packet for protocol
+ * <proto> and whether the type field in that protocol's header has
+ * the value <v>, e.g. if <proto> is Q_IP, it checks whether it's an
+ * IP packet and checks the protocol number in the IP header against <v>.
+ *
+ * If <proto> is Q_DEFAULT, i.e. just "proto" was specified, it checks
+ * against Q_IP and Q_IPV6.
+ */
+static struct block *
+gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
+{
+	struct block *b0, *b1;
+#ifndef CHASE_CHAIN
+	struct block *b2;
+#endif
+
+	if (dir != Q_DEFAULT)
+		bpf_error(cstate, "direction applied to 'proto'");
+
+	switch (proto) {
+	case Q_DEFAULT:
+		b0 = gen_proto(cstate, v, Q_IP, dir);
+		b1 = gen_proto(cstate, v, Q_IPV6, dir);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_LINK:
+		return gen_linktype(cstate, v);
+
+	case Q_IP:
+		/*
+		 * For FDDI, RFC 1188 says that SNAP encapsulation is used,
+		 * not LLC encapsulation with LLCSAP_IP.
+		 *
+		 * For IEEE 802 networks - which includes 802.5 token ring
+		 * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042
+		 * says that SNAP encapsulation is used, not LLC encapsulation
+		 * with LLCSAP_IP.
+		 *
+		 * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and
+		 * RFC 2225 say that SNAP encapsulation is used, not LLC
+		 * encapsulation with LLCSAP_IP.
+		 *
+		 * So we always check for ETHERTYPE_IP.
+		 */
+		b0 = gen_linktype(cstate, ETHERTYPE_IP);
+#ifndef CHASE_CHAIN
+		b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v);
+#else
+		b1 = gen_protochain(cstate, v, Q_IP);
+#endif
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_ARP:
+		bpf_error(cstate, "arp does not encapsulate another protocol");
+		/*NOTREACHED*/
+
+	case Q_RARP:
+		bpf_error(cstate, "rarp does not encapsulate another protocol");
+		/*NOTREACHED*/
+
+	case Q_SCTP:
+		bpf_error(cstate, "'sctp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_TCP:
+		bpf_error(cstate, "'tcp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_UDP:
+		bpf_error(cstate, "'udp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ICMP:
+		bpf_error(cstate, "'icmp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_IGMP:
+		bpf_error(cstate, "'igmp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_IGRP:
+		bpf_error(cstate, "'igrp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ATALK:
+		bpf_error(cstate, "AppleTalk encapsulation is not specifiable");
+		/*NOTREACHED*/
+
+	case Q_DECNET:
+		bpf_error(cstate, "DECNET encapsulation is not specifiable");
+		/*NOTREACHED*/
+
+	case Q_LAT:
+		bpf_error(cstate, "LAT does not encapsulate another protocol");
+		/*NOTREACHED*/
+
+	case Q_SCA:
+		bpf_error(cstate, "SCA does not encapsulate another protocol");
+		/*NOTREACHED*/
+
+	case Q_MOPRC:
+		bpf_error(cstate, "MOPRC does not encapsulate another protocol");
+		/*NOTREACHED*/
+
+	case Q_MOPDL:
+		bpf_error(cstate, "MOPDL does not encapsulate another protocol");
+		/*NOTREACHED*/
+
+	case Q_IPV6:
+		b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+#ifndef CHASE_CHAIN
+		/*
+		 * Also check for a fragment header before the final
+		 * header.
+		 */
+		b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT);
+		b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v);
+		gen_and(b2, b1);
+		b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v);
+		gen_or(b2, b1);
+#else
+		b1 = gen_protochain(cstate, v, Q_IPV6);
+#endif
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_ICMPV6:
+		bpf_error(cstate, "'icmp6 proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_AH:
+		bpf_error(cstate, "'ah proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ESP:
+		bpf_error(cstate, "'esp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_PIM:
+		bpf_error(cstate, "'pim proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_VRRP:
+		bpf_error(cstate, "'vrrp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_AARP:
+		bpf_error(cstate, "'aarp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISO:
+		switch (cstate->linktype) {
+
+		case DLT_FRELAY:
+			/*
+			 * Frame Relay packets typically have an OSI
+			 * NLPID at the beginning; "gen_linktype(cstate, LLCSAP_ISONS)"
+			 * generates code to check for all the OSI
+			 * NLPIDs, so calling it and then adding a check
+			 * for the particular NLPID for which we're
+			 * looking is bogus, as we can just check for
+			 * the NLPID.
+			 *
+			 * What we check for is the NLPID and a frame
+			 * control field value of UI, i.e. 0x03 followed
+			 * by the NLPID.
+			 *
+			 * XXX - assumes a 2-byte Frame Relay header with
+			 * DLCI and flags.  What if the address is longer?
+			 *
+			 * XXX - what about SNAP-encapsulated frames?
+			 */
+			return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v);
+			/*NOTREACHED*/
+
+		case DLT_C_HDLC:
+			/*
+			 * Cisco uses an Ethertype lookalike - for OSI,
+			 * it's 0xfefe.
+			 */
+			b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS);
+			/* OSI in C-HDLC is stuffed with a fudge byte */
+			b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, v);
+			gen_and(b0, b1);
+			return b1;
+
+		default:
+			b0 = gen_linktype(cstate, LLCSAP_ISONS);
+			b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, v);
+			gen_and(b0, b1);
+			return b1;
+		}
+
+	case Q_ESIS:
+		bpf_error(cstate, "'esis proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS:
+		b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT);
+		/*
+		 * 4 is the offset of the PDU type relative to the IS-IS
+		 * header.
+		 */
+		b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, v);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_CLNP:
+		bpf_error(cstate, "'clnp proto' is not supported");
+		/*NOTREACHED*/
+
+	case Q_STP:
+		bpf_error(cstate, "'stp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_IPX:
+		bpf_error(cstate, "'ipx proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_NETBEUI:
+		bpf_error(cstate, "'netbeui proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS_L1:
+		bpf_error(cstate, "'l1 proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS_L2:
+		bpf_error(cstate, "'l2 proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS_IIH:
+		bpf_error(cstate, "'iih proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS_SNP:
+		bpf_error(cstate, "'snp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS_CSNP:
+		bpf_error(cstate, "'csnp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS_PSNP:
+		bpf_error(cstate, "'psnp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_ISIS_LSP:
+		bpf_error(cstate, "'lsp proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_RADIO:
+		bpf_error(cstate, "'radio proto' is bogus");
+		/*NOTREACHED*/
+
+	case Q_CARP:
+		bpf_error(cstate, "'carp proto' is bogus");
+		/*NOTREACHED*/
+
+	default:
+		abort();
+		/*NOTREACHED*/
+	}
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
+{
+	int proto = q.proto;
+	int dir = q.dir;
+	int tproto;
+	u_char *eaddr;
+	bpf_u_int32 mask, addr;
+	struct addrinfo *res, *res0;
+	struct sockaddr_in *sin4;
+#ifdef INET6
+	int tproto6;
+	struct sockaddr_in6 *sin6;
+	struct in6_addr mask128;
+#endif /*INET6*/
+	struct block *b, *tmp;
+	int port, real_proto;
+	int port1, port2;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (q.addr) {
+
+	case Q_NET:
+		addr = pcap_nametonetaddr(name);
+		if (addr == 0)
+			bpf_error(cstate, "unknown network '%s'", name);
+		/* Left justify network addr and calculate its network mask */
+		mask = 0xffffffff;
+		while (addr && (addr & 0xff000000) == 0) {
+			addr <<= 8;
+			mask <<= 8;
+		}
+		return gen_host(cstate, addr, mask, proto, dir, q.addr);
+
+	case Q_DEFAULT:
+	case Q_HOST:
+		if (proto == Q_LINK) {
+			switch (cstate->linktype) {
+
+			case DLT_EN10MB:
+			case DLT_NETANALYZER:
+			case DLT_NETANALYZER_TRANSPARENT:
+				eaddr = pcap_ether_hostton(name);
+				if (eaddr == NULL)
+					bpf_error(cstate,
+					    "unknown ether host '%s'", name);
+				tmp = gen_prevlinkhdr_check(cstate);
+				b = gen_ehostop(cstate, eaddr, dir);
+				if (tmp != NULL)
+					gen_and(tmp, b);
+				free(eaddr);
+				return b;
+
+			case DLT_FDDI:
+				eaddr = pcap_ether_hostton(name);
+				if (eaddr == NULL)
+					bpf_error(cstate,
+					    "unknown FDDI host '%s'", name);
+				b = gen_fhostop(cstate, eaddr, dir);
+				free(eaddr);
+				return b;
+
+			case DLT_IEEE802:
+				eaddr = pcap_ether_hostton(name);
+				if (eaddr == NULL)
+					bpf_error(cstate,
+					    "unknown token ring host '%s'", name);
+				b = gen_thostop(cstate, eaddr, dir);
+				free(eaddr);
+				return b;
+
+			case DLT_IEEE802_11:
+			case DLT_PRISM_HEADER:
+			case DLT_IEEE802_11_RADIO_AVS:
+			case DLT_IEEE802_11_RADIO:
+			case DLT_PPI:
+				eaddr = pcap_ether_hostton(name);
+				if (eaddr == NULL)
+					bpf_error(cstate,
+					    "unknown 802.11 host '%s'", name);
+				b = gen_wlanhostop(cstate, eaddr, dir);
+				free(eaddr);
+				return b;
+
+			case DLT_IP_OVER_FC:
+				eaddr = pcap_ether_hostton(name);
+				if (eaddr == NULL)
+					bpf_error(cstate,
+					    "unknown Fibre Channel host '%s'", name);
+				b = gen_ipfchostop(cstate, eaddr, dir);
+				free(eaddr);
+				return b;
+			}
+
+			bpf_error(cstate, "only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name");
+		} else if (proto == Q_DECNET) {
+			unsigned short dn_addr;
+
+			if (!__pcap_nametodnaddr(name, &dn_addr)) {
+#ifdef	DECNETLIB
+				bpf_error(cstate, "unknown decnet host name '%s'\n", name);
+#else
+				bpf_error(cstate, "decnet name support not included, '%s' cannot be translated\n",
+					name);
+#endif
+			}
+			/*
+			 * I don't think DECNET hosts can be multihomed, so
+			 * there is no need to build up a list of addresses
+			 */
+			return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr));
+		} else {
+#ifdef INET6
+			memset(&mask128, 0xff, sizeof(mask128));
+#endif
+			res0 = res = pcap_nametoaddrinfo(name);
+			if (res == NULL)
+				bpf_error(cstate, "unknown host '%s'", name);
+			cstate->ai = res;
+			b = tmp = NULL;
+			tproto = proto;
+#ifdef INET6
+			tproto6 = proto;
+#endif
+			if (cstate->off_linktype.constant_part == OFFSET_NOT_SET &&
+			    tproto == Q_DEFAULT) {
+				tproto = Q_IP;
+#ifdef INET6
+				tproto6 = Q_IPV6;
+#endif
+			}
+			for (res = res0; res; res = res->ai_next) {
+				switch (res->ai_family) {
+				case AF_INET:
+#ifdef INET6
+					if (tproto == Q_IPV6)
+						continue;
+#endif
+
+					sin4 = (struct sockaddr_in *)
+						res->ai_addr;
+					tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr),
+						0xffffffff, tproto, dir, q.addr);
+					break;
+#ifdef INET6
+				case AF_INET6:
+					if (tproto6 == Q_IP)
+						continue;
+
+					sin6 = (struct sockaddr_in6 *)
+						res->ai_addr;
+					tmp = gen_host6(cstate, &sin6->sin6_addr,
+						&mask128, tproto6, dir, q.addr);
+					break;
+#endif
+				default:
+					continue;
+				}
+				if (b)
+					gen_or(b, tmp);
+				b = tmp;
+			}
+			cstate->ai = NULL;
+			freeaddrinfo(res0);
+			if (b == NULL) {
+				bpf_error(cstate, "unknown host '%s'%s", name,
+				    (proto == Q_DEFAULT)
+					? ""
+					: " for specified address family");
+			}
+			return b;
+		}
+
+	case Q_PORT:
+		if (proto != Q_DEFAULT &&
+		    proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP)
+			bpf_error(cstate, "illegal qualifier of 'port'");
+		if (pcap_nametoport(name, &port, &real_proto) == 0)
+			bpf_error(cstate, "unknown port '%s'", name);
+		if (proto == Q_UDP) {
+			if (real_proto == IPPROTO_TCP)
+				bpf_error(cstate, "port '%s' is tcp", name);
+			else if (real_proto == IPPROTO_SCTP)
+				bpf_error(cstate, "port '%s' is sctp", name);
+			else
+				/* override PROTO_UNDEF */
+				real_proto = IPPROTO_UDP;
+		}
+		if (proto == Q_TCP) {
+			if (real_proto == IPPROTO_UDP)
+				bpf_error(cstate, "port '%s' is udp", name);
+
+			else if (real_proto == IPPROTO_SCTP)
+				bpf_error(cstate, "port '%s' is sctp", name);
+			else
+				/* override PROTO_UNDEF */
+				real_proto = IPPROTO_TCP;
+		}
+		if (proto == Q_SCTP) {
+			if (real_proto == IPPROTO_UDP)
+				bpf_error(cstate, "port '%s' is udp", name);
+
+			else if (real_proto == IPPROTO_TCP)
+				bpf_error(cstate, "port '%s' is tcp", name);
+			else
+				/* override PROTO_UNDEF */
+				real_proto = IPPROTO_SCTP;
+		}
+		if (port < 0)
+			bpf_error(cstate, "illegal port number %d < 0", port);
+		if (port > 65535)
+			bpf_error(cstate, "illegal port number %d > 65535", port);
+		b = gen_port(cstate, port, real_proto, dir);
+		gen_or(gen_port6(cstate, port, real_proto, dir), b);
+		return b;
+
+	case Q_PORTRANGE:
+		if (proto != Q_DEFAULT &&
+		    proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP)
+			bpf_error(cstate, "illegal qualifier of 'portrange'");
+		if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0)
+			bpf_error(cstate, "unknown port in range '%s'", name);
+		if (proto == Q_UDP) {
+			if (real_proto == IPPROTO_TCP)
+				bpf_error(cstate, "port in range '%s' is tcp", name);
+			else if (real_proto == IPPROTO_SCTP)
+				bpf_error(cstate, "port in range '%s' is sctp", name);
+			else
+				/* override PROTO_UNDEF */
+				real_proto = IPPROTO_UDP;
+		}
+		if (proto == Q_TCP) {
+			if (real_proto == IPPROTO_UDP)
+				bpf_error(cstate, "port in range '%s' is udp", name);
+			else if (real_proto == IPPROTO_SCTP)
+				bpf_error(cstate, "port in range '%s' is sctp", name);
+			else
+				/* override PROTO_UNDEF */
+				real_proto = IPPROTO_TCP;
+		}
+		if (proto == Q_SCTP) {
+			if (real_proto == IPPROTO_UDP)
+				bpf_error(cstate, "port in range '%s' is udp", name);
+			else if (real_proto == IPPROTO_TCP)
+				bpf_error(cstate, "port in range '%s' is tcp", name);
+			else
+				/* override PROTO_UNDEF */
+				real_proto = IPPROTO_SCTP;
+		}
+		if (port1 < 0)
+			bpf_error(cstate, "illegal port number %d < 0", port1);
+		if (port1 > 65535)
+			bpf_error(cstate, "illegal port number %d > 65535", port1);
+		if (port2 < 0)
+			bpf_error(cstate, "illegal port number %d < 0", port2);
+		if (port2 > 65535)
+			bpf_error(cstate, "illegal port number %d > 65535", port2);
+
+		b = gen_portrange(cstate, port1, port2, real_proto, dir);
+		gen_or(gen_portrange6(cstate, port1, port2, real_proto, dir), b);
+		return b;
+
+	case Q_GATEWAY:
+#ifndef INET6
+		eaddr = pcap_ether_hostton(name);
+		if (eaddr == NULL)
+			bpf_error(cstate, "unknown ether host: %s", name);
+
+		res = pcap_nametoaddrinfo(name);
+		cstate->ai = res;
+		if (res == NULL)
+			bpf_error(cstate, "unknown host '%s'", name);
+		b = gen_gateway(cstate, eaddr, res, proto, dir);
+		cstate->ai = NULL;
+		freeaddrinfo(res);
+		if (b == NULL)
+			bpf_error(cstate, "unknown host '%s'", name);
+		return b;
+#else
+		bpf_error(cstate, "'gateway' not supported in this configuration");
+#endif /*INET6*/
+
+	case Q_PROTO:
+		real_proto = lookup_proto(cstate, name, proto);
+		if (real_proto >= 0)
+			return gen_proto(cstate, real_proto, proto, dir);
+		else
+			bpf_error(cstate, "unknown protocol: %s", name);
+
+	case Q_PROTOCHAIN:
+		real_proto = lookup_proto(cstate, name, proto);
+		if (real_proto >= 0)
+			return gen_protochain(cstate, real_proto, proto);
+		else
+			bpf_error(cstate, "unknown protocol: %s", name);
+
+	case Q_UNDEF:
+		syntax(cstate);
+		/*NOTREACHED*/
+	}
+	abort();
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
+    bpf_u_int32 masklen, struct qual q)
+{
+	register int nlen, mlen;
+	bpf_u_int32 n, m;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	nlen = __pcap_atoin(s1, &n);
+	if (nlen < 0)
+		bpf_error(cstate, "invalid IPv4 address '%s'", s1);
+	/* Promote short ipaddr */
+	n <<= 32 - nlen;
+
+	if (s2 != NULL) {
+		mlen = __pcap_atoin(s2, &m);
+		if (mlen < 0)
+			bpf_error(cstate, "invalid IPv4 address '%s'", s2);
+		/* Promote short ipaddr */
+		m <<= 32 - mlen;
+		if ((n & ~m) != 0)
+			bpf_error(cstate, "non-network bits set in \"%s mask %s\"",
+			    s1, s2);
+	} else {
+		/* Convert mask len to mask */
+		if (masklen > 32)
+			bpf_error(cstate, "mask length must be <= 32");
+		if (masklen == 0) {
+			/*
+			 * X << 32 is not guaranteed by C to be 0; it's
+			 * undefined.
+			 */
+			m = 0;
+		} else
+			m = 0xffffffff << (32 - masklen);
+		if ((n & ~m) != 0)
+			bpf_error(cstate, "non-network bits set in \"%s/%d\"",
+			    s1, masklen);
+	}
+
+	switch (q.addr) {
+
+	case Q_NET:
+		return gen_host(cstate, n, m, q.proto, q.dir, q.addr);
+
+	default:
+		bpf_error(cstate, "Mask syntax for networks only");
+		/*NOTREACHED*/
+	}
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
+{
+	bpf_u_int32 mask;
+	int proto;
+	int dir;
+	register int vlen;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	proto = q.proto;
+	dir = q.dir;
+	if (s == NULL)
+		vlen = 32;
+	else if (q.proto == Q_DECNET) {
+		vlen = __pcap_atodn(s, &v);
+		if (vlen == 0)
+			bpf_error(cstate, "malformed decnet address '%s'", s);
+	} else {
+		vlen = __pcap_atoin(s, &v);
+		if (vlen < 0)
+			bpf_error(cstate, "invalid IPv4 address '%s'", s);
+	}
+
+	switch (q.addr) {
+
+	case Q_DEFAULT:
+	case Q_HOST:
+	case Q_NET:
+		if (proto == Q_DECNET)
+			return gen_host(cstate, v, 0, proto, dir, q.addr);
+		else if (proto == Q_LINK) {
+			bpf_error(cstate, "illegal link layer address");
+		} else {
+			mask = 0xffffffff;
+			if (s == NULL && q.addr == Q_NET) {
+				/* Promote short net number */
+				while (v && (v & 0xff000000) == 0) {
+					v <<= 8;
+					mask <<= 8;
+				}
+			} else {
+				/* Promote short ipaddr */
+				v <<= 32 - vlen;
+				mask <<= 32 - vlen ;
+			}
+			return gen_host(cstate, v, mask, proto, dir, q.addr);
+		}
+
+	case Q_PORT:
+		if (proto == Q_UDP)
+			proto = IPPROTO_UDP;
+		else if (proto == Q_TCP)
+			proto = IPPROTO_TCP;
+		else if (proto == Q_SCTP)
+			proto = IPPROTO_SCTP;
+		else if (proto == Q_DEFAULT)
+			proto = PROTO_UNDEF;
+		else
+			bpf_error(cstate, "illegal qualifier of 'port'");
+
+		if (v > 65535)
+			bpf_error(cstate, "illegal port number %u > 65535", v);
+
+	    {
+		struct block *b;
+		b = gen_port(cstate, v, proto, dir);
+		gen_or(gen_port6(cstate, v, proto, dir), b);
+		return b;
+	    }
+
+	case Q_PORTRANGE:
+		if (proto == Q_UDP)
+			proto = IPPROTO_UDP;
+		else if (proto == Q_TCP)
+			proto = IPPROTO_TCP;
+		else if (proto == Q_SCTP)
+			proto = IPPROTO_SCTP;
+		else if (proto == Q_DEFAULT)
+			proto = PROTO_UNDEF;
+		else
+			bpf_error(cstate, "illegal qualifier of 'portrange'");
+
+		if (v > 65535)
+			bpf_error(cstate, "illegal port number %u > 65535", v);
+
+	    {
+		struct block *b;
+		b = gen_portrange(cstate, v, v, proto, dir);
+		gen_or(gen_portrange6(cstate, v, v, proto, dir), b);
+		return b;
+	    }
+
+	case Q_GATEWAY:
+		bpf_error(cstate, "'gateway' requires a name");
+		/*NOTREACHED*/
+
+	case Q_PROTO:
+		return gen_proto(cstate, v, proto, dir);
+
+	case Q_PROTOCHAIN:
+		return gen_protochain(cstate, v, proto);
+
+	case Q_UNDEF:
+		syntax(cstate);
+		/*NOTREACHED*/
+
+	default:
+		abort();
+		/*NOTREACHED*/
+	}
+	/*NOTREACHED*/
+}
+
+#ifdef INET6
+struct block *
+gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
+    bpf_u_int32 masklen, struct qual q)
+{
+	struct addrinfo *res;
+	struct in6_addr *addr;
+	struct in6_addr mask;
+	struct block *b;
+	uint32_t *a, *m;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if (s2)
+		bpf_error(cstate, "no mask %s supported", s2);
+
+	res = pcap_nametoaddrinfo(s1);
+	if (!res)
+		bpf_error(cstate, "invalid ip6 address %s", s1);
+	cstate->ai = res;
+	if (res->ai_next)
+		bpf_error(cstate, "%s resolved to multiple address", s1);
+	addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+
+	if (masklen > sizeof(mask.s6_addr) * 8)
+		bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask.s6_addr) * 8));
+	memset(&mask, 0, sizeof(mask));
+	memset(&mask.s6_addr, 0xff, masklen / 8);
+	if (masklen % 8) {
+		mask.s6_addr[masklen / 8] =
+			(0xff << (8 - masklen % 8)) & 0xff;
+	}
+
+	a = (uint32_t *)addr;
+	m = (uint32_t *)&mask;
+	if ((a[0] & ~m[0]) || (a[1] & ~m[1])
+	 || (a[2] & ~m[2]) || (a[3] & ~m[3])) {
+		bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen);
+	}
+
+	switch (q.addr) {
+
+	case Q_DEFAULT:
+	case Q_HOST:
+		if (masklen != 128)
+			bpf_error(cstate, "Mask syntax for networks only");
+		/* FALLTHROUGH */
+
+	case Q_NET:
+		b = gen_host6(cstate, addr, &mask, q.proto, q.dir, q.addr);
+		cstate->ai = NULL;
+		freeaddrinfo(res);
+		return b;
+
+	default:
+		bpf_error(cstate, "invalid qualifier against IPv6 address");
+		/*NOTREACHED*/
+	}
+}
+#endif /*INET6*/
+
+struct block *
+gen_ecode(compiler_state_t *cstate, const char *s, struct qual q)
+{
+	struct block *b, *tmp;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
+		cstate->e = pcap_ether_aton(s);
+		if (cstate->e == NULL)
+			bpf_error(cstate, "malloc");
+		switch (cstate->linktype) {
+		case DLT_EN10MB:
+		case DLT_NETANALYZER:
+		case DLT_NETANALYZER_TRANSPARENT:
+			tmp = gen_prevlinkhdr_check(cstate);
+			b = gen_ehostop(cstate, cstate->e, (int)q.dir);
+			if (tmp != NULL)
+				gen_and(tmp, b);
+			break;
+		case DLT_FDDI:
+			b = gen_fhostop(cstate, cstate->e, (int)q.dir);
+			break;
+		case DLT_IEEE802:
+			b = gen_thostop(cstate, cstate->e, (int)q.dir);
+			break;
+		case DLT_IEEE802_11:
+		case DLT_PRISM_HEADER:
+		case DLT_IEEE802_11_RADIO_AVS:
+		case DLT_IEEE802_11_RADIO:
+		case DLT_PPI:
+			b = gen_wlanhostop(cstate, cstate->e, (int)q.dir);
+			break;
+		case DLT_IP_OVER_FC:
+			b = gen_ipfchostop(cstate, cstate->e, (int)q.dir);
+			break;
+		default:
+			free(cstate->e);
+			cstate->e = NULL;
+			bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+			/*NOTREACHED*/
+		}
+		free(cstate->e);
+		cstate->e = NULL;
+		return (b);
+	}
+	bpf_error(cstate, "ethernet address used in non-ether expression");
+	/*NOTREACHED*/
+}
+
+void
+sappend(struct slist *s0, struct slist *s1)
+{
+	/*
+	 * This is definitely not the best way to do this, but the
+	 * lists will rarely get long.
+	 */
+	while (s0->next)
+		s0 = s0->next;
+	s0->next = s1;
+}
+
+static struct slist *
+xfer_to_x(compiler_state_t *cstate, struct arth *a)
+{
+	struct slist *s;
+
+	s = new_stmt(cstate, BPF_LDX|BPF_MEM);
+	s->s.k = a->regno;
+	return s;
+}
+
+static struct slist *
+xfer_to_a(compiler_state_t *cstate, struct arth *a)
+{
+	struct slist *s;
+
+	s = new_stmt(cstate, BPF_LD|BPF_MEM);
+	s->s.k = a->regno;
+	return s;
+}
+
+/*
+ * Modify "index" to use the value stored into its register as an
+ * offset relative to the beginning of the header for the protocol
+ * "proto", and allocate a register and put an item "size" bytes long
+ * (1, 2, or 4) at that offset into that register, making it the register
+ * for "index".
+ */
+static struct arth *
+gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst,
+    bpf_u_int32 size)
+{
+	int size_code;
+	struct slist *s, *tmp;
+	struct block *b;
+	int regno = alloc_reg(cstate);
+
+	free_reg(cstate, inst->regno);
+	switch (size) {
+
+	default:
+		bpf_error(cstate, "data size must be 1, 2, or 4");
+		/*NOTREACHED*/
+
+	case 1:
+		size_code = BPF_B;
+		break;
+
+	case 2:
+		size_code = BPF_H;
+		break;
+
+	case 4:
+		size_code = BPF_W;
+		break;
+	}
+	switch (proto) {
+	default:
+		bpf_error(cstate, "unsupported index operation");
+
+	case Q_RADIO:
+		/*
+		 * The offset is relative to the beginning of the packet
+		 * data, if we have a radio header.  (If we don't, this
+		 * is an error.)
+		 */
+		if (cstate->linktype != DLT_IEEE802_11_RADIO_AVS &&
+		    cstate->linktype != DLT_IEEE802_11_RADIO &&
+		    cstate->linktype != DLT_PRISM_HEADER)
+			bpf_error(cstate, "radio information not present in capture");
+
+		/*
+		 * Load into the X register the offset computed into the
+		 * register specified by "index".
+		 */
+		s = xfer_to_x(cstate, inst);
+
+		/*
+		 * Load the item at that offset.
+		 */
+		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+		sappend(s, tmp);
+		sappend(inst->s, s);
+		break;
+
+	case Q_LINK:
+		/*
+		 * The offset is relative to the beginning of
+		 * the link-layer header.
+		 *
+		 * XXX - what about ATM LANE?  Should the index be
+		 * relative to the beginning of the AAL5 frame, so
+		 * that 0 refers to the beginning of the LE Control
+		 * field, or relative to the beginning of the LAN
+		 * frame, so that 0 refers, for Ethernet LANE, to
+		 * the beginning of the destination address?
+		 */
+		s = gen_abs_offset_varpart(cstate, &cstate->off_linkhdr);
+
+		/*
+		 * 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
+		 * register the offset computed into the register specified
+		 * by "index".
+		 */
+		if (s != NULL) {
+			sappend(s, xfer_to_a(cstate, inst));
+			sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+			sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+		} else
+			s = xfer_to_x(cstate, inst);
+
+		/*
+		 * Load the item at the sum of the offset we've put in the
+		 * X register 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).
+		 */
+		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+		tmp->s.k = cstate->off_linkhdr.constant_part;
+		sappend(s, tmp);
+		sappend(inst->s, s);
+		break;
+
+	case Q_IP:
+	case Q_ARP:
+	case Q_RARP:
+	case Q_ATALK:
+	case Q_DECNET:
+	case Q_SCA:
+	case Q_LAT:
+	case Q_MOPRC:
+	case Q_MOPDL:
+	case Q_IPV6:
+		/*
+		 * The offset is relative to the beginning of
+		 * the network-layer header.
+		 * XXX - are there any cases where we want
+		 * cstate->off_nl_nosnap?
+		 */
+		s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+
+		/*
+		 * If "s" is non-null, it has code to arrange that the
+		 * X register contains the variable part of the offset
+		 * of the link-layer payload.  Add to it the offset
+		 * computed into the register specified by "index",
+		 * and move that into the X register.  Otherwise, just
+		 * load into the X register the offset computed into
+		 * the register specified by "index".
+		 */
+		if (s != NULL) {
+			sappend(s, xfer_to_a(cstate, inst));
+			sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+			sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+		} else
+			s = xfer_to_x(cstate, inst);
+
+		/*
+		 * Load the item at the sum of the offset we've put in the
+		 * X register, the offset of the start of the network
+		 * layer header from the beginning of the link-layer
+		 * payload, and the constant part of the offset of the
+		 * start of the link-layer payload.
+		 */
+		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+		tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+		sappend(s, tmp);
+		sappend(inst->s, s);
+
+		/*
+		 * Do the computation only if the packet contains
+		 * the protocol in question.
+		 */
+		b = gen_proto_abbrev_internal(cstate, proto);
+		if (inst->b)
+			gen_and(inst->b, b);
+		inst->b = b;
+		break;
+
+	case Q_SCTP:
+	case Q_TCP:
+	case Q_UDP:
+	case Q_ICMP:
+	case Q_IGMP:
+	case Q_IGRP:
+	case Q_PIM:
+	case Q_VRRP:
+	case Q_CARP:
+		/*
+		 * The offset is relative to the beginning of
+		 * the transport-layer header.
+		 *
+		 * Load the X register with the length of the IPv4 header
+		 * (plus the offset of the link-layer header, if it's
+		 * a variable-length header), in bytes.
+		 *
+		 * XXX - are there any cases where we want
+		 * cstate->off_nl_nosnap?
+		 * XXX - we should, if we're built with
+		 * IPv6 support, generate code to load either
+		 * IPv4, IPv6, or both, as appropriate.
+		 */
+		s = gen_loadx_iphdrlen(cstate);
+
+		/*
+		 * The X register now contains the sum of the variable
+		 * part of the offset of the link-layer payload 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 sum of the constant part of
+		 * the offset of the link-layer payload and the offset,
+		 * relative to the beginning of the link-layer payload,
+		 * of the network-layer header.
+		 */
+		sappend(s, xfer_to_a(cstate, inst));
+		sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+		sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+		sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code));
+		tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+		sappend(inst->s, s);
+
+		/*
+		 * Do the computation only if the packet contains
+		 * the protocol in question - which is true only
+		 * if this is an IP datagram and is the first or
+		 * only fragment of that datagram.
+		 */
+		gen_and(gen_proto_abbrev_internal(cstate, proto), b = gen_ipfrag(cstate));
+		if (inst->b)
+			gen_and(inst->b, b);
+		gen_and(gen_proto_abbrev_internal(cstate, Q_IP), b);
+		inst->b = b;
+		break;
+	case Q_ICMPV6:
+        /*
+        * Do the computation only if the packet contains
+        * the protocol in question.
+        */
+        b = gen_proto_abbrev_internal(cstate, Q_IPV6);
+        if (inst->b) {
+            gen_and(inst->b, b);
+        }
+        inst->b = b;
+
+        /*
+        * Check if we have an icmp6 next header
+        */
+        b = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, 58);
+        if (inst->b) {
+            gen_and(inst->b, b);
+        }
+        inst->b = b;
+
+
+        s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+        /*
+        * If "s" is non-null, it has code to arrange that the
+        * X register contains the variable part of the offset
+        * of the link-layer payload.  Add to it the offset
+        * computed into the register specified by "index",
+        * and move that into the X register.  Otherwise, just
+        * load into the X register the offset computed into
+        * the register specified by "index".
+        */
+        if (s != NULL) {
+            sappend(s, xfer_to_a(cstate, inst));
+            sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+            sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+        } else {
+            s = xfer_to_x(cstate, inst);
+        }
+
+        /*
+        * Load the item at the sum of the offset we've put in the
+        * X register, the offset of the start of the network
+        * layer header from the beginning of the link-layer
+        * payload, and the constant part of the offset of the
+        * start of the link-layer payload.
+        */
+        tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+        tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40;
+
+        sappend(s, tmp);
+        sappend(inst->s, s);
+
+        break;
+	}
+	inst->regno = regno;
+	s = new_stmt(cstate, BPF_ST);
+	s->s.k = regno;
+	sappend(inst->s, s);
+
+	return inst;
+}
+
+struct arth *
+gen_load(compiler_state_t *cstate, int proto, struct arth *inst,
+    bpf_u_int32 size)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	return gen_load_internal(cstate, proto, inst, size);
+}
+
+static struct block *
+gen_relation_internal(compiler_state_t *cstate, int code, struct arth *a0,
+    struct arth *a1, int reversed)
+{
+	struct slist *s0, *s1, *s2;
+	struct block *b, *tmp;
+
+	s0 = xfer_to_x(cstate, a1);
+	s1 = xfer_to_a(cstate, a0);
+	if (code == BPF_JEQ) {
+		s2 = new_stmt(cstate, BPF_ALU|BPF_SUB|BPF_X);
+		b = new_block(cstate, JMP(code));
+		sappend(s1, s2);
+	}
+	else
+		b = new_block(cstate, BPF_JMP|code|BPF_X);
+	if (reversed)
+		gen_not(b);
+
+	sappend(s0, s1);
+	sappend(a1->s, s0);
+	sappend(a0->s, a1->s);
+
+	b->stmts = a0->s;
+
+	free_reg(cstate, a0->regno);
+	free_reg(cstate, a1->regno);
+
+	/* 'and' together protocol checks */
+	if (a0->b) {
+		if (a1->b) {
+			gen_and(a0->b, tmp = a1->b);
+		}
+		else
+			tmp = a0->b;
+	} else
+		tmp = a1->b;
+
+	if (tmp)
+		gen_and(tmp, b);
+
+	return b;
+}
+
+struct block *
+gen_relation(compiler_state_t *cstate, int code, struct arth *a0,
+    struct arth *a1, int reversed)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	return gen_relation_internal(cstate, code, a0, a1, reversed);
+}
+
+struct arth *
+gen_loadlen(compiler_state_t *cstate)
+{
+	int regno;
+	struct arth *a;
+	struct slist *s;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	regno = alloc_reg(cstate);
+	a = (struct arth *)newchunk(cstate, sizeof(*a));
+	s = new_stmt(cstate, BPF_LD|BPF_LEN);
+	s->next = new_stmt(cstate, BPF_ST);
+	s->next->s.k = regno;
+	a->s = s;
+	a->regno = regno;
+
+	return a;
+}
+
+static struct arth *
+gen_loadi_internal(compiler_state_t *cstate, bpf_u_int32 val)
+{
+	struct arth *a;
+	struct slist *s;
+	int reg;
+
+	a = (struct arth *)newchunk(cstate, sizeof(*a));
+
+	reg = alloc_reg(cstate);
+
+	s = new_stmt(cstate, BPF_LD|BPF_IMM);
+	s->s.k = val;
+	s->next = new_stmt(cstate, BPF_ST);
+	s->next->s.k = reg;
+	a->s = s;
+	a->regno = reg;
+
+	return a;
+}
+
+struct arth *
+gen_loadi(compiler_state_t *cstate, bpf_u_int32 val)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	return gen_loadi_internal(cstate, val);
+}
+
+/*
+ * The a_arg dance is to avoid annoying whining by compilers that
+ * a might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct arth *
+gen_neg(compiler_state_t *cstate, struct arth *a_arg)
+{
+	struct arth *a = a_arg;
+	struct slist *s;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	s = xfer_to_a(cstate, a);
+	sappend(a->s, s);
+	s = new_stmt(cstate, BPF_ALU|BPF_NEG);
+	s->s.k = 0;
+	sappend(a->s, s);
+	s = new_stmt(cstate, BPF_ST);
+	s->s.k = a->regno;
+	sappend(a->s, s);
+
+	return a;
+}
+
+/*
+ * The a0_arg dance is to avoid annoying whining by compilers that
+ * a0 might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct arth *
+gen_arth(compiler_state_t *cstate, int code, struct arth *a0_arg,
+    struct arth *a1)
+{
+	struct arth *a0 = a0_arg;
+	struct slist *s0, *s1, *s2;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Disallow division by, or modulus by, zero; we do this here
+	 * so that it gets done even if the optimizer is disabled.
+	 *
+	 * Also disallow shifts by a value greater than 31; we do this
+	 * here, for the same reason.
+	 */
+	if (code == BPF_DIV) {
+		if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
+			bpf_error(cstate, "division by zero");
+	} else if (code == BPF_MOD) {
+		if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
+			bpf_error(cstate, "modulus by zero");
+	} else if (code == BPF_LSH || code == BPF_RSH) {
+		if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k > 31)
+			bpf_error(cstate, "shift by more than 31 bits");
+	}
+	s0 = xfer_to_x(cstate, a1);
+	s1 = xfer_to_a(cstate, a0);
+	s2 = new_stmt(cstate, BPF_ALU|BPF_X|code);
+
+	sappend(s1, s2);
+	sappend(s0, s1);
+	sappend(a1->s, s0);
+	sappend(a0->s, a1->s);
+
+	free_reg(cstate, a0->regno);
+	free_reg(cstate, a1->regno);
+
+	s0 = new_stmt(cstate, BPF_ST);
+	a0->regno = s0->s.k = alloc_reg(cstate);
+	sappend(a0->s, s0);
+
+	return a0;
+}
+
+/*
+ * Initialize the table of used registers and the current register.
+ */
+static void
+init_regs(compiler_state_t *cstate)
+{
+	cstate->curreg = 0;
+	memset(cstate->regused, 0, sizeof cstate->regused);
+}
+
+/*
+ * Return the next free register.
+ */
+static int
+alloc_reg(compiler_state_t *cstate)
+{
+	int n = BPF_MEMWORDS;
+
+	while (--n >= 0) {
+		if (cstate->regused[cstate->curreg])
+			cstate->curreg = (cstate->curreg + 1) % BPF_MEMWORDS;
+		else {
+			cstate->regused[cstate->curreg] = 1;
+			return cstate->curreg;
+		}
+	}
+	bpf_error(cstate, "too many registers needed to evaluate expression");
+	/*NOTREACHED*/
+}
+
+/*
+ * Return a register to the table so it can
+ * be used later.
+ */
+static void
+free_reg(compiler_state_t *cstate, int n)
+{
+	cstate->regused[n] = 0;
+}
+
+static struct block *
+gen_len(compiler_state_t *cstate, int jmp, int n)
+{
+	struct slist *s;
+	struct block *b;
+
+	s = new_stmt(cstate, BPF_LD|BPF_LEN);
+	b = new_block(cstate, JMP(jmp));
+	b->stmts = s;
+	b->s.k = n;
+
+	return b;
+}
+
+struct block *
+gen_greater(compiler_state_t *cstate, int n)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	return gen_len(cstate, BPF_JGE, n);
+}
+
+/*
+ * Actually, this is less than or equal.
+ */
+struct block *
+gen_less(compiler_state_t *cstate, int n)
+{
+	struct block *b;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	b = gen_len(cstate, BPF_JGT, n);
+	gen_not(b);
+
+	return b;
+}
+
+/*
+ * This is for "byte {idx} {op} {val}"; "idx" is treated as relative to
+ * the beginning of the link-layer header.
+ * XXX - that means you can't test values in the radiotap header, but
+ * as that header is difficult if not impossible to parse generally
+ * without a loop, that might not be a severe problem.  A new keyword
+ * "radio" could be added for that, although what you'd really want
+ * would be a way of testing particular radio header values, which
+ * would generate code appropriate to the radio header in question.
+ */
+struct block *
+gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
+{
+	struct block *b;
+	struct slist *s;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (op) {
+	default:
+		abort();
+
+	case '=':
+		return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
+
+	case '<':
+		b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
+		return b;
+
+	case '>':
+		b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
+		return b;
+
+	case '|':
+		s = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_K);
+		break;
+
+	case '&':
+		s = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+		break;
+	}
+	s->s.k = val;
+	b = new_block(cstate, JMP(BPF_JEQ));
+	b->stmts = s;
+	gen_not(b);
+
+	return b;
+}
+
+static const u_char abroadcast[] = { 0x0 };
+
+struct block *
+gen_broadcast(compiler_state_t *cstate, int proto)
+{
+	bpf_u_int32 hostmask;
+	struct block *b0, *b1, *b2;
+	static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (proto) {
+
+	case Q_DEFAULT:
+	case Q_LINK:
+		switch (cstate->linktype) {
+		case DLT_ARCNET:
+		case DLT_ARCNET_LINUX:
+			return gen_ahostop(cstate, abroadcast, Q_DST);
+		case DLT_EN10MB:
+		case DLT_NETANALYZER:
+		case DLT_NETANALYZER_TRANSPARENT:
+			b1 = gen_prevlinkhdr_check(cstate);
+			b0 = gen_ehostop(cstate, ebroadcast, Q_DST);
+			if (b1 != NULL)
+				gen_and(b1, b0);
+			return b0;
+		case DLT_FDDI:
+			return gen_fhostop(cstate, ebroadcast, Q_DST);
+		case DLT_IEEE802:
+			return gen_thostop(cstate, ebroadcast, Q_DST);
+		case DLT_IEEE802_11:
+		case DLT_PRISM_HEADER:
+		case DLT_IEEE802_11_RADIO_AVS:
+		case DLT_IEEE802_11_RADIO:
+		case DLT_PPI:
+			return gen_wlanhostop(cstate, ebroadcast, Q_DST);
+		case DLT_IP_OVER_FC:
+			return gen_ipfchostop(cstate, ebroadcast, Q_DST);
+		default:
+			bpf_error(cstate, "not a broadcast link");
+		}
+ 		/*NOTREACHED*/
+
+	case Q_IP:
+		/*
+		 * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff)
+		 * as an indication that we don't know the netmask, and fail
+		 * in that case.
+		 */
+		if (cstate->netmask == PCAP_NETMASK_UNKNOWN)
+			bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported");
+		b0 = gen_linktype(cstate, ETHERTYPE_IP);
+		hostmask = ~cstate->netmask;
+		b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, 0, hostmask);
+		b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W,
+			      ~0 & hostmask, hostmask);
+		gen_or(b1, b2);
+		gen_and(b0, b2);
+		return b2;
+	}
+	bpf_error(cstate, "only link-layer/IP broadcast filters supported");
+	/*NOTREACHED*/
+}
+
+/*
+ * Generate code to test the low-order bit of a MAC address (that's
+ * the bottom bit of the *first* byte).
+ */
+static struct block *
+gen_mac_multicast(compiler_state_t *cstate, int offset)
+{
+	register struct block *b0;
+	register struct slist *s;
+
+	/* link[offset] & 1 != 0 */
+	s = gen_load_a(cstate, OR_LINKHDR, offset, BPF_B);
+	b0 = new_block(cstate, JMP(BPF_JSET));
+	b0->s.k = 1;
+	b0->stmts = s;
+	return b0;
+}
+
+struct block *
+gen_multicast(compiler_state_t *cstate, int proto)
+{
+	register struct block *b0, *b1, *b2;
+	register struct slist *s;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (proto) {
+
+	case Q_DEFAULT:
+	case Q_LINK:
+		switch (cstate->linktype) {
+		case DLT_ARCNET:
+		case DLT_ARCNET_LINUX:
+			/* all ARCnet multicasts use the same address */
+			return gen_ahostop(cstate, abroadcast, Q_DST);
+		case DLT_EN10MB:
+		case DLT_NETANALYZER:
+		case DLT_NETANALYZER_TRANSPARENT:
+			b1 = gen_prevlinkhdr_check(cstate);
+			/* ether[0] & 1 != 0 */
+			b0 = gen_mac_multicast(cstate, 0);
+			if (b1 != NULL)
+				gen_and(b1, b0);
+			return b0;
+		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(cstate, 1);
+		case DLT_IEEE802:
+			/* tr[2] & 1 != 0 */
+			return gen_mac_multicast(cstate, 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(cstate, OR_LINKHDR, 1, BPF_B);
+			b1 = new_block(cstate, JMP(BPF_JSET));
+			b1->s.k = 0x01;	/* To DS */
+			b1->stmts = s;
+
+			/*
+			 * If To DS is set, the DA is at 16.
+			 */
+			b0 = gen_mac_multicast(cstate, 16);
+			gen_and(b1, b0);
+
+			/*
+			 * Now, check for To DS not set, i.e. check
+			 * "!(link[1] & 0x01)".
+			 */
+			s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+			b2 = new_block(cstate, JMP(BPF_JSET));
+			b2->s.k = 0x01;	/* To DS */
+			b2->stmts = s;
+			gen_not(b2);
+
+			/*
+			 * If To DS is not set, the DA is at 4.
+			 */
+			b1 = gen_mac_multicast(cstate, 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(cstate, OR_LINKHDR, 0, BPF_B);
+			b1 = new_block(cstate, 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(cstate, OR_LINKHDR, 0, BPF_B);
+			b2 = new_block(cstate, 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(cstate, 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(cstate, OR_LINKHDR, 0, BPF_B);
+			b1 = new_block(cstate, 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(cstate, 2);
+			return b0;
+		default:
+			break;
+		}
+		/* Link not known to support multicasts */
+		break;
+
+	case Q_IP:
+		b0 = gen_linktype(cstate, ETHERTYPE_IP);
+		b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, 224);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_IPV6:
+		b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+		b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, 255);
+		gen_and(b0, b1);
+		return b1;
+	}
+	bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel");
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_ifindex(compiler_state_t *cstate, int ifindex)
+{
+	register struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Only some data link types support ifindex qualifiers.
+	 */
+	switch (cstate->linktype) {
+	case DLT_LINUX_SLL2:
+		/* match packets on this interface */
+		b0 = gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex);
+		break;
+        default:
+#if defined(linux)
+		/*
+		 * This is Linux; we require PF_PACKET support.
+		 * If this is a *live* capture, we can look at
+		 * special meta-data in the filter expression;
+		 * if it's a savefile, we can't.
+		 */
+		if (cstate->bpf_pcap->rfile != NULL) {
+			/* We have a FILE *, so this is a savefile */
+			bpf_error(cstate, "ifindex not supported on %s when reading savefiles",
+			    pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+			b0 = NULL;
+			/*NOTREACHED*/
+		}
+		/* match ifindex */
+		b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W,
+		             ifindex);
+#else /* defined(linux) */
+		bpf_error(cstate, "ifindex not supported on %s",
+		    pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+		/*NOTREACHED*/
+#endif /* defined(linux) */
+	}
+	return (b0);
+}
+
+/*
+ * Filter on inbound (dir == 0) or outbound (dir == 1) traffic.
+ * Outbound traffic is sent by this machine, while inbound traffic is
+ * sent by a remote machine (and may include packets destined for a
+ * unicast or multicast link-layer address we are not subscribing to).
+ * These are the same definitions implemented by pcap_setdirection().
+ * Capturing only unicast traffic destined for this host is probably
+ * better accomplished using a higher-layer filter.
+ */
+struct block *
+gen_inbound(compiler_state_t *cstate, int dir)
+{
+	register struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Only some data link types support inbound/outbound qualifiers.
+	 */
+	switch (cstate->linktype) {
+	case DLT_SLIP:
+		b0 = gen_relation_internal(cstate, BPF_JEQ,
+			  gen_load_internal(cstate, Q_LINK, gen_loadi_internal(cstate, 0), 1),
+			  gen_loadi_internal(cstate, 0),
+			  dir);
+		break;
+
+	case DLT_IPNET:
+		if (dir) {
+			/* match outgoing packets */
+			b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND);
+		} else {
+			/* match incoming packets */
+			b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_INBOUND);
+		}
+		break;
+
+	case DLT_LINUX_SLL:
+		/* match outgoing packets */
+		b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING);
+		if (!dir) {
+			/* to filter on inbound traffic, invert the match */
+			gen_not(b0);
+		}
+		break;
+
+	case DLT_LINUX_SLL2:
+		/* match outgoing packets */
+		b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING);
+		if (!dir) {
+			/* to filter on inbound traffic, invert the match */
+			gen_not(b0);
+		}
+		break;
+
+#ifdef HAVE_NET_PFVAR_H
+	case DLT_PFLOG:
+		b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
+		    ((dir == 0) ? PF_IN : PF_OUT));
+		break;
+#endif
+
+	case DLT_PPP_PPPD:
+		if (dir) {
+			/* match outgoing packets */
+			b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT);
+		} else {
+			/* match incoming packets */
+			b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN);
+		}
+		break;
+
+        case DLT_JUNIPER_MFR:
+        case DLT_JUNIPER_MLFR:
+        case DLT_JUNIPER_MLPPP:
+	case DLT_JUNIPER_ATM1:
+	case DLT_JUNIPER_ATM2:
+	case DLT_JUNIPER_PPPOE:
+	case DLT_JUNIPER_PPPOE_ATM:
+        case DLT_JUNIPER_GGSN:
+        case DLT_JUNIPER_ES:
+        case DLT_JUNIPER_MONITOR:
+        case DLT_JUNIPER_SERVICES:
+        case DLT_JUNIPER_ETHER:
+        case DLT_JUNIPER_PPP:
+        case DLT_JUNIPER_FRELAY:
+        case DLT_JUNIPER_CHDLC:
+        case DLT_JUNIPER_VP:
+        case DLT_JUNIPER_ST:
+        case DLT_JUNIPER_ISM:
+        case DLT_JUNIPER_VS:
+        case DLT_JUNIPER_SRX_E2E:
+        case DLT_JUNIPER_FIBRECHANNEL:
+	case DLT_JUNIPER_ATM_CEMIC:
+
+		/* juniper flags (including direction) are stored
+		 * the byte after the 3-byte magic number */
+		if (dir) {
+			/* match outgoing packets */
+			b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 0, 0x01);
+		} else {
+			/* match incoming packets */
+			b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 1, 0x01);
+		}
+		break;
+
+	default:
+		/*
+		 * If we have packet meta-data indicating a direction,
+		 * and that metadata can be checked by BPF code, check
+		 * it.  Otherwise, give up, as this link-layer type has
+		 * nothing in the packet data.
+		 *
+		 * Currently, the only platform where a BPF filter can
+		 * check that metadata is Linux with the in-kernel
+		 * BPF interpreter.  If other packet capture mechanisms
+		 * and BPF filters also supported this, it would be
+		 * nice.  It would be even better if they made that
+		 * metadata available so that we could provide it
+		 * with newer capture APIs, allowing it to be saved
+		 * in pcapng files.
+		 */
+#if defined(linux)
+		/*
+		 * This is Linux; we require PF_PACKET support.
+		 * If this is a *live* capture, we can look at
+		 * special meta-data in the filter expression;
+		 * if it's a savefile, we can't.
+		 */
+		if (cstate->bpf_pcap->rfile != NULL) {
+			/* We have a FILE *, so this is a savefile */
+			bpf_error(cstate, "inbound/outbound not supported on %s when reading savefiles",
+			    pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+			/*NOTREACHED*/
+		}
+		/* match outgoing packets */
+		b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H,
+		             PACKET_OUTGOING);
+		if (!dir) {
+			/* to filter on inbound traffic, invert the match */
+			gen_not(b0);
+		}
+#else /* defined(linux) */
+		bpf_error(cstate, "inbound/outbound not supported on %s",
+		    pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+		/*NOTREACHED*/
+#endif /* defined(linux) */
+	}
+	return (b0);
+}
+
+#ifdef HAVE_NET_PFVAR_H
+/* PF firewall log matched interface */
+struct block *
+gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
+{
+	struct block *b0;
+	u_int len, off;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if (cstate->linktype != DLT_PFLOG) {
+		bpf_error(cstate, "ifname supported only on PF linktype");
+		/*NOTREACHED*/
+	}
+	len = sizeof(((struct pfloghdr *)0)->ifname);
+	off = offsetof(struct pfloghdr, ifname);
+	if (strlen(ifname) >= len) {
+		bpf_error(cstate, "ifname interface names can only be %d characters",
+		    len-1);
+		/*NOTREACHED*/
+	}
+	b0 = gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname),
+	    (const u_char *)ifname);
+	return (b0);
+}
+
+/* PF firewall log ruleset name */
+struct block *
+gen_pf_ruleset(compiler_state_t *cstate, char *ruleset)
+{
+	struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if (cstate->linktype != DLT_PFLOG) {
+		bpf_error(cstate, "ruleset supported only on PF linktype");
+		/*NOTREACHED*/
+	}
+
+	if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) {
+		bpf_error(cstate, "ruleset names can only be %ld characters",
+		    (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1));
+		/*NOTREACHED*/
+	}
+
+	b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset),
+	    (u_int)strlen(ruleset), (const u_char *)ruleset);
+	return (b0);
+}
+
+/* PF firewall log rule number */
+struct block *
+gen_pf_rnr(compiler_state_t *cstate, int rnr)
+{
+	struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if (cstate->linktype != DLT_PFLOG) {
+		bpf_error(cstate, "rnr supported only on PF linktype");
+		/*NOTREACHED*/
+	}
+
+	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
+		 (bpf_u_int32)rnr);
+	return (b0);
+}
+
+/* PF firewall log sub-rule number */
+struct block *
+gen_pf_srnr(compiler_state_t *cstate, int srnr)
+{
+	struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if (cstate->linktype != DLT_PFLOG) {
+		bpf_error(cstate, "srnr supported only on PF linktype");
+		/*NOTREACHED*/
+	}
+
+	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
+	    (bpf_u_int32)srnr);
+	return (b0);
+}
+
+/* PF firewall log reason code */
+struct block *
+gen_pf_reason(compiler_state_t *cstate, int reason)
+{
+	struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if (cstate->linktype != DLT_PFLOG) {
+		bpf_error(cstate, "reason supported only on PF linktype");
+		/*NOTREACHED*/
+	}
+
+	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
+	    (bpf_u_int32)reason);
+	return (b0);
+}
+
+/* PF firewall log action */
+struct block *
+gen_pf_action(compiler_state_t *cstate, int action)
+{
+	struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	if (cstate->linktype != DLT_PFLOG) {
+		bpf_error(cstate, "action supported only on PF linktype");
+		/*NOTREACHED*/
+	}
+
+	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
+	    (bpf_u_int32)action);
+	return (b0);
+}
+#else /* !HAVE_NET_PFVAR_H */
+struct block *
+gen_pf_ifname(compiler_state_t *cstate, const char *ifname _U_)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	bpf_error(cstate, "libpcap was compiled without pf support");
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_pf_ruleset(compiler_state_t *cstate, char *ruleset _U_)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_pf_rnr(compiler_state_t *cstate, int rnr _U_)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_pf_srnr(compiler_state_t *cstate, int srnr _U_)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_pf_reason(compiler_state_t *cstate, int reason _U_)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+	/*NOTREACHED*/
+}
+
+struct block *
+gen_pf_action(compiler_state_t *cstate, int action _U_)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+	/*NOTREACHED*/
+}
+#endif /* HAVE_NET_PFVAR_H */
+
+/* IEEE 802.11 wireless header */
+struct block *
+gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask)
+{
+	struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (cstate->linktype) {
+
+	case DLT_IEEE802_11:
+	case DLT_PRISM_HEADER:
+	case DLT_IEEE802_11_RADIO_AVS:
+	case DLT_IEEE802_11_RADIO:
+		b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask);
+		break;
+
+	default:
+		bpf_error(cstate, "802.11 link-layer types supported only on 802.11");
+		/*NOTREACHED*/
+	}
+
+	return (b0);
+}
+
+struct block *
+gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir)
+{
+	struct block *b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (cstate->linktype) {
+
+	case DLT_IEEE802_11:
+	case DLT_PRISM_HEADER:
+	case DLT_IEEE802_11_RADIO_AVS:
+	case DLT_IEEE802_11_RADIO:
+		break;
+
+	default:
+		bpf_error(cstate, "frame direction supported only with 802.11 headers");
+		/*NOTREACHED*/
+	}
+
+	b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir,
+	    IEEE80211_FC1_DIR_MASK);
+
+	return (b0);
+}
+
+struct block *
+gen_acode(compiler_state_t *cstate, const char *s, struct qual q)
+{
+	struct block *b;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (cstate->linktype) {
+
+	case DLT_ARCNET:
+	case DLT_ARCNET_LINUX:
+		if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) &&
+		    q.proto == Q_LINK) {
+			cstate->e = pcap_ether_aton(s);
+			if (cstate->e == NULL)
+				bpf_error(cstate, "malloc");
+			b = gen_ahostop(cstate, cstate->e, (int)q.dir);
+			free(cstate->e);
+			cstate->e = NULL;
+			return (b);
+		} else
+			bpf_error(cstate, "ARCnet address used in non-arc expression");
+ 		/*NOTREACHED*/
+
+	default:
+		bpf_error(cstate, "aid supported only on ARCnet");
+		/*NOTREACHED*/
+	}
+}
+
+static struct block *
+gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+	register struct block *b0, *b1;
+
+	switch (dir) {
+	/* src comes first, different from Ethernet */
+	case Q_SRC:
+		return gen_bcmp(cstate, OR_LINKHDR, 0, 1, eaddr);
+
+	case Q_DST:
+		return gen_bcmp(cstate, OR_LINKHDR, 1, 1, eaddr);
+
+	case Q_AND:
+		b0 = gen_ahostop(cstate, eaddr, Q_SRC);
+		b1 = gen_ahostop(cstate, eaddr, Q_DST);
+		gen_and(b0, b1);
+		return b1;
+
+	case Q_DEFAULT:
+	case Q_OR:
+		b0 = gen_ahostop(cstate, eaddr, Q_SRC);
+		b1 = gen_ahostop(cstate, eaddr, Q_DST);
+		gen_or(b0, b1);
+		return b1;
+
+	case Q_ADDR1:
+		bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+ 		/*NOTREACHED*/
+
+	case Q_ADDR2:
+		bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+ 		/*NOTREACHED*/
+
+	case Q_ADDR3:
+		bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+ 		/*NOTREACHED*/
+
+	case Q_ADDR4:
+		bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+ 		/*NOTREACHED*/
+
+	case Q_RA:
+		bpf_error(cstate, "'ra' is only supported on 802.11");
+ 		/*NOTREACHED*/
+
+	case Q_TA:
+		bpf_error(cstate, "'ta' is only supported on 802.11");
+ 		/*NOTREACHED*/
+	}
+	abort();
+	/*NOTREACHED*/
+}
+
+static struct block *
+gen_vlan_tpid_test(compiler_state_t *cstate)
+{
+	struct block *b0, *b1;
+
+	/* check for VLAN, including QinQ */
+	b0 = gen_linktype(cstate, ETHERTYPE_8021Q);
+	b1 = gen_linktype(cstate, ETHERTYPE_8021AD);
+	gen_or(b0,b1);
+	b0 = b1;
+	b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ);
+	gen_or(b0,b1);
+
+	return b1;
+}
+
+static struct block *
+gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num)
+{
+	if (vlan_num > 0x0fff) {
+		bpf_error(cstate, "VLAN tag %u greater than maximum %u",
+		    vlan_num, 0x0fff);
+	}
+	return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff);
+}
+
+static struct block *
+gen_vlan_no_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
+    int has_vlan_tag)
+{
+	struct block *b0, *b1;
+
+	b0 = gen_vlan_tpid_test(cstate);
+
+	if (has_vlan_tag) {
+		b1 = gen_vlan_vid_test(cstate, vlan_num);
+		gen_and(b0, b1);
+		b0 = b1;
+	}
+
+	/*
+	 * Both payload and link header type follow the VLAN tags so that
+	 * both need to be updated.
+	 */
+	cstate->off_linkpl.constant_part += 4;
+	cstate->off_linktype.constant_part += 4;
+
+	return b0;
+}
+
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+/* add v to variable part of off */
+static void
+gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off,
+    bpf_u_int32 v, struct slist *s)
+{
+	struct slist *s2;
+
+	if (!off->is_variable)
+		off->is_variable = 1;
+	if (off->reg == -1)
+		off->reg = alloc_reg(cstate);
+
+	s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
+	s2->s.k = off->reg;
+	sappend(s, s2);
+	s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+	s2->s.k = v;
+	sappend(s, s2);
+	s2 = new_stmt(cstate, BPF_ST);
+	s2->s.k = off->reg;
+	sappend(s, s2);
+}
+
+/*
+ * patch block b_tpid (VLAN TPID test) to update variable parts of link payload
+ * and link type offsets first
+ */
+static void
+gen_vlan_patch_tpid_test(compiler_state_t *cstate, struct block *b_tpid)
+{
+	struct slist s;
+
+	/* offset determined at run time, shift variable part */
+	s.next = NULL;
+	cstate->is_vlan_vloffset = 1;
+	gen_vlan_vloffset_add(cstate, &cstate->off_linkpl, 4, &s);
+	gen_vlan_vloffset_add(cstate, &cstate->off_linktype, 4, &s);
+
+	/* we get a pointer to a chain of or-ed blocks, patch first of them */
+	sappend(s.next, b_tpid->head->stmts);
+	b_tpid->head->stmts = s.next;
+}
+
+/*
+ * patch block b_vid (VLAN id test) to load VID value either from packet
+ * metadata (using BPF extensions) if SKF_AD_VLAN_TAG_PRESENT is true
+ */
+static void
+gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid)
+{
+	struct slist *s, *s2, *sjeq;
+	unsigned cnt;
+
+	s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+	s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+	/* true -> next instructions, false -> beginning of b_vid */
+	sjeq = new_stmt(cstate, JMP(BPF_JEQ));
+	sjeq->s.k = 1;
+	sjeq->s.jf = b_vid->stmts;
+	sappend(s, sjeq);
+
+	s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+	s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
+	sappend(s, s2);
+	sjeq->s.jt = s2;
+
+	/* Jump to the test in b_vid. We need to jump one instruction before
+	 * the end of the b_vid block so that we only skip loading the TCI
+	 * from packet data and not the 'and' instruction extractging VID.
+	 */
+	cnt = 0;
+	for (s2 = b_vid->stmts; s2; s2 = s2->next)
+		cnt++;
+	s2 = new_stmt(cstate, JMP(BPF_JA));
+	s2->s.k = cnt - 1;
+	sappend(s, s2);
+
+	/* insert our statements at the beginning of b_vid */
+	sappend(s, b_vid->stmts);
+	b_vid->stmts = s;
+}
+
+/*
+ * Generate check for "vlan" or "vlan <id>" on systems with support for BPF
+ * extensions.  Even if kernel supports VLAN BPF extensions, (outermost) VLAN
+ * tag can be either in metadata or in packet data; therefore if the
+ * SKF_AD_VLAN_TAG_PRESENT test is negative, we need to check link
+ * header for VLAN tag. As the decision is done at run time, we need
+ * update variable part of the offsets
+ */
+static struct block *
+gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
+    int has_vlan_tag)
+{
+        struct block *b0, *b_tpid, *b_vid = NULL;
+        struct slist *s;
+
+        /* generate new filter code based on extracting packet
+         * metadata */
+        s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+        s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+        b0 = new_block(cstate, JMP(BPF_JEQ));
+        b0->stmts = s;
+        b0->s.k = 1;
+
+	/*
+	 * This is tricky. We need to insert the statements updating variable
+	 * parts of offsets before the traditional TPID and VID tests so
+	 * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but
+	 * we do not want this update to affect those checks. That's why we
+	 * generate both test blocks first and insert the statements updating
+	 * variable parts of both offsets after that. This wouldn't work if
+	 * there already were variable length link header when entering this
+	 * function but gen_vlan_bpf_extensions() isn't called in that case.
+	 */
+	b_tpid = gen_vlan_tpid_test(cstate);
+	if (has_vlan_tag)
+		b_vid = gen_vlan_vid_test(cstate, vlan_num);
+
+	gen_vlan_patch_tpid_test(cstate, b_tpid);
+	gen_or(b0, b_tpid);
+	b0 = b_tpid;
+
+	if (has_vlan_tag) {
+		gen_vlan_patch_vid_test(cstate, b_vid);
+		gen_and(b0, b_vid);
+		b0 = b_vid;
+	}
+
+        return b0;
+}
+#endif
+
+/*
+ * support IEEE 802.1Q VLAN trunk over ethernet
+ */
+struct block *
+gen_vlan(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag)
+{
+	struct	block	*b0;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/* can't check for VLAN-encapsulated packets inside MPLS */
+	if (cstate->label_stack_depth > 0)
+		bpf_error(cstate, "no VLAN match after MPLS");
+
+	/*
+	 * 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
+	 * generates an expression tree, and a code generator that
+	 * takes an expression tree (which could come from our
+	 * parser or from some other parser) and generates BPF code,
+	 * we could perhaps make the offsets parameters of routines
+	 * and, in the handler for an "AND" node, pass to subnodes
+	 * other than the VLAN node the adjusted offsets.
+	 *
+	 * This would mean that "vlan" would, instead of changing the
+	 * behavior of *all* tests after it, change only the behavior
+	 * of tests ANDed with it.  That would change the documented
+	 * semantics of "vlan", which might break some expressions.
+	 * However, it would mean that "(vlan and ip) or ip" would check
+	 * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than
+	 * checking only for VLAN-encapsulated IP, so that could still
+	 * be considered worth doing; it wouldn't break expressions
+	 * that are of the form "vlan and ..." or "vlan N and ...",
+	 * which I suspect are the most common expressions involving
+	 * "vlan".  "vlan or ..." doesn't necessarily do what the user
+	 * would really want, now, as all the "or ..." tests would
+	 * be done assuming a VLAN, even though the "or" could be viewed
+	 * as meaning "or, if this isn't a VLAN packet...".
+	 */
+	switch (cstate->linktype) {
+
+	case DLT_EN10MB:
+	case DLT_NETANALYZER:
+	case DLT_NETANALYZER_TRANSPARENT:
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+		/* Verify that this is the outer part of the packet and
+		 * not encapsulated somehow. */
+		if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable &&
+		    cstate->off_linkhdr.constant_part ==
+		    cstate->off_outermostlinkhdr.constant_part) {
+			/*
+			 * Do we need special VLAN handling?
+			 */
+			if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING)
+				b0 = gen_vlan_bpf_extensions(cstate, vlan_num,
+				    has_vlan_tag);
+			else
+				b0 = gen_vlan_no_bpf_extensions(cstate,
+				    vlan_num, has_vlan_tag);
+		} else
+#endif
+			b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num,
+			    has_vlan_tag);
+                break;
+
+	case DLT_IEEE802_11:
+	case DLT_PRISM_HEADER:
+	case DLT_IEEE802_11_RADIO_AVS:
+	case DLT_IEEE802_11_RADIO:
+		b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag);
+		break;
+
+	default:
+		bpf_error(cstate, "no VLAN support for %s",
+		      pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+		/*NOTREACHED*/
+	}
+
+        cstate->vlan_stack_depth++;
+
+	return (b0);
+}
+
+/*
+ * support for MPLS
+ *
+ * The label_num_arg dance is to avoid annoying whining by compilers that
+ * label_num might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct block *
+gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num_arg,
+    int has_label_num)
+{
+	volatile bpf_u_int32 label_num = label_num_arg;
+	struct	block	*b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+        if (cstate->label_stack_depth > 0) {
+            /* just match the bottom-of-stack bit clear */
+            b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01);
+        } else {
+            /*
+             * We're not in an MPLS stack yet, so check the link-layer
+             * type against MPLS.
+             */
+            switch (cstate->linktype) {
+
+            case DLT_C_HDLC: /* fall through */
+            case DLT_EN10MB:
+            case DLT_NETANALYZER:
+            case DLT_NETANALYZER_TRANSPARENT:
+                    b0 = gen_linktype(cstate, ETHERTYPE_MPLS);
+                    break;
+
+            case DLT_PPP:
+                    b0 = gen_linktype(cstate, PPP_MPLS_UCAST);
+                    break;
+
+                    /* FIXME add other DLT_s ...
+                     * for Frame-Relay/and ATM this may get messy due to SNAP headers
+                     * leave it for now */
+
+            default:
+                    bpf_error(cstate, "no MPLS support for %s",
+                          pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+                    /*NOTREACHED*/
+            }
+        }
+
+	/* If a specific MPLS label is requested, check it */
+	if (has_label_num) {
+		if (label_num > 0xFFFFF) {
+			bpf_error(cstate, "MPLS label %u greater than maximum %u",
+			    label_num, 0xFFFFF);
+		}
+		label_num = label_num << 12; /* label is shifted 12 bits on the wire */
+		b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num,
+		    0xfffff000); /* only compare the first 20 bits */
+		gen_and(b0, b1);
+		b0 = b1;
+	}
+
+        /*
+         * Change the offsets to point to the type and data fields within
+         * the MPLS packet.  Just increment the offsets, so that we
+         * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to
+         * capture packets with an outer label of 100000 and an inner
+         * label of 1024.
+         *
+         * Increment the MPLS stack depth as well; this indicates that
+         * we're checking MPLS-encapsulated headers, to make sure higher
+         * level code generators don't try to match against IP-related
+         * protocols such as Q_ARP, Q_RARP etc.
+         *
+         * XXX - this is a bit of a kludge.  See comments in gen_vlan().
+         */
+        cstate->off_nl_nosnap += 4;
+        cstate->off_nl += 4;
+        cstate->label_stack_depth++;
+	return (b0);
+}
+
+/*
+ * Support PPPOE discovery and session.
+ */
+struct block *
+gen_pppoed(compiler_state_t *cstate)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/* check for PPPoE discovery */
+	return gen_linktype(cstate, ETHERTYPE_PPPOED);
+}
+
+struct block *
+gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	/*
+	 * Test against the PPPoE session link-layer type.
+	 */
+	b0 = gen_linktype(cstate, ETHERTYPE_PPPOES);
+
+	/* If a specific session is requested, check PPPoE session id */
+	if (has_sess_num) {
+		if (sess_num > 0x0000ffff) {
+			bpf_error(cstate, "PPPoE session number %u greater than maximum %u",
+			    sess_num, 0x0000ffff);
+		}
+		b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, sess_num, 0x0000ffff);
+		gen_and(b0, b1);
+		b0 = b1;
+	}
+
+	/*
+	 * Change the offsets to point to the type and data fields within
+	 * the PPP packet, and note that this is PPPoE rather than
+	 * raw PPP.
+	 *
+	 * XXX - this is a bit of a kludge.  See the comments in
+	 * gen_vlan().
+	 *
+	 * The "network-layer" protocol is PPPoE, which has a 6-byte
+	 * PPPoE header, followed by a PPP packet.
+	 *
+	 * 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 cstate->off_nl.
+	 */
+	PUSH_LINKHDR(cstate, DLT_PPP, cstate->off_linkpl.is_variable,
+	    cstate->off_linkpl.constant_part + cstate->off_nl + 6, /* 6 bytes past the PPPoE header */
+	    cstate->off_linkpl.reg);
+
+	cstate->off_linktype = cstate->off_linkhdr;
+	cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 2;
+
+	cstate->off_nl = 0;
+	cstate->off_nl_nosnap = 0;	/* no 802.2 LLC */
+
+	return b0;
+}
+
+/* Check that this is Geneve and the VNI is correct if
+ * specified. Parameterized to handle both IPv4 and IPv6. */
+static struct block *
+gen_geneve_check(compiler_state_t *cstate,
+    struct block *(*gen_portfn)(compiler_state_t *, u_int, int, int),
+    enum e_offrel offrel, bpf_u_int32 vni, int has_vni)
+{
+	struct block *b0, *b1;
+
+	b0 = gen_portfn(cstate, GENEVE_PORT, IPPROTO_UDP, Q_DST);
+
+	/* Check that we are operating on version 0. Otherwise, we
+	 * can't decode the rest of the fields. The version is 2 bits
+	 * in the first byte of the Geneve header. */
+	b1 = gen_mcmp(cstate, offrel, 8, BPF_B, 0, 0xc0);
+	gen_and(b0, b1);
+	b0 = b1;
+
+	if (has_vni) {
+		if (vni > 0xffffff) {
+			bpf_error(cstate, "Geneve VNI %u greater than maximum %u",
+			    vni, 0xffffff);
+		}
+		vni <<= 8; /* VNI is in the upper 3 bytes */
+		b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00);
+		gen_and(b0, b1);
+		b0 = b1;
+	}
+
+	return b0;
+}
+
+/* The IPv4 and IPv6 Geneve checks need to do two things:
+ * - Verify that this actually is Geneve with the right VNI.
+ * - Place the IP header length (plus variable link prefix if
+ *   needed) into register A to be used later to compute
+ *   the inner packet offsets. */
+static struct block *
+gen_geneve4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+	struct block *b0, *b1;
+	struct slist *s, *s1;
+
+	b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni, has_vni);
+
+	/* Load the IP header length into A. */
+	s = gen_loadx_iphdrlen(cstate);
+
+	s1 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+	sappend(s, s1);
+
+	/* Forcibly append these statements to the true condition
+	 * of the protocol check by creating a new block that is
+	 * always true and ANDing them. */
+	b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
+	b1->stmts = s;
+	b1->s.k = 0;
+
+	gen_and(b0, b1);
+
+	return b1;
+}
+
+static struct block *
+gen_geneve6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+	struct block *b0, *b1;
+	struct slist *s, *s1;
+
+	b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni, has_vni);
+
+	/* Load the IP header length. We need to account for a
+	 * variable length link prefix if there is one. */
+	s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+	if (s) {
+		s1 = new_stmt(cstate, BPF_LD|BPF_IMM);
+		s1->s.k = 40;
+		sappend(s, s1);
+
+		s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+		s1->s.k = 0;
+		sappend(s, s1);
+	} else {
+		s = new_stmt(cstate, BPF_LD|BPF_IMM);
+		s->s.k = 40;
+	}
+
+	/* Forcibly append these statements to the true condition
+	 * of the protocol check by creating a new block that is
+	 * always true and ANDing them. */
+	s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+	sappend(s, s1);
+
+	b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
+	b1->stmts = s;
+	b1->s.k = 0;
+
+	gen_and(b0, b1);
+
+	return b1;
+}
+
+/* We need to store three values based on the Geneve header::
+ * - The offset of the linktype.
+ * - The offset of the end of the Geneve header.
+ * - The offset of the end of the encapsulated MAC header. */
+static struct slist *
+gen_geneve_offsets(compiler_state_t *cstate)
+{
+	struct slist *s, *s1, *s_proto;
+
+	/* First we need to calculate the offset of the Geneve header
+	 * itself. This is composed of the IP header previously calculated
+	 * (include any variable link prefix) and stored in A plus the
+	 * fixed sized headers (fixed link prefix, MAC length, and UDP
+	 * header). */
+	s = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 8;
+
+	/* Stash this in X since we'll need it later. */
+	s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+	sappend(s, s1);
+
+	/* The EtherType in Geneve is 2 bytes in. Calculate this and
+	 * store it. */
+	s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s1->s.k = 2;
+	sappend(s, s1);
+
+	cstate->off_linktype.reg = alloc_reg(cstate);
+	cstate->off_linktype.is_variable = 1;
+	cstate->off_linktype.constant_part = 0;
+
+	s1 = new_stmt(cstate, BPF_ST);
+	s1->s.k = cstate->off_linktype.reg;
+	sappend(s, s1);
+
+	/* Load the Geneve option length and mask and shift to get the
+	 * number of bytes. It is stored in the first byte of the Geneve
+	 * header. */
+	s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+	s1->s.k = 0;
+	sappend(s, s1);
+
+	s1 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+	s1->s.k = 0x3f;
+	sappend(s, s1);
+
+	s1 = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
+	s1->s.k = 4;
+	sappend(s, s1);
+
+	/* Add in the rest of the Geneve base header. */
+	s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s1->s.k = 8;
+	sappend(s, s1);
+
+	/* Add the Geneve header length to its offset and store. */
+	s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+	s1->s.k = 0;
+	sappend(s, s1);
+
+	/* Set the encapsulated type as Ethernet. Even though we may
+	 * not actually have Ethernet inside there are two reasons this
+	 * is useful:
+	 * - The linktype field is always in EtherType format regardless
+	 *   of whether it is in Geneve or an inner Ethernet frame.
+	 * - The only link layer that we have specific support for is
+	 *   Ethernet. We will confirm that the packet actually is
+	 *   Ethernet at runtime before executing these checks. */
+	PUSH_LINKHDR(cstate, DLT_EN10MB, 1, 0, alloc_reg(cstate));
+
+	s1 = new_stmt(cstate, BPF_ST);
+	s1->s.k = cstate->off_linkhdr.reg;
+	sappend(s, s1);
+
+	/* Calculate whether we have an Ethernet header or just raw IP/
+	 * MPLS/etc. If we have Ethernet, advance the end of the MAC offset
+	 * and linktype by 14 bytes so that the network header can be found
+	 * seamlessly. Otherwise, keep what we've calculated already. */
+
+	/* We have a bare jmp so we can't use the optimizer. */
+	cstate->no_optimize = 1;
+
+	/* Load the EtherType in the Geneve header, 2 bytes in. */
+	s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_H);
+	s1->s.k = 2;
+	sappend(s, s1);
+
+	/* Load X with the end of the Geneve header. */
+	s1 = new_stmt(cstate, BPF_LDX|BPF_MEM);
+	s1->s.k = cstate->off_linkhdr.reg;
+	sappend(s, s1);
+
+	/* Check if the EtherType is Transparent Ethernet Bridging. At the
+	 * end of this check, we should have the total length in X. In
+	 * the non-Ethernet case, it's already there. */
+	s_proto = new_stmt(cstate, JMP(BPF_JEQ));
+	s_proto->s.k = ETHERTYPE_TEB;
+	sappend(s, s_proto);
+
+	s1 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+	sappend(s, s1);
+	s_proto->s.jt = s1;
+
+	/* Since this is Ethernet, use the EtherType of the payload
+	 * directly as the linktype. Overwrite what we already have. */
+	s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s1->s.k = 12;
+	sappend(s, s1);
+
+	s1 = new_stmt(cstate, BPF_ST);
+	s1->s.k = cstate->off_linktype.reg;
+	sappend(s, s1);
+
+	/* Advance two bytes further to get the end of the Ethernet
+	 * header. */
+	s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+	s1->s.k = 2;
+	sappend(s, s1);
+
+	/* Move the result to X. */
+	s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+	sappend(s, s1);
+
+	/* Store the final result of our linkpl calculation. */
+	cstate->off_linkpl.reg = alloc_reg(cstate);
+	cstate->off_linkpl.is_variable = 1;
+	cstate->off_linkpl.constant_part = 0;
+
+	s1 = new_stmt(cstate, BPF_STX);
+	s1->s.k = cstate->off_linkpl.reg;
+	sappend(s, s1);
+	s_proto->s.jf = s1;
+
+	cstate->off_nl = 0;
+
+	return s;
+}
+
+/* Check to see if this is a Geneve packet. */
+struct block *
+gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+	struct block *b0, *b1;
+	struct slist *s;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	b0 = gen_geneve4(cstate, vni, has_vni);
+	b1 = gen_geneve6(cstate, vni, has_vni);
+
+	gen_or(b0, b1);
+	b0 = b1;
+
+	/* Later filters should act on the payload of the Geneve frame,
+	 * update all of the header pointers. Attach this code so that
+	 * it gets executed in the event that the Geneve filter matches. */
+	s = gen_geneve_offsets(cstate);
+
+	b1 = gen_true(cstate);
+	sappend(s, b1->stmts);
+	b1->stmts = s;
+
+	gen_and(b0, b1);
+
+	cstate->is_geneve = 1;
+
+	return b1;
+}
+
+/* Check that the encapsulated frame has a link layer header
+ * for Ethernet filters. */
+static struct block *
+gen_geneve_ll_check(compiler_state_t *cstate)
+{
+	struct block *b0;
+	struct slist *s, *s1;
+
+	/* The easiest way to see if there is a link layer present
+	 * is to check if the link layer header and payload are not
+	 * the same. */
+
+	/* Geneve always generates pure variable offsets so we can
+	 * compare only the registers. */
+	s = new_stmt(cstate, BPF_LD|BPF_MEM);
+	s->s.k = cstate->off_linkhdr.reg;
+
+	s1 = new_stmt(cstate, BPF_LDX|BPF_MEM);
+	s1->s.k = cstate->off_linkpl.reg;
+	sappend(s, s1);
+
+	b0 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
+	b0->stmts = s;
+	b0->s.k = 0;
+	gen_not(b0);
+
+	return b0;
+}
+
+static struct block *
+gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
+    bpf_u_int32 jvalue, int jtype, int reverse)
+{
+	struct block *b0;
+
+	switch (atmfield) {
+
+	case A_VPI:
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'vpi' supported only on raw ATM");
+		if (cstate->off_vpi == OFFSET_NOT_SET)
+			abort();
+		b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B,
+		    0xffffffffU, jtype, reverse, jvalue);
+		break;
+
+	case A_VCI:
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'vci' supported only on raw ATM");
+		if (cstate->off_vci == OFFSET_NOT_SET)
+			abort();
+		b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H,
+		    0xffffffffU, jtype, reverse, jvalue);
+		break;
+
+	case A_PROTOTYPE:
+		if (cstate->off_proto == OFFSET_NOT_SET)
+			abort();	/* XXX - this isn't on FreeBSD */
+		b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+		    0x0fU, jtype, reverse, jvalue);
+		break;
+
+	case A_MSGTYPE:
+		if (cstate->off_payload == OFFSET_NOT_SET)
+			abort();
+		b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B,
+		    0xffffffffU, jtype, reverse, jvalue);
+		break;
+
+	case A_CALLREFTYPE:
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'callref' supported only on raw ATM");
+		if (cstate->off_proto == OFFSET_NOT_SET)
+			abort();
+		b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+		    0xffffffffU, jtype, reverse, jvalue);
+		break;
+
+	default:
+		abort();
+	}
+	return b0;
+}
+
+static struct block *
+gen_atmtype_metac(compiler_state_t *cstate)
+{
+	struct block *b0, *b1;
+
+	b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+	b1 = gen_atmfield_code_internal(cstate, A_VCI, 1, BPF_JEQ, 0);
+	gen_and(b0, b1);
+	return b1;
+}
+
+static struct block *
+gen_atmtype_sc(compiler_state_t *cstate)
+{
+	struct block *b0, *b1;
+
+	b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+	b1 = gen_atmfield_code_internal(cstate, A_VCI, 5, BPF_JEQ, 0);
+	gen_and(b0, b1);
+	return b1;
+}
+
+static struct block *
+gen_atmtype_llc(compiler_state_t *cstate)
+{
+	struct block *b0;
+
+	b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+	cstate->linktype = cstate->prevlinktype;
+	return b0;
+}
+
+struct block *
+gen_atmfield_code(compiler_state_t *cstate, int atmfield,
+    bpf_u_int32 jvalue, int jtype, int reverse)
+{
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	return gen_atmfield_code_internal(cstate, atmfield, jvalue, jtype,
+	    reverse);
+}
+
+struct block *
+gen_atmtype_abbrev(compiler_state_t *cstate, int type)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (type) {
+
+	case A_METAC:
+		/* Get all packets in Meta signalling Circuit */
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'metac' supported only on raw ATM");
+		b1 = gen_atmtype_metac(cstate);
+		break;
+
+	case A_BCC:
+		/* Get all packets in Broadcast Circuit*/
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'bcc' supported only on raw ATM");
+		b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+		b1 = gen_atmfield_code_internal(cstate, A_VCI, 2, BPF_JEQ, 0);
+		gen_and(b0, b1);
+		break;
+
+	case A_OAMF4SC:
+		/* Get all cells in Segment OAM F4 circuit*/
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'oam4sc' supported only on raw ATM");
+		b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+		b1 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
+		gen_and(b0, b1);
+		break;
+
+	case A_OAMF4EC:
+		/* Get all cells in End-to-End OAM F4 Circuit*/
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'oam4ec' supported only on raw ATM");
+		b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+		b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+		gen_and(b0, b1);
+		break;
+
+	case A_SC:
+		/*  Get all packets in connection Signalling Circuit */
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'sc' supported only on raw ATM");
+		b1 = gen_atmtype_sc(cstate);
+		break;
+
+	case A_ILMIC:
+		/* Get all packets in ILMI Circuit */
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'ilmic' supported only on raw ATM");
+		b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+		b1 = gen_atmfield_code_internal(cstate, A_VCI, 16, BPF_JEQ, 0);
+		gen_and(b0, b1);
+		break;
+
+	case A_LANE:
+		/* Get all LANE packets */
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'lane' supported only on raw ATM");
+		b1 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0);
+
+		/*
+		 * Arrange that all subsequent tests assume LANE
+		 * rather than LLC-encapsulated packets, and set
+		 * the offsets appropriately for LANE-encapsulated
+		 * Ethernet.
+		 *
+		 * We assume LANE means Ethernet, not Token Ring.
+		 */
+		PUSH_LINKHDR(cstate, DLT_EN10MB, 0,
+		    cstate->off_payload + 2,	/* Ethernet header */
+		    -1);
+		cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
+		cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14;	/* Ethernet */
+		cstate->off_nl = 0;			/* Ethernet II */
+		cstate->off_nl_nosnap = 3;		/* 802.3+802.2 */
+		break;
+
+	case A_LLC:
+		/* Get all LLC-encapsulated packets */
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'llc' supported only on raw ATM");
+		b1 = gen_atmtype_llc(cstate);
+		break;
+
+	default:
+		abort();
+	}
+	return b1;
+}
+
+/*
+ * Filtering for MTP2 messages based on li value
+ * FISU, length is null
+ * LSSU, length is 1 or 2
+ * MSU, length is 3 or more
+ * For MTP2_HSL, sequences are on 2 bytes, and length on 9 bits
+ */
+struct block *
+gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (type) {
+
+	case M_FISU:
+		if ( (cstate->linktype != DLT_MTP2) &&
+		     (cstate->linktype != DLT_ERF) &&
+		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+			bpf_error(cstate, "'fisu' supported only on MTP2");
+		/* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JEQ, 0, 0U);
+		break;
+
+	case M_LSSU:
+		if ( (cstate->linktype != DLT_MTP2) &&
+		     (cstate->linktype != DLT_ERF) &&
+		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+			bpf_error(cstate, "'lssu' supported only on MTP2");
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JGT, 1, 2U);
+		b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JGT, 0, 0U);
+		gen_and(b1, b0);
+		break;
+
+	case M_MSU:
+		if ( (cstate->linktype != DLT_MTP2) &&
+		     (cstate->linktype != DLT_ERF) &&
+		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+			bpf_error(cstate, "'msu' supported only on MTP2");
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JGT, 0, 2U);
+		break;
+
+	case MH_FISU:
+		if ( (cstate->linktype != DLT_MTP2) &&
+		     (cstate->linktype != DLT_ERF) &&
+		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+			bpf_error(cstate, "'hfisu' supported only on MTP2_HSL");
+		/* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JEQ, 0, 0U);
+		break;
+
+	case MH_LSSU:
+		if ( (cstate->linktype != DLT_MTP2) &&
+		     (cstate->linktype != DLT_ERF) &&
+		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+			bpf_error(cstate, "'hlssu' supported only on MTP2_HSL");
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JGT, 1, 0x0100U);
+		b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JGT, 0, 0U);
+		gen_and(b1, b0);
+		break;
+
+	case MH_MSU:
+		if ( (cstate->linktype != DLT_MTP2) &&
+		     (cstate->linktype != DLT_ERF) &&
+		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+			bpf_error(cstate, "'hmsu' supported only on MTP2_HSL");
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JGT, 0, 0x0100U);
+		break;
+
+	default:
+		abort();
+	}
+	return b0;
+}
+
+/*
+ * The jvalue_arg dance is to avoid annoying whining by compilers that
+ * jvalue might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct block *
+gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
+    bpf_u_int32 jvalue_arg, int jtype, int reverse)
+{
+	volatile bpf_u_int32 jvalue = jvalue_arg;
+	struct block *b0;
+	bpf_u_int32 val1 , val2 , val3;
+	u_int newoff_sio;
+	u_int newoff_opc;
+	u_int newoff_dpc;
+	u_int newoff_sls;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	newoff_sio = cstate->off_sio;
+	newoff_opc = cstate->off_opc;
+	newoff_dpc = cstate->off_dpc;
+	newoff_sls = cstate->off_sls;
+	switch (mtp3field) {
+
+	case MH_SIO:
+		newoff_sio += 3; /* offset for MTP2_HSL */
+		/* FALLTHROUGH */
+
+	case M_SIO:
+		if (cstate->off_sio == OFFSET_NOT_SET)
+			bpf_error(cstate, "'sio' supported only on SS7");
+		/* sio coded on 1 byte so max value 255 */
+		if(jvalue > 255)
+		        bpf_error(cstate, "sio value %u too big; max value = 255",
+		            jvalue);
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffffU,
+		    jtype, reverse, jvalue);
+		break;
+
+	case MH_OPC:
+		newoff_opc += 3;
+
+		/* FALLTHROUGH */
+        case M_OPC:
+	        if (cstate->off_opc == OFFSET_NOT_SET)
+			bpf_error(cstate, "'opc' supported only on SS7");
+		/* opc coded on 14 bits so max value 16383 */
+		if (jvalue > 16383)
+		        bpf_error(cstate, "opc value %u too big; max value = 16383",
+		            jvalue);
+		/* the following instructions are made to convert jvalue
+		 * to the form used to write opc in an ss7 message*/
+		val1 = jvalue & 0x00003c00;
+		val1 = val1 >>10;
+		val2 = jvalue & 0x000003fc;
+		val2 = val2 <<6;
+		val3 = jvalue & 0x00000003;
+		val3 = val3 <<22;
+		jvalue = val1 + val2 + val3;
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0fU,
+		    jtype, reverse, jvalue);
+		break;
+
+	case MH_DPC:
+		newoff_dpc += 3;
+		/* FALLTHROUGH */
+
+	case M_DPC:
+	        if (cstate->off_dpc == OFFSET_NOT_SET)
+			bpf_error(cstate, "'dpc' supported only on SS7");
+		/* dpc coded on 14 bits so max value 16383 */
+		if (jvalue > 16383)
+		        bpf_error(cstate, "dpc value %u too big; max value = 16383",
+		            jvalue);
+		/* the following instructions are made to convert jvalue
+		 * to the forme used to write dpc in an ss7 message*/
+		val1 = jvalue & 0x000000ff;
+		val1 = val1 << 24;
+		val2 = jvalue & 0x00003f00;
+		val2 = val2 << 8;
+		jvalue = val1 + val2;
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000U,
+		    jtype, reverse, jvalue);
+		break;
+
+	case MH_SLS:
+		newoff_sls += 3;
+		/* FALLTHROUGH */
+
+	case M_SLS:
+	        if (cstate->off_sls == OFFSET_NOT_SET)
+			bpf_error(cstate, "'sls' supported only on SS7");
+		/* sls coded on 4 bits so max value 15 */
+		if (jvalue > 15)
+		         bpf_error(cstate, "sls value %u too big; max value = 15",
+		             jvalue);
+		/* the following instruction is made to convert jvalue
+		 * to the forme used to write sls in an ss7 message*/
+		jvalue = jvalue << 4;
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0U,
+		    jtype, reverse, jvalue);
+		break;
+
+	default:
+		abort();
+	}
+	return b0;
+}
+
+static struct block *
+gen_msg_abbrev(compiler_state_t *cstate, int type)
+{
+	struct block *b1;
+
+	/*
+	 * Q.2931 signalling protocol messages for handling virtual circuits
+	 * establishment and teardown
+	 */
+	switch (type) {
+
+	case A_SETUP:
+		b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0);
+		break;
+
+	case A_CALLPROCEED:
+		b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0);
+		break;
+
+	case A_CONNECT:
+		b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0);
+		break;
+
+	case A_CONNECTACK:
+		b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0);
+		break;
+
+	case A_RELEASE:
+		b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0);
+		break;
+
+	case A_RELEASE_DONE:
+		b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0);
+		break;
+
+	default:
+		abort();
+	}
+	return b1;
+}
+
+struct block *
+gen_atmmulti_abbrev(compiler_state_t *cstate, int type)
+{
+	struct block *b0, *b1;
+
+	/*
+	 * Catch errors reported by us and routines below us, and return NULL
+	 * on an error.
+	 */
+	if (setjmp(cstate->top_ctx))
+		return (NULL);
+
+	switch (type) {
+
+	case A_OAM:
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'oam' supported only on raw ATM");
+		/* OAM F4 type */
+		b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
+		b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+		gen_or(b0, b1);
+		b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+		gen_and(b0, b1);
+		break;
+
+	case A_OAMF4:
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'oamf4' supported only on raw ATM");
+		/* OAM F4 type */
+		b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
+		b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+		gen_or(b0, b1);
+		b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+		gen_and(b0, b1);
+		break;
+
+	case A_CONNECTMSG:
+		/*
+		 * Get Q.2931 signalling messages for switched
+		 * virtual connection
+		 */
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'connectmsg' supported only on raw ATM");
+		b0 = gen_msg_abbrev(cstate, A_SETUP);
+		b1 = gen_msg_abbrev(cstate, A_CALLPROCEED);
+		gen_or(b0, b1);
+		b0 = gen_msg_abbrev(cstate, A_CONNECT);
+		gen_or(b0, b1);
+		b0 = gen_msg_abbrev(cstate, A_CONNECTACK);
+		gen_or(b0, b1);
+		b0 = gen_msg_abbrev(cstate, A_RELEASE);
+		gen_or(b0, b1);
+		b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE);
+		gen_or(b0, b1);
+		b0 = gen_atmtype_sc(cstate);
+		gen_and(b0, b1);
+		break;
+
+	case A_METACONNECT:
+		if (!cstate->is_atm)
+			bpf_error(cstate, "'metaconnect' supported only on raw ATM");
+		b0 = gen_msg_abbrev(cstate, A_SETUP);
+		b1 = gen_msg_abbrev(cstate, A_CALLPROCEED);
+		gen_or(b0, b1);
+		b0 = gen_msg_abbrev(cstate, A_CONNECT);
+		gen_or(b0, b1);
+		b0 = gen_msg_abbrev(cstate, A_RELEASE);
+		gen_or(b0, b1);
+		b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE);
+		gen_or(b0, b1);
+		b0 = gen_atmtype_metac(cstate);
+		gen_and(b0, b1);
+		break;
+
+	default:
+		abort();
+	}
+	return b1;
+}
diff --git a/gencode.h b/gencode.h
new file mode 100644
index 0000000..053e85f
--- /dev/null
+++ b/gencode.h
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "pcap/funcattrs.h"
+
+/*
+ * ATM support:
+ *
+ * Copyright (c) 1997 Yen Yen Lim and North Dakota State University
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Yen Yen Lim and
+ *      North Dakota State University
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Address qualifiers. */
+
+#define Q_HOST		1
+#define Q_NET		2
+#define Q_PORT		3
+#define Q_GATEWAY	4
+#define Q_PROTO		5
+#define Q_PROTOCHAIN	6
+#define Q_PORTRANGE	7
+
+/* Protocol qualifiers. */
+
+#define Q_LINK		1
+#define Q_IP		2
+#define Q_ARP		3
+#define Q_RARP		4
+#define Q_SCTP		5
+#define Q_TCP		6
+#define Q_UDP		7
+#define Q_ICMP		8
+#define Q_IGMP		9
+#define Q_IGRP		10
+
+
+#define	Q_ATALK		11
+#define	Q_DECNET	12
+#define	Q_LAT		13
+#define Q_SCA		14
+#define	Q_MOPRC		15
+#define	Q_MOPDL		16
+
+
+#define Q_IPV6		17
+#define Q_ICMPV6	18
+#define Q_AH		19
+#define Q_ESP		20
+
+#define Q_PIM		21
+#define Q_VRRP		22
+
+#define Q_AARP		23
+
+#define Q_ISO		24
+#define Q_ESIS		25
+#define Q_ISIS		26
+#define Q_CLNP		27
+
+#define Q_STP		28
+
+#define Q_IPX		29
+
+#define Q_NETBEUI	30
+
+/* IS-IS Levels */
+#define Q_ISIS_L1       31
+#define Q_ISIS_L2       32
+/* PDU types */
+#define Q_ISIS_IIH      33
+#define Q_ISIS_SNP      34
+#define Q_ISIS_CSNP     35
+#define Q_ISIS_PSNP     36
+#define Q_ISIS_LSP      37
+
+#define Q_RADIO		38
+
+#define Q_CARP		39
+
+/* Directional qualifiers. */
+
+#define Q_SRC		1
+#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_RA		9
+#define Q_TA		10
+
+#define Q_DEFAULT	0
+#define Q_UNDEF		255
+
+/* ATM types */
+#define A_METAC		22	/* Meta signalling Circuit */
+#define A_BCC		23	/* Broadcast Circuit */
+#define A_OAMF4SC	24	/* Segment OAM F4 Circuit */
+#define A_OAMF4EC	25	/* End-to-End OAM F4 Circuit */
+#define A_SC		26	/* Signalling Circuit*/
+#define A_ILMIC		27	/* ILMI Circuit */
+#define A_OAM		28	/* OAM cells : F4 only */
+#define A_OAMF4		29	/* OAM F4 cells: Segment + End-to-end */
+#define A_LANE		30	/* LANE traffic */
+#define A_LLC		31	/* LLC-encapsulated traffic */
+
+/* Based on Q.2931 signalling protocol */
+#define A_SETUP		41	/* Setup message */
+#define A_CALLPROCEED	42	/* Call proceeding message */
+#define A_CONNECT	43	/* Connect message */
+#define A_CONNECTACK	44	/* Connect Ack message */
+#define A_RELEASE	45	/* Release message */
+#define A_RELEASE_DONE	46	/* Release message */
+
+/* ATM field types */
+#define A_VPI		51
+#define A_VCI		52
+#define A_PROTOTYPE	53
+#define A_MSGTYPE	54
+#define A_CALLREFTYPE	55
+
+#define A_CONNECTMSG	70	/* returns Q.2931 signalling messages for
+				   establishing and destroying switched
+				   virtual connection */
+#define A_METACONNECT	71	/* returns Q.2931 signalling messages for
+				   establishing and destroying predefined
+				   virtual circuits, such as broadcast
+				   circuit, oamf4 segment circuit, oamf4
+				   end-to-end circuits, ILMI circuits or
+				   connection signalling circuit. */
+
+/* MTP2 types */
+#define M_FISU		22	/* FISU */
+#define M_LSSU		23	/* LSSU */
+#define M_MSU		24	/* MSU */
+
+/* MTP2 HSL types */
+#define MH_FISU		25	/* FISU for HSL */
+#define MH_LSSU		26	/* LSSU */
+#define MH_MSU		27	/* MSU */
+
+/* MTP3 field types */
+#define M_SIO		1
+#define M_OPC		2
+#define M_DPC		3
+#define M_SLS		4
+
+/* MTP3 field types in case of MTP2 HSL */
+#define MH_SIO		5
+#define MH_OPC		6
+#define MH_DPC		7
+#define MH_SLS		8
+
+
+struct slist;
+
+/*
+ * A single statement, corresponding to an instruction in a block.
+ */
+struct stmt {
+	int code;		/* opcode */
+	struct slist *jt;	/* only for relative jump in block */
+	struct slist *jf;	/* only for relative jump in block */
+	bpf_u_int32 k;		/* k field */
+};
+
+struct slist {
+	struct stmt s;
+	struct slist *next;
+};
+
+/*
+ * A bit vector to represent definition sets.  We assume TOT_REGISTERS
+ * is smaller than 8*sizeof(atomset).
+ */
+typedef bpf_u_int32 atomset;
+#define ATOMMASK(n) (1 << (n))
+#define ATOMELEM(d, n) (d & ATOMMASK(n))
+
+/*
+ * An unbounded set.
+ */
+typedef bpf_u_int32 *uset;
+
+/*
+ * Total number of atomic entities, including accumulator (A) and index (X).
+ * We treat all these guys similarly during flow analysis.
+ */
+#define N_ATOMS (BPF_MEMWORDS+2)
+
+/*
+ * Control flow graph of a program.
+ * This corresponds to an edge in the CFG.
+ * It's a directed graph, so an edge has a predecessor and a successor.
+ */
+struct edge {
+	u_int id;
+	int code;		/* opcode for branch corresponding to this edge */
+	uset edom;
+	struct block *succ;	/* successor vertex */
+	struct block *pred;	/* predecessor vertex */
+	struct edge *next;	/* link list of incoming edges for a node */
+};
+
+/*
+ * A block is a vertex in the CFG.
+ * It has a list of statements, with the final statement being a
+ * branch to successor blocks.
+ */
+struct block {
+	u_int id;
+	struct slist *stmts;	/* side effect stmts */
+	struct stmt s;		/* branch stmt */
+	int mark;
+	u_int longjt;		/* jt branch requires long jump */
+	u_int longjf;		/* jf branch requires long jump */
+	int level;
+	int offset;
+	int sense;
+	struct edge et;		/* edge corresponding to the jt branch */
+	struct edge ef;		/* edge corresponding to the jf branch */
+	struct block *head;
+	struct block *link;	/* link field used by optimizer */
+	uset dom;
+	uset closure;
+	struct edge *in_edges;	/* first edge in the set (linked list) of edges with this as a successor */
+	atomset def, kill;
+	atomset in_use;
+	atomset out_use;
+	int oval;		/* value ID for value tested in branch stmt */
+	bpf_u_int32 val[N_ATOMS];
+};
+
+/*
+ * A value of 0 for val[i] means the value is unknown.
+ */
+#define VAL_UNKNOWN	0
+
+struct arth {
+	struct block *b;	/* protocol checks */
+	struct slist *s;	/* stmt list */
+	int regno;		/* virtual register number of result */
+};
+
+struct qual {
+	unsigned char addr;
+	unsigned char proto;
+	unsigned char dir;
+	unsigned char pad;
+};
+
+struct _compiler_state;
+
+typedef struct _compiler_state compiler_state_t;
+
+struct arth *gen_loadi(compiler_state_t *, bpf_u_int32);
+struct arth *gen_load(compiler_state_t *, int, struct arth *, bpf_u_int32);
+struct arth *gen_loadlen(compiler_state_t *);
+struct arth *gen_neg(compiler_state_t *, struct arth *);
+struct arth *gen_arth(compiler_state_t *, int, struct arth *, struct arth *);
+
+void gen_and(struct block *, struct block *);
+void gen_or(struct block *, struct block *);
+void gen_not(struct block *);
+
+struct block *gen_scode(compiler_state_t *, const char *, struct qual);
+struct block *gen_ecode(compiler_state_t *, const char *, struct qual);
+struct block *gen_acode(compiler_state_t *, const char *, struct qual);
+struct block *gen_mcode(compiler_state_t *, const char *, const char *,
+    bpf_u_int32, struct qual);
+#ifdef INET6
+struct block *gen_mcode6(compiler_state_t *, const char *, const char *,
+    bpf_u_int32, struct qual);
+#endif
+struct block *gen_ncode(compiler_state_t *, const char *, bpf_u_int32,
+    struct qual);
+struct block *gen_proto_abbrev(compiler_state_t *, int);
+struct block *gen_relation(compiler_state_t *, int, struct arth *,
+    struct arth *, int);
+struct block *gen_less(compiler_state_t *, int);
+struct block *gen_greater(compiler_state_t *, int);
+struct block *gen_byteop(compiler_state_t *, int, int, bpf_u_int32);
+struct block *gen_broadcast(compiler_state_t *, int);
+struct block *gen_multicast(compiler_state_t *, int);
+struct block *gen_ifindex(compiler_state_t *, int);
+struct block *gen_inbound(compiler_state_t *, int);
+
+struct block *gen_llc(compiler_state_t *);
+struct block *gen_llc_i(compiler_state_t *);
+struct block *gen_llc_s(compiler_state_t *);
+struct block *gen_llc_u(compiler_state_t *);
+struct block *gen_llc_s_subtype(compiler_state_t *, bpf_u_int32);
+struct block *gen_llc_u_subtype(compiler_state_t *, bpf_u_int32);
+
+struct block *gen_vlan(compiler_state_t *, bpf_u_int32, int);
+struct block *gen_mpls(compiler_state_t *, bpf_u_int32, int);
+
+struct block *gen_pppoed(compiler_state_t *);
+struct block *gen_pppoes(compiler_state_t *, bpf_u_int32, int);
+
+struct block *gen_geneve(compiler_state_t *, bpf_u_int32, int);
+
+struct block *gen_atmfield_code(compiler_state_t *, int, bpf_u_int32,
+    int, int);
+struct block *gen_atmtype_abbrev(compiler_state_t *, int);
+struct block *gen_atmmulti_abbrev(compiler_state_t *, int);
+
+struct block *gen_mtp2type_abbrev(compiler_state_t *, int);
+struct block *gen_mtp3field_code(compiler_state_t *, int, bpf_u_int32,
+    int, int);
+
+struct block *gen_pf_ifname(compiler_state_t *, const char *);
+struct block *gen_pf_rnr(compiler_state_t *, int);
+struct block *gen_pf_srnr(compiler_state_t *, int);
+struct block *gen_pf_ruleset(compiler_state_t *, char *);
+struct block *gen_pf_reason(compiler_state_t *, int);
+struct block *gen_pf_action(compiler_state_t *, int);
+
+struct block *gen_p80211_type(compiler_state_t *, bpf_u_int32, bpf_u_int32);
+struct block *gen_p80211_fcdir(compiler_state_t *, bpf_u_int32);
+
+/*
+ * Representation of a program as a tree of blocks, plus current mark.
+ * A block is marked if only if its mark equals the current mark.
+ * Rather than traverse the code array, marking each item, 'cur_mark'
+ * is incremented.  This automatically makes each element unmarked.
+ */
+#define isMarked(icp, p) ((p)->mark == (icp)->cur_mark)
+#define unMarkAll(icp) (icp)->cur_mark += 1
+#define Mark(icp, p) ((p)->mark = (icp)->cur_mark)
+
+struct icode {
+	struct block *root;
+	int cur_mark;
+};
+
+int bpf_optimize(struct icode *, char *);
+void bpf_set_error(compiler_state_t *, const char *, ...)
+    PCAP_PRINTFLIKE(2, 3);
+
+int finish_parse(compiler_state_t *, struct block *);
+char *sdup(compiler_state_t *, const char *);
+
+struct bpf_insn *icode_to_fcode(struct icode *, struct block *, u_int *,
+    char *);
+void sappend(struct slist *, struct slist *);
+
+/*
+ * Older versions of Bison don't put this declaration in
+ * grammar.h.
+ */
+int pcap_parse(void *, compiler_state_t *);
+
+/* XXX */
+#define JT(b)  ((b)->et.succ)
+#define JF(b)  ((b)->ef.succ)
diff --git a/grammar.y.in b/grammar.y.in
new file mode 100644
index 0000000..2fbd861
--- /dev/null
+++ b/grammar.y.in
@@ -0,0 +1,843 @@
+/*
+ * We want a reentrant parser.
+ */
+@REENTRANT_PARSER@
+
+/*
+ * We also want a reentrant scanner, so we have to pass the
+ * handle for the reentrant scanner to the parser, and the
+ * parser has to pass it to the lexical analyzer.
+ *
+ * We use void * rather than yyscan_t because, at least with some
+ * versions of Flex and Bison, if you use yyscan_t in %parse-param and
+ * %lex-param, you have to include scanner.h before grammar.h to get
+ * yyscan_t declared, and you have to include grammar.h before scanner.h
+ * to get YYSTYPE declared.  Using void * breaks the cycle; the Flex
+ * documentation says yyscan_t is just a void *.
+ */
+%parse-param   {void *yyscanner}
+%lex-param   {void *yyscanner}
+
+/*
+ * According to bison documentation, shift/reduce conflicts are not an issue
+ * in most parsers as long as the number does not evolve over time:
+ * https://www.gnu.org/software/bison/manual/html_node/Expect-Decl.html
+ * So, following the advice use %expect to check the amount of shift/reduce
+ * warnings.
+ *
+ * This doesn't appear to work in Berkeley YACC - 1.9 20170709; it still
+ * warns of 38 shift/reduce conflicts.
+ *
+ * The Berkeley YACC documentation:
+ *
+ *    https://invisible-island.net/byacc/manpage/yacc.html
+ *
+ * claims that "Bison's support for "%expect" is broken in more than one
+ * release.", but doesn't give details.  Hopefully, that only means that
+ * you get warnings even if you have the expected number of shift/reduce
+ * conflicts, not that anything else fails.
+ */
+%expect 38
+
+/*
+ * And we need to pass the compiler state to the scanner.
+ */
+%parse-param { compiler_state_t *cstate }
+
+%{
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* _WIN32 */
+
+#include <stdio.h>
+
+#include "diag-control.h"
+
+#include "pcap-int.h"
+
+#include "gencode.h"
+#include "grammar.h"
+#include "scanner.h"
+
+#ifdef HAVE_NET_PFVAR_H
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <net/if_pflog.h>
+#endif
+#include "llc.h"
+#include "ieee80211.h"
+#include <pcap/namedb.h>
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef YYBYACC
+/*
+ * Both Berkeley YACC and Bison define yydebug (under whatever name
+ * it has) as a global, but Bison does so only if YYDEBUG is defined.
+ * Berkeley YACC define it even if YYDEBUG isn't defined; declare it
+ * here to suppress a warning.
+ */
+#if !defined(YYDEBUG)
+extern int yydebug;
+#endif
+
+/*
+ * In Berkeley YACC, yynerrs (under whatever name it has) is global,
+ * even if it's building a reentrant parser.  In Bison, it's local
+ * in reentrant parsers.
+ *
+ * Declare it to squelch a warning.
+ */
+extern int yynerrs;
+#endif
+
+#define QSET(q, p, d, a) (q).proto = (unsigned char)(p),\
+			 (q).dir = (unsigned char)(d),\
+			 (q).addr = (unsigned char)(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 }
+};
+static const struct tok llc_s_subtypes[] = {
+	{ LLC_RR, "rr" },
+	{ LLC_RNR, "rnr" },
+	{ LLC_REJ, "rej" },
+	{ 0, NULL }
+};
+static const struct tok llc_u_subtypes[] = {
+	{ LLC_UI, "ui" },
+	{ LLC_UA, "ua" },
+	{ LLC_DISC, "disc" },
+	{ LLC_DM, "dm" },
+	{ LLC_SABME, "sabme" },
+	{ LLC_TEST, "test" },
+	{ LLC_XID, "xid" },
+	{ LLC_FRMR, "frmr" },
+	{ 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) {
+			/*
+			 * Just in case somebody is using this to
+			 * generate values of -1/0xFFFFFFFF.
+			 * That won't work, as it's indistinguishable
+			 * from an error.
+			 */
+			if (toks[i].v == -1)
+				abort();
+			return (toks[i].v);
+		}
+	}
+	return (-1);
+}
+
+static const struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
+
+static void
+yyerror(void *yyscanner _U_, compiler_state_t *cstate, const char *msg)
+{
+	bpf_set_error(cstate, "can't parse filter expression: %s", msg);
+}
+
+#ifdef HAVE_NET_PFVAR_H
+static int
+pfreason_to_num(compiler_state_t *cstate, const char *reason)
+{
+	const char *reasons[] = PFRES_NAMES;
+	int i;
+
+	for (i = 0; reasons[i]; i++) {
+		if (pcap_strcasecmp(reason, reasons[i]) == 0)
+			return (i);
+	}
+	bpf_set_error(cstate, "unknown PF reason \"%s\"", reason);
+	return (-1);
+}
+
+static int
+pfaction_to_num(compiler_state_t *cstate, const char *action)
+{
+	if (pcap_strcasecmp(action, "pass") == 0 ||
+	    pcap_strcasecmp(action, "accept") == 0)
+		return (PF_PASS);
+	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_set_error(cstate, "unknown PF action \"%s\"", action);
+		return (-1);
+	}
+}
+#else /* !HAVE_NET_PFVAR_H */
+static int
+pfreason_to_num(compiler_state_t *cstate, const char *reason _U_)
+{
+	bpf_set_error(cstate, "libpcap was compiled on a machine without pf support");
+	return (-1);
+}
+
+static int
+pfaction_to_num(compiler_state_t *cstate, const char *action _U_)
+{
+	bpf_set_error(cstate, "libpcap was compiled on a machine without pf support");
+	return (-1);
+}
+#endif /* HAVE_NET_PFVAR_H */
+
+/*
+ * For calls that might return an "an error occurred" value.
+ */
+#define CHECK_INT_VAL(val)	if (val == -1) YYABORT
+#define CHECK_PTR_VAL(val)	if (val == NULL) YYABORT
+
+DIAG_OFF_BISON_BYACC
+%}
+
+%union {
+	int i;
+	bpf_u_int32 h;
+	char *s;
+	struct stmt *stmt;
+	struct arth *a;
+	struct {
+		struct qual q;
+		int atmfieldtype;
+		int mtp3fieldtype;
+		struct block *b;
+	} blk;
+	struct block *rblk;
+}
+
+%type	<blk>	expr id nid pid term rterm qid
+%type	<blk>	head
+%type	<i>	pqual dqual aqual ndaqual
+%type	<a>	arth narth
+%type	<i>	byteop pname relop irelop
+%type	<h>	pnum
+%type	<blk>	and or paren not null prog
+%type	<rblk>	other pfvar p80211 pllc
+%type	<i>	atmtype atmmultitype
+%type	<blk>	atmfield
+%type	<blk>	atmfieldvalue atmvalue atmlistvalue
+%type	<i>	mtp2type
+%type	<blk>	mtp3field
+%type	<blk>	mtp3fieldvalue mtp3value mtp3listvalue
+
+
+%token  DST SRC HOST GATEWAY
+%token  NET NETMASK PORT PORTRANGE LESS GREATER PROTO PROTOCHAIN CBYTE
+%token  ARP RARP IP SCTP TCP UDP ICMP IGMP IGRP PIM VRRP CARP
+%token  ATALK AARP DECNET LAT SCA MOPRC MOPDL
+%token  TK_BROADCAST TK_MULTICAST
+%token  NUM INBOUND OUTBOUND
+%token  IFINDEX
+%token  PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION
+%token	TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4 RA TA
+%token  LINK
+%token	GEQ LEQ NEQ
+%token	ID EID HID HID6 AID
+%token	LSH RSH
+%token  LEN
+%token  IPV6 ICMPV6 AH ESP
+%token	VLAN MPLS
+%token	PPPOED PPPOES GENEVE
+%token  ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP
+%token  STP
+%token  IPX
+%token  NETBEUI
+%token	LANE LLC METAC BCC SC ILMIC OAMF4EC OAMF4SC
+%token	OAM OAMF4 CONNECTMSG METACONNECT
+%token	VPI VCI
+%token	RADIO
+%token	FISU LSSU MSU HFISU HLSSU HMSU
+%token	SIO OPC DPC SLS HSIO HOPC HDPC HSLS
+%token	LEX_ERROR
+
+%type	<s> ID EID AID
+%type	<s> HID HID6
+%type	<h> NUM
+%type	<i> action reason type subtype type_subtype dir
+
+%left OR AND
+%nonassoc  '!'
+%left '|'
+%left '&'
+%left LSH RSH
+%left '+' '-'
+%left '*' '/'
+%nonassoc UMINUS
+%%
+prog:	  null expr
+{
+	CHECK_INT_VAL(finish_parse(cstate, $2.b));
+}
+	| null
+	;
+null:	  /* null */		{ $$.q = qerr; }
+	;
+expr:	  term
+	| expr and term		{ gen_and($1.b, $3.b); $$ = $3; }
+	| expr and id		{ gen_and($1.b, $3.b); $$ = $3; }
+	| expr or term		{ gen_or($1.b, $3.b); $$ = $3; }
+	| expr or id		{ gen_or($1.b, $3.b); $$ = $3; }
+	;
+and:	  AND			{ $$ = $<blk>0; }
+	;
+or:	  OR			{ $$ = $<blk>0; }
+	;
+id:	  nid
+	| pnum			{ CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
+						   $$.q = $<blk>0.q))); }
+	| paren pid ')'		{ $$ = $2; }
+	;
+nid:	  ID			{ CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.q = $<blk>0.q))); }
+	| HID '/' NUM		{ CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, NULL, $3,
+				    $$.q = $<blk>0.q))); }
+	| HID NETMASK HID	{ CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, $3, 0,
+				    $$.q = $<blk>0.q))); }
+	| HID			{
+				  CHECK_PTR_VAL($1);
+				  /* Decide how to parse HID based on proto */
+				  $$.q = $<blk>0.q;
+				  if ($$.q.addr == Q_PORT) {
+					bpf_set_error(cstate, "'port' modifier applied to ip host");
+					YYABORT;
+				  } else if ($$.q.addr == Q_PORTRANGE) {
+					bpf_set_error(cstate, "'portrange' modifier applied to ip host");
+					YYABORT;
+				  } else if ($$.q.addr == Q_PROTO) {
+					bpf_set_error(cstate, "'proto' modifier applied to ip host");
+					YYABORT;
+				  } else if ($$.q.addr == Q_PROTOCHAIN) {
+					bpf_set_error(cstate, "'protochain' modifier applied to ip host");
+					YYABORT;
+				  }
+				  CHECK_PTR_VAL(($$.b = gen_ncode(cstate, $1, 0, $$.q)));
+				}
+	| HID6 '/' NUM		{
+				  CHECK_PTR_VAL($1);
+#ifdef INET6
+				  CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, NULL, $3,
+				    $$.q = $<blk>0.q)));
+#else
+				  bpf_set_error(cstate, "'ip6addr/prefixlen' not supported "
+					"in this configuration");
+				  YYABORT;
+#endif /*INET6*/
+				}
+	| HID6			{
+				  CHECK_PTR_VAL($1);
+#ifdef INET6
+				  CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, 0, 128,
+				    $$.q = $<blk>0.q)));
+#else
+				  bpf_set_error(cstate, "'ip6addr' not supported "
+					"in this configuration");
+				  YYABORT;
+#endif /*INET6*/
+				}
+	| EID			{ CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_ecode(cstate, $1, $$.q = $<blk>0.q))); }
+	| AID			{ CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_acode(cstate, $1, $$.q = $<blk>0.q))); }
+	| not id		{ gen_not($2.b); $$ = $2; }
+	;
+not:	  '!'			{ $$ = $<blk>0; }
+	;
+paren:	  '('			{ $$ = $<blk>0; }
+	;
+pid:	  nid
+	| qid and id		{ gen_and($1.b, $3.b); $$ = $3; }
+	| qid or id		{ gen_or($1.b, $3.b); $$ = $3; }
+	;
+qid:	  pnum			{ CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
+						   $$.q = $<blk>0.q))); }
+	| pid
+	;
+term:	  rterm
+	| not term		{ gen_not($2.b); $$ = $2; }
+	;
+head:	  pqual dqual aqual	{ QSET($$.q, $1, $2, $3); }
+	| pqual dqual		{ QSET($$.q, $1, $2, Q_DEFAULT); }
+	| pqual aqual		{ QSET($$.q, $1, Q_DEFAULT, $2); }
+	| pqual PROTO		{ QSET($$.q, $1, Q_DEFAULT, Q_PROTO); }
+	| pqual PROTOCHAIN	{
+#ifdef NO_PROTOCHAIN
+				  bpf_set_error(cstate, "protochain not supported");
+				  YYABORT;
+#else
+				  QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN);
+#endif
+				}
+	| pqual ndaqual		{ QSET($$.q, $1, Q_DEFAULT, $2); }
+	;
+rterm:	  head id		{ $$ = $2; }
+	| paren expr ')'	{ $$.b = $2.b; $$.q = $1.q; }
+	| pname			{ CHECK_PTR_VAL(($$.b = gen_proto_abbrev(cstate, $1))); $$.q = qerr; }
+	| arth relop arth	{ CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 0)));
+				  $$.q = qerr; }
+	| arth irelop arth	{ CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 1)));
+				  $$.q = qerr; }
+	| other			{ $$.b = $1; $$.q = qerr; }
+	| atmtype		{ CHECK_PTR_VAL(($$.b = gen_atmtype_abbrev(cstate, $1))); $$.q = qerr; }
+	| atmmultitype		{ CHECK_PTR_VAL(($$.b = gen_atmmulti_abbrev(cstate, $1))); $$.q = qerr; }
+	| atmfield atmvalue	{ $$.b = $2.b; $$.q = qerr; }
+	| mtp2type		{ CHECK_PTR_VAL(($$.b = gen_mtp2type_abbrev(cstate, $1))); $$.q = qerr; }
+	| mtp3field mtp3value	{ $$.b = $2.b; $$.q = qerr; }
+	;
+/* protocol level qualifiers */
+pqual:	  pname
+	|			{ $$ = Q_DEFAULT; }
+	;
+/* 'direction' qualifiers */
+dqual:	  SRC			{ $$ = Q_SRC; }
+	| DST			{ $$ = Q_DST; }
+	| SRC OR DST		{ $$ = Q_OR; }
+	| 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; }
+	| RA			{ $$ = Q_RA; }
+	| TA			{ $$ = Q_TA; }
+	;
+/* address type qualifiers */
+aqual:	  HOST			{ $$ = Q_HOST; }
+	| NET			{ $$ = Q_NET; }
+	| PORT			{ $$ = Q_PORT; }
+	| PORTRANGE		{ $$ = Q_PORTRANGE; }
+	;
+/* non-directional address type qualifiers */
+ndaqual:  GATEWAY		{ $$ = Q_GATEWAY; }
+	;
+pname:	  LINK			{ $$ = Q_LINK; }
+	| IP			{ $$ = Q_IP; }
+	| ARP			{ $$ = Q_ARP; }
+	| RARP			{ $$ = Q_RARP; }
+	| SCTP			{ $$ = Q_SCTP; }
+	| TCP			{ $$ = Q_TCP; }
+	| UDP			{ $$ = Q_UDP; }
+	| ICMP			{ $$ = Q_ICMP; }
+	| IGMP			{ $$ = Q_IGMP; }
+	| IGRP			{ $$ = Q_IGRP; }
+	| PIM			{ $$ = Q_PIM; }
+	| VRRP			{ $$ = Q_VRRP; }
+	| CARP			{ $$ = Q_CARP; }
+	| ATALK			{ $$ = Q_ATALK; }
+	| AARP			{ $$ = Q_AARP; }
+	| DECNET		{ $$ = Q_DECNET; }
+	| LAT			{ $$ = Q_LAT; }
+	| SCA			{ $$ = Q_SCA; }
+	| MOPDL			{ $$ = Q_MOPDL; }
+	| MOPRC			{ $$ = Q_MOPRC; }
+	| IPV6			{ $$ = Q_IPV6; }
+	| ICMPV6		{ $$ = Q_ICMPV6; }
+	| AH			{ $$ = Q_AH; }
+	| ESP			{ $$ = Q_ESP; }
+	| ISO			{ $$ = Q_ISO; }
+	| ESIS			{ $$ = Q_ESIS; }
+	| ISIS			{ $$ = Q_ISIS; }
+	| L1			{ $$ = Q_ISIS_L1; }
+	| L2			{ $$ = Q_ISIS_L2; }
+	| IIH			{ $$ = Q_ISIS_IIH; }
+	| LSP			{ $$ = Q_ISIS_LSP; }
+	| SNP			{ $$ = Q_ISIS_SNP; }
+	| PSNP			{ $$ = Q_ISIS_PSNP; }
+	| CSNP			{ $$ = Q_ISIS_CSNP; }
+	| CLNP			{ $$ = Q_CLNP; }
+	| STP			{ $$ = Q_STP; }
+	| IPX			{ $$ = Q_IPX; }
+	| NETBEUI		{ $$ = Q_NETBEUI; }
+	| RADIO			{ $$ = Q_RADIO; }
+	;
+other:	  pqual TK_BROADCAST	{ CHECK_PTR_VAL(($$ = gen_broadcast(cstate, $1))); }
+	| pqual TK_MULTICAST	{ CHECK_PTR_VAL(($$ = gen_multicast(cstate, $1))); }
+	| LESS NUM		{ CHECK_PTR_VAL(($$ = gen_less(cstate, $2))); }
+	| GREATER NUM		{ CHECK_PTR_VAL(($$ = gen_greater(cstate, $2))); }
+	| CBYTE NUM byteop NUM	{ CHECK_PTR_VAL(($$ = gen_byteop(cstate, $3, $2, $4))); }
+	| INBOUND		{ CHECK_PTR_VAL(($$ = gen_inbound(cstate, 0))); }
+	| OUTBOUND		{ CHECK_PTR_VAL(($$ = gen_inbound(cstate, 1))); }
+	| IFINDEX NUM		{ CHECK_PTR_VAL(($$ = gen_ifindex(cstate, $2))); }
+	| VLAN pnum		{ CHECK_PTR_VAL(($$ = gen_vlan(cstate, $2, 1))); }
+	| VLAN			{ CHECK_PTR_VAL(($$ = gen_vlan(cstate, 0, 0))); }
+	| MPLS pnum		{ CHECK_PTR_VAL(($$ = gen_mpls(cstate, $2, 1))); }
+	| MPLS			{ CHECK_PTR_VAL(($$ = gen_mpls(cstate, 0, 0))); }
+	| PPPOED		{ CHECK_PTR_VAL(($$ = gen_pppoed(cstate))); }
+	| PPPOES pnum		{ CHECK_PTR_VAL(($$ = gen_pppoes(cstate, $2, 1))); }
+	| PPPOES		{ CHECK_PTR_VAL(($$ = gen_pppoes(cstate, 0, 0))); }
+	| GENEVE pnum		{ CHECK_PTR_VAL(($$ = gen_geneve(cstate, $2, 1))); }
+	| GENEVE		{ CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); }
+	| pfvar			{ $$ = $1; }
+	| pqual p80211		{ $$ = $2; }
+	| pllc			{ $$ = $1; }
+	;
+
+pfvar:	  PF_IFNAME ID		{ CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ifname(cstate, $2))); }
+	| PF_RSET ID		{ CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ruleset(cstate, $2))); }
+	| PF_RNR NUM		{ CHECK_PTR_VAL(($$ = gen_pf_rnr(cstate, $2))); }
+	| PF_SRNR NUM		{ CHECK_PTR_VAL(($$ = gen_pf_srnr(cstate, $2))); }
+	| PF_REASON reason	{ CHECK_PTR_VAL(($$ = gen_pf_reason(cstate, $2))); }
+	| PF_ACTION action	{ CHECK_PTR_VAL(($$ = gen_pf_action(cstate, $2))); }
+	;
+
+p80211:   TYPE type SUBTYPE subtype
+				{ CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2 | $4,
+					IEEE80211_FC0_TYPE_MASK |
+					IEEE80211_FC0_SUBTYPE_MASK)));
+				}
+	| TYPE type		{ CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2,
+					IEEE80211_FC0_TYPE_MASK)));
+				}
+	| SUBTYPE type_subtype	{ CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2,
+					IEEE80211_FC0_TYPE_MASK |
+					IEEE80211_FC0_SUBTYPE_MASK)));
+				}
+	| DIR dir		{ CHECK_PTR_VAL(($$ = gen_p80211_fcdir(cstate, $2))); }
+	;
+
+type:	  NUM			{ if (($1 & (~IEEE80211_FC0_TYPE_MASK)) != 0) {
+					bpf_set_error(cstate, "invalid 802.11 type value 0x%02x", $1);
+					YYABORT;
+				  }
+				  $$ = (int)$1;
+				}
+	| ID			{ CHECK_PTR_VAL($1);
+				  $$ = str2tok($1, ieee80211_types);
+				  if ($$ == -1) {
+					bpf_set_error(cstate, "unknown 802.11 type name \"%s\"", $1);
+					YYABORT;
+				  }
+				}
+	;
+
+subtype:  NUM			{ if (($1 & (~IEEE80211_FC0_SUBTYPE_MASK)) != 0) {
+					bpf_set_error(cstate, "invalid 802.11 subtype value 0x%02x", $1);
+					YYABORT;
+				  }
+				  $$ = (int)$1;
+				}
+	| ID			{ const struct tok *types = NULL;
+				  int i;
+				  CHECK_PTR_VAL($1);
+				  for (i = 0;; i++) {
+					if (ieee80211_type_subtypes[i].tok == NULL) {
+						/* Ran out of types */
+						bpf_set_error(cstate, "unknown 802.11 type");
+						YYABORT;
+					}
+					if ($<i>-1 == ieee80211_type_subtypes[i].type) {
+						types = ieee80211_type_subtypes[i].tok;
+						break;
+					}
+				  }
+
+				  $$ = str2tok($1, types);
+				  if ($$ == -1) {
+					bpf_set_error(cstate, "unknown 802.11 subtype name \"%s\"", $1);
+					YYABORT;
+				  }
+				}
+	;
+
+type_subtype:	ID		{ int i;
+				  CHECK_PTR_VAL($1);
+				  for (i = 0;; i++) {
+					if (ieee80211_type_subtypes[i].tok == NULL) {
+						/* Ran out of types */
+						bpf_set_error(cstate, "unknown 802.11 type name");
+						YYABORT;
+					}
+					$$ = str2tok($1, ieee80211_type_subtypes[i].tok);
+					if ($$ != -1) {
+						$$ |= ieee80211_type_subtypes[i].type;
+						break;
+					}
+				  }
+				}
+		;
+
+pllc:	LLC			{ CHECK_PTR_VAL(($$ = gen_llc(cstate))); }
+	| LLC ID		{ CHECK_PTR_VAL($2);
+				  if (pcap_strcasecmp($2, "i") == 0) {
+					CHECK_PTR_VAL(($$ = gen_llc_i(cstate)));
+				  } else if (pcap_strcasecmp($2, "s") == 0) {
+					CHECK_PTR_VAL(($$ = gen_llc_s(cstate)));
+				  } else if (pcap_strcasecmp($2, "u") == 0) {
+					CHECK_PTR_VAL(($$ = gen_llc_u(cstate)));
+				  } else {
+					int subtype;
+
+					subtype = str2tok($2, llc_s_subtypes);
+					if (subtype != -1) {
+						CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, subtype)));
+					} else {
+						subtype = str2tok($2, llc_u_subtypes);
+						if (subtype == -1) {
+							bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2);
+							YYABORT;
+						}
+						CHECK_PTR_VAL(($$ = gen_llc_u_subtype(cstate, subtype)));
+					}
+				  }
+				}
+				/* sigh, "rnr" is already a keyword for PF */
+	| LLC PF_RNR		{ CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, LLC_RNR))); }
+	;
+
+dir:	  NUM			{ $$ = (int)$1; }
+	| ID			{ CHECK_PTR_VAL($1);
+				  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_set_error(cstate, "unknown 802.11 direction");
+					YYABORT;
+				  }
+				}
+	;
+
+reason:	  NUM			{ $$ = $1; }
+	| ID			{ CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfreason_to_num(cstate, $1))); }
+	;
+
+action:	  ID			{ CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfaction_to_num(cstate, $1))); }
+	;
+
+relop:	  '>'			{ $$ = BPF_JGT; }
+	| GEQ			{ $$ = BPF_JGE; }
+	| '='			{ $$ = BPF_JEQ; }
+	;
+irelop:	  LEQ			{ $$ = BPF_JGT; }
+	| '<'			{ $$ = BPF_JGE; }
+	| NEQ			{ $$ = BPF_JEQ; }
+	;
+arth:	  pnum			{ CHECK_PTR_VAL(($$ = gen_loadi(cstate, $1))); }
+	| narth
+	;
+narth:	  pname '[' arth ']'		{ CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, 1))); }
+	| pname '[' arth ':' NUM ']'	{ CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, $5))); }
+	| arth '+' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_ADD, $1, $3))); }
+	| arth '-' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_SUB, $1, $3))); }
+	| arth '*' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MUL, $1, $3))); }
+	| arth '/' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_DIV, $1, $3))); }
+	| arth '%' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MOD, $1, $3))); }
+	| arth '&' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_AND, $1, $3))); }
+	| arth '|' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_OR, $1, $3))); }
+	| arth '^' arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_XOR, $1, $3))); }
+	| arth LSH arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_LSH, $1, $3))); }
+	| arth RSH arth			{ CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_RSH, $1, $3))); }
+	| '-' arth %prec UMINUS		{ CHECK_PTR_VAL(($$ = gen_neg(cstate, $2))); }
+	| paren narth ')'		{ $$ = $2; }
+	| LEN				{ CHECK_PTR_VAL(($$ = gen_loadlen(cstate))); }
+	;
+byteop:	  '&'			{ $$ = '&'; }
+	| '|'			{ $$ = '|'; }
+	| '<'			{ $$ = '<'; }
+	| '>'			{ $$ = '>'; }
+	| '='			{ $$ = '='; }
+	;
+pnum:	  NUM
+	| paren pnum ')'	{ $$ = $2; }
+	;
+atmtype: LANE			{ $$ = A_LANE; }
+	| METAC			{ $$ = A_METAC;	}
+	| BCC			{ $$ = A_BCC; }
+	| OAMF4EC		{ $$ = A_OAMF4EC; }
+	| OAMF4SC		{ $$ = A_OAMF4SC; }
+	| SC			{ $$ = A_SC; }
+	| ILMIC			{ $$ = A_ILMIC; }
+	;
+atmmultitype: OAM		{ $$ = A_OAM; }
+	| OAMF4			{ $$ = A_OAMF4; }
+	| CONNECTMSG		{ $$ = A_CONNECTMSG; }
+	| METACONNECT		{ $$ = A_METACONNECT; }
+	;
+	/* ATM field types quantifier */
+atmfield: VPI			{ $$.atmfieldtype = A_VPI; }
+	| VCI			{ $$.atmfieldtype = A_VCI; }
+	;
+atmvalue: atmfieldvalue
+	| relop NUM		{ CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, $2, $1, 0))); }
+	| irelop NUM		{ CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, $2, $1, 1))); }
+	| paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; }
+	;
+atmfieldvalue: NUM {
+	$$.atmfieldtype = $<blk>0.atmfieldtype;
+	if ($$.atmfieldtype == A_VPI ||
+	    $$.atmfieldtype == A_VCI)
+		CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $$.atmfieldtype, $1, BPF_JEQ, 0)));
+	}
+	;
+atmlistvalue: atmfieldvalue
+	| atmlistvalue or atmfieldvalue { gen_or($1.b, $3.b); $$ = $3; }
+	;
+	/* MTP2 types quantifier */
+mtp2type: FISU			{ $$ = M_FISU; }
+	| LSSU			{ $$ = M_LSSU; }
+	| MSU			{ $$ = M_MSU; }
+	| HFISU			{ $$ = MH_FISU; }
+	| HLSSU			{ $$ = MH_LSSU; }
+	| HMSU			{ $$ = MH_MSU; }
+	;
+	/* MTP3 field types quantifier */
+mtp3field: SIO			{ $$.mtp3fieldtype = M_SIO; }
+	| OPC			{ $$.mtp3fieldtype = M_OPC; }
+	| DPC			{ $$.mtp3fieldtype = M_DPC; }
+	| SLS                   { $$.mtp3fieldtype = M_SLS; }
+	| HSIO			{ $$.mtp3fieldtype = MH_SIO; }
+	| HOPC			{ $$.mtp3fieldtype = MH_OPC; }
+	| HDPC			{ $$.mtp3fieldtype = MH_DPC; }
+	| HSLS                  { $$.mtp3fieldtype = MH_SLS; }
+	;
+mtp3value: mtp3fieldvalue
+	| relop NUM		{ CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, $2, $1, 0))); }
+	| irelop NUM		{ CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, $2, $1, 1))); }
+	| paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; }
+	;
+mtp3fieldvalue: NUM {
+	$$.mtp3fieldtype = $<blk>0.mtp3fieldtype;
+	if ($$.mtp3fieldtype == M_SIO ||
+	    $$.mtp3fieldtype == M_OPC ||
+	    $$.mtp3fieldtype == M_DPC ||
+	    $$.mtp3fieldtype == M_SLS ||
+	    $$.mtp3fieldtype == MH_SIO ||
+	    $$.mtp3fieldtype == MH_OPC ||
+	    $$.mtp3fieldtype == MH_DPC ||
+	    $$.mtp3fieldtype == MH_SLS)
+		CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, $1, BPF_JEQ, 0)));
+	}
+	;
+mtp3listvalue: mtp3fieldvalue
+	| mtp3listvalue or mtp3fieldvalue { gen_or($1.b, $3.b); $$ = $3; }
+	;
+%%
diff --git a/ieee80211.h b/ieee80211.h
new file mode 100644
index 0000000..473803d
--- /dev/null
+++ b/ieee80211.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 2001 Atsushi Onoe
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/net80211/ieee80211.h,v 1.10 2005/07/22 16:55:27 sam Exp $
+ */
+#ifndef _NET80211_IEEE80211_H_
+#define _NET80211_IEEE80211_H_
+
+/*
+ * 802.11 protocol definitions.
+ */
+
+#define	IEEE80211_FC0_VERSION_MASK		0x03
+#define	IEEE80211_FC0_VERSION_SHIFT		0
+#define	IEEE80211_FC0_VERSION_0			0x00
+#define	IEEE80211_FC0_TYPE_MASK			0x0c
+#define	IEEE80211_FC0_TYPE_SHIFT		2
+#define	IEEE80211_FC0_TYPE_MGT			0x00
+#define	IEEE80211_FC0_TYPE_CTL			0x04
+#define	IEEE80211_FC0_TYPE_DATA			0x08
+
+#define	IEEE80211_FC0_SUBTYPE_MASK		0xf0
+#define	IEEE80211_FC0_SUBTYPE_SHIFT		4
+/* for TYPE_MGT */
+#define	IEEE80211_FC0_SUBTYPE_ASSOC_REQ		0x00
+#define	IEEE80211_FC0_SUBTYPE_ASSOC_RESP	0x10
+#define	IEEE80211_FC0_SUBTYPE_REASSOC_REQ	0x20
+#define	IEEE80211_FC0_SUBTYPE_REASSOC_RESP	0x30
+#define	IEEE80211_FC0_SUBTYPE_PROBE_REQ		0x40
+#define	IEEE80211_FC0_SUBTYPE_PROBE_RESP	0x50
+#define	IEEE80211_FC0_SUBTYPE_BEACON		0x80
+#define	IEEE80211_FC0_SUBTYPE_ATIM		0x90
+#define	IEEE80211_FC0_SUBTYPE_DISASSOC		0xa0
+#define	IEEE80211_FC0_SUBTYPE_AUTH		0xb0
+#define	IEEE80211_FC0_SUBTYPE_DEAUTH		0xc0
+/* for TYPE_CTL */
+#define	IEEE80211_FC0_SUBTYPE_PS_POLL		0xa0
+#define	IEEE80211_FC0_SUBTYPE_RTS		0xb0
+#define	IEEE80211_FC0_SUBTYPE_CTS		0xc0
+#define	IEEE80211_FC0_SUBTYPE_ACK		0xd0
+#define	IEEE80211_FC0_SUBTYPE_CF_END		0xe0
+#define	IEEE80211_FC0_SUBTYPE_CF_END_ACK	0xf0
+/* for TYPE_DATA (bit combination) */
+#define	IEEE80211_FC0_SUBTYPE_DATA		0x00
+#define	IEEE80211_FC0_SUBTYPE_CF_ACK		0x10
+#define	IEEE80211_FC0_SUBTYPE_CF_POLL		0x20
+#define	IEEE80211_FC0_SUBTYPE_CF_ACPL		0x30
+#define	IEEE80211_FC0_SUBTYPE_NODATA		0x40
+#define	IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK	0x50
+#define	IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL	0x60
+#define	IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL	0x70
+#define	IEEE80211_FC0_SUBTYPE_QOS		0x80
+#define	IEEE80211_FC0_SUBTYPE_QOS_NULL		0xc0
+
+#define	IEEE80211_FC1_DIR_MASK			0x03
+#define	IEEE80211_FC1_DIR_NODS			0x00	/* STA->STA */
+#define	IEEE80211_FC1_DIR_TODS			0x01	/* STA->AP  */
+#define	IEEE80211_FC1_DIR_FROMDS		0x02	/* AP ->STA */
+#define	IEEE80211_FC1_DIR_DSTODS		0x03	/* AP ->AP  */
+
+#define	IEEE80211_FC1_MORE_FRAG			0x04
+#define	IEEE80211_FC1_RETRY			0x08
+#define	IEEE80211_FC1_PWR_MGT			0x10
+#define	IEEE80211_FC1_MORE_DATA			0x20
+#define	IEEE80211_FC1_WEP			0x40
+#define	IEEE80211_FC1_ORDER			0x80
+
+#define	IEEE80211_SEQ_FRAG_MASK			0x000f
+#define	IEEE80211_SEQ_FRAG_SHIFT		0
+#define	IEEE80211_SEQ_SEQ_MASK			0xfff0
+#define	IEEE80211_SEQ_SEQ_SHIFT			4
+
+#define	IEEE80211_NWID_LEN			32
+
+#define	IEEE80211_QOS_TXOP			0x00ff
+/* bit 8 is reserved */
+#define	IEEE80211_QOS_ACKPOLICY			0x60
+#define	IEEE80211_QOS_ACKPOLICY_S		5
+#define	IEEE80211_QOS_ESOP			0x10
+#define	IEEE80211_QOS_ESOP_S			4
+#define	IEEE80211_QOS_TID			0x0f
+
+#define IEEE80211_MGT_SUBTYPE_NAMES {			\
+	"assoc-req",		"assoc-resp",		\
+	"reassoc-req",		"reassoc-resp",		\
+	"probe-req",		"probe-resp",		\
+	"reserved#6",		"reserved#7",		\
+	"beacon",		"atim",			\
+	"disassoc",		"auth",			\
+	"deauth",		"reserved#13",		\
+	"reserved#14",		"reserved#15"		\
+}
+
+#define IEEE80211_CTL_SUBTYPE_NAMES {			\
+	"reserved#0",		"reserved#1",		\
+	"reserved#2",		"reserved#3",		\
+	"reserved#3",		"reserved#5",		\
+	"reserved#6",		"reserved#7",		\
+	"reserved#8",		"reserved#9",		\
+	"ps-poll",		"rts",			\
+	"cts",			"ack",			\
+	"cf-end",		"cf-end-ack"		\
+}
+
+#define IEEE80211_DATA_SUBTYPE_NAMES {			\
+	"data",			"data-cf-ack",		\
+	"data-cf-poll",		"data-cf-ack-poll",	\
+	"null",			"cf-ack",		\
+	"cf-poll",		"cf-ack-poll",		\
+	"qos-data",		"qos-data-cf-ack",	\
+	"qos-data-cf-poll",	"qos-data-cf-ack-poll",	\
+	"qos",			"reserved#13",		\
+	"qos-cf-poll",		"qos-cf-ack-poll"	\
+}
+
+#define IEEE80211_TYPE_NAMES	{ "mgt", "ctl", "data", "reserved#4" }
+
+#endif /* _NET80211_IEEE80211_H_ */
diff --git a/llc.h b/llc.h
new file mode 100644
index 0000000..b0cf881
--- /dev/null
+++ b/llc.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1993, 1994, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Definitions for information in the LLC header.
+ */
+
+#define	LLC_U_FMT	3
+#define	LLC_GSAP	1
+#define	LLC_IG	        1 /* Individual / Group */
+#define LLC_S_FMT	1
+
+#define	LLC_U_POLL	0x10
+#define	LLC_IS_POLL	0x0100
+#define	LLC_XID_FI	0x81
+
+#define LLC_U_CMD_MASK	0xef
+#define	LLC_UI		0x03
+#define	LLC_UA		0x63
+#define	LLC_DISC	0x43
+#define	LLC_DM		0x0f
+#define	LLC_SABME	0x6f
+#define	LLC_TEST	0xe3
+#define	LLC_XID		0xaf
+#define	LLC_FRMR	0x87
+
+#define LLC_S_CMD_MASK	0x0f
+#define	LLC_RR		0x0001
+#define	LLC_RNR		0x0005
+#define	LLC_REJ		0x0009
+
+#define LLC_IS_NR(is)	(((is) >> 9) & 0x7f)
+#define LLC_I_NS(is)	(((is) >> 1) & 0x7f)
+
+/*
+ * 802.2 LLC SAP values.
+ */
+
+#ifndef LLCSAP_NULL
+#define	LLCSAP_NULL		0x00
+#endif
+#ifndef LLCSAP_GLOBAL
+#define	LLCSAP_GLOBAL		0xff
+#endif
+#ifndef LLCSAP_8021B_I
+#define	LLCSAP_8021B_I		0x02
+#endif
+#ifndef LLCSAP_8021B_G
+#define	LLCSAP_8021B_G		0x03
+#endif
+#ifndef LLCSAP_IP
+#define	LLCSAP_IP		0x06
+#endif
+#ifndef LLCSAP_PROWAYNM
+#define	LLCSAP_PROWAYNM		0x0e
+#endif
+#ifndef LLCSAP_8021D
+#define	LLCSAP_8021D		0x42
+#endif
+#ifndef LLCSAP_RS511
+#define	LLCSAP_RS511		0x4e
+#endif
+#ifndef LLCSAP_ISO8208
+#define	LLCSAP_ISO8208		0x7e
+#endif
+#ifndef LLCSAP_PROWAY
+#define	LLCSAP_PROWAY		0x8e
+#endif
+#ifndef LLCSAP_SNAP
+#define	LLCSAP_SNAP		0xaa
+#endif
+#ifndef LLCSAP_IPX
+#define LLCSAP_IPX		0xe0
+#endif
+#ifndef LLCSAP_NETBEUI
+#define LLCSAP_NETBEUI		0xf0
+#endif
+#ifndef LLCSAP_ISONS
+#define	LLCSAP_ISONS		0xfe
+#endif
diff --git a/nametoaddr.c b/nametoaddr.c
new file mode 100644
index 0000000..c944ad3
--- /dev/null
+++ b/nametoaddr.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Name to id translation routines used by the scanner.
+ * These functions are not time critical.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef DECNETLIB
+#include <sys/types.h>
+#include <netdnet/dnetdb.h>
+#endif
+
+#ifdef _WIN32
+  #include <winsock2.h>
+  #include <ws2tcpip.h>
+
+  #ifdef INET6
+    /*
+     * To quote the MSDN page for getaddrinfo() at
+     *
+     *    https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
+     *
+     * "Support for getaddrinfo on Windows 2000 and older versions
+     * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
+     * later. To execute an application that uses this function on earlier
+     * versions of Windows, then you need to include the Ws2tcpip.h and
+     * Wspiapi.h files. When the Wspiapi.h include file is added, the
+     * getaddrinfo function is defined to the WspiapiGetAddrInfo inline
+     * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
+     * function is implemented in such a way that if the Ws2_32.dll or the
+     * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
+     * Preview for Windows 2000) does not include getaddrinfo, then a
+     * version of getaddrinfo is implemented inline based on code in the
+     * Wspiapi.h header file. This inline code will be used on older Windows
+     * platforms that do not natively support the getaddrinfo function."
+     *
+     * We use getaddrinfo(), so we include Wspiapi.h here.
+     */
+    #include <wspiapi.h>
+  #endif /* INET6 */
+#else /* _WIN32 */
+  #include <sys/param.h>
+  #include <sys/types.h>
+  #include <sys/socket.h>
+  #include <sys/time.h>
+
+  #include <netinet/in.h>
+
+  #ifdef HAVE_ETHER_HOSTTON
+    #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON)
+      /*
+       * OK, just include <net/ethernet.h>.
+       */
+      #include <net/ethernet.h>
+    #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON)
+      /*
+       * OK, just include <netinet/ether.h>
+       */
+      #include <netinet/ether.h>
+    #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON)
+      /*
+       * OK, just include <sys/ethernet.h>
+       */
+      #include <sys/ethernet.h>
+    #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON)
+      /*
+       * OK, just include <arpa/inet.h>
+       */
+      #include <arpa/inet.h>
+    #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON)
+      /*
+       * OK, include <netinet/if_ether.h>, after all the other stuff we
+       * need to include or define for its benefit.
+       */
+      #define NEED_NETINET_IF_ETHER_H
+    #else
+      /*
+       * We'll have to declare it ourselves.
+       * If <netinet/if_ether.h> defines struct ether_addr, include
+       * it.  Otherwise, define it ourselves.
+       */
+      #ifdef HAVE_STRUCT_ETHER_ADDR
+        #define NEED_NETINET_IF_ETHER_H
+      #else /* HAVE_STRUCT_ETHER_ADDR */
+	struct ether_addr {
+		unsigned char ether_addr_octet[6];
+	};
+      #endif /* HAVE_STRUCT_ETHER_ADDR */
+    #endif /* what declares ether_hostton() */
+
+    #ifdef NEED_NETINET_IF_ETHER_H
+      #include <net/if.h>	/* Needed on some platforms */
+      #include <netinet/in.h>	/* Needed on some platforms */
+      #include <netinet/if_ether.h>
+    #endif /* NEED_NETINET_IF_ETHER_H */
+
+    #ifndef HAVE_DECL_ETHER_HOSTTON
+      /*
+       * No header declares it, so declare it ourselves.
+       */
+      extern int ether_hostton(const char *, struct ether_addr *);
+    #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */
+  #endif /* HAVE_ETHER_HOSTTON */
+
+  #include <arpa/inet.h>
+  #include <netdb.h>
+#endif /* _WIN32 */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "pcap-int.h"
+
+#include "diag-control.h"
+
+#include "gencode.h"
+#include <pcap/namedb.h>
+#include "nametoaddr.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifndef NTOHL
+#define NTOHL(x) (x) = ntohl(x)
+#define NTOHS(x) (x) = ntohs(x)
+#endif
+
+/*
+ *  Convert host name to internet address.
+ *  Return 0 upon failure.
+ *  XXX - not thread-safe; don't use it inside libpcap.
+ */
+bpf_u_int32 **
+pcap_nametoaddr(const char *name)
+{
+#ifndef h_addr
+	static bpf_u_int32 *hlist[2];
+#endif
+	bpf_u_int32 **p;
+	struct hostent *hp;
+
+	/*
+	 * gethostbyname() is deprecated on Windows, perhaps because
+	 * it's not thread-safe, or because it doesn't support IPv6,
+	 * or both.
+	 *
+	 * We deprecate pcap_nametoaddr() on all platforms because
+	 * it's not thread-safe; we supply it for backwards compatibility,
+	 * so suppress the deprecation warning.  We could, I guess,
+	 * use getaddrinfo() and construct the array ourselves, but
+	 * that's probably not worth the effort, as that wouldn't make
+	 * this thread-safe - we can't change the API to require that
+	 * our caller free the address array, so we still have to reuse
+	 * a local array.
+	 */
+DIAG_OFF_DEPRECATION
+	if ((hp = gethostbyname(name)) != NULL) {
+DIAG_ON_DEPRECATION
+#ifndef h_addr
+		hlist[0] = (bpf_u_int32 *)hp->h_addr;
+		NTOHL(hp->h_addr);
+		return hlist;
+#else
+		for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p)
+			NTOHL(**p);
+		return (bpf_u_int32 **)hp->h_addr_list;
+#endif
+	}
+	else
+		return 0;
+}
+
+struct addrinfo *
+pcap_nametoaddrinfo(const char *name)
+{
+	struct addrinfo hints, *res;
+	int error;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;	/*not really*/
+	hints.ai_protocol = IPPROTO_TCP;	/*not really*/
+	error = getaddrinfo(name, NULL, &hints, &res);
+	if (error)
+		return NULL;
+	else
+		return res;
+}
+
+/*
+ *  Convert net name to internet address.
+ *  Return 0 upon failure.
+ *  XXX - not guaranteed to be thread-safe!  See below for platforms
+ *  on which it is thread-safe and on which it isn't.
+ */
+#if defined(_WIN32) || defined(__CYGWIN__)
+bpf_u_int32
+pcap_nametonetaddr(const char *name _U_)
+{
+	/*
+	 * There's no "getnetbyname()" on Windows.
+	 *
+	 * XXX - I guess we could use the BSD code to read
+	 * C:\Windows\System32\drivers\etc/networks, assuming
+	 * that's its home on all the versions of Windows
+	 * we use, but that file probably just has the loopback
+	 * network on 127/24 on 99 44/100% of Windows machines.
+	 *
+	 * (Heck, these days it probably just has that on 99 44/100%
+	 * of *UN*X* machines.)
+	 */
+	return 0;
+}
+#else /* _WIN32 */
+bpf_u_int32
+pcap_nametonetaddr(const char *name)
+{
+	/*
+	 * UN*X.
+	 */
+	struct netent *np;
+  #if defined(HAVE_LINUX_GETNETBYNAME_R)
+	/*
+	 * We have Linux's reentrant getnetbyname_r().
+	 */
+	struct netent result_buf;
+	char buf[1024];	/* arbitrary size */
+	int h_errnoval;
+	int err;
+
+	/*
+	 * Apparently, the man page at
+	 *
+	 *    http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html
+	 *
+	 * lies when it says
+	 *
+	 *    If the function call successfully obtains a network record,
+	 *    then *result is set pointing to result_buf; otherwise, *result
+	 *    is set to NULL.
+	 *
+	 * and, in fact, at least in some versions of GNU libc, it does
+	 * *not* always get set if getnetbyname_r() succeeds.
+	 */
+	np = NULL;
+ 	err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np,
+	    &h_errnoval);
+	if (err != 0) {
+		/*
+		 * XXX - dynamically allocate the buffer, and make it
+		 * bigger if we get ERANGE back?
+		 */
+		return 0;
+	}
+  #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
+	/*
+	 * We have Solaris's and IRIX's reentrant getnetbyname_r().
+	 */
+	struct netent result_buf;
+	char buf[1024];	/* arbitrary size */
+
+	np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf);
+  #elif defined(HAVE_AIX_GETNETBYNAME_R)
+	/*
+	 * We have AIX's reentrant getnetbyname_r().
+	 */
+	struct netent result_buf;
+	struct netent_data net_data;
+
+	if (getnetbyname_r(name, &result_buf, &net_data) == -1)
+		np = NULL;
+	else
+		np = &result_buf;
+  #else
+ 	/*
+ 	 * We don't have any getnetbyname_r(); either we have a
+ 	 * getnetbyname() that uses thread-specific data, in which
+ 	 * case we're thread-safe (sufficiently recent FreeBSD,
+ 	 * sufficiently recent Darwin-based OS, sufficiently recent
+ 	 * HP-UX, sufficiently recent Tru64 UNIX), or we have the
+ 	 * traditional getnetbyname() (everything else, including
+ 	 * current NetBSD and OpenBSD), in which case we're not
+ 	 * thread-safe.
+ 	 */
+	np = getnetbyname(name);
+  #endif
+	if (np != NULL)
+		return np->n_net;
+	else
+		return 0;
+}
+#endif /* _WIN32 */
+
+/*
+ * Convert a port name to its port and protocol numbers.
+ * We assume only TCP or UDP.
+ * Return 0 upon failure.
+ */
+int
+pcap_nametoport(const char *name, int *port, int *proto)
+{
+	struct addrinfo hints, *res, *ai;
+	int error;
+	struct sockaddr_in *in4;
+#ifdef INET6
+	struct sockaddr_in6 *in6;
+#endif
+	int tcp_port = -1;
+	int udp_port = -1;
+
+	/*
+	 * We check for both TCP and UDP in case there are
+	 * ambiguous entries.
+	 */
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = IPPROTO_TCP;
+	error = getaddrinfo(NULL, name, &hints, &res);
+	if (error != 0) {
+		if (error != EAI_NONAME &&
+		    error != EAI_SERVICE) {
+			/*
+			 * This is a real error, not just "there's
+			 * no such service name".
+			 * XXX - this doesn't return an error string.
+			 */
+			return 0;
+		}
+	} else {
+		/*
+		 * OK, we found it.  Did it find anything?
+		 */
+		for (ai = res; ai != NULL; ai = ai->ai_next) {
+			/*
+			 * Does it have an address?
+			 */
+			if (ai->ai_addr != NULL) {
+				/*
+				 * Yes.  Get a port number; we're done.
+				 */
+				if (ai->ai_addr->sa_family == AF_INET) {
+					in4 = (struct sockaddr_in *)ai->ai_addr;
+					tcp_port = ntohs(in4->sin_port);
+					break;
+				}
+#ifdef INET6
+				if (ai->ai_addr->sa_family == AF_INET6) {
+					in6 = (struct sockaddr_in6 *)ai->ai_addr;
+					tcp_port = ntohs(in6->sin6_port);
+					break;
+				}
+#endif
+			}
+		}
+		freeaddrinfo(res);
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_DGRAM;
+	hints.ai_protocol = IPPROTO_UDP;
+	error = getaddrinfo(NULL, name, &hints, &res);
+	if (error != 0) {
+		if (error != EAI_NONAME &&
+		    error != EAI_SERVICE) {
+			/*
+			 * This is a real error, not just "there's
+			 * no such service name".
+			 * XXX - this doesn't return an error string.
+			 */
+			return 0;
+		}
+	} else {
+		/*
+		 * OK, we found it.  Did it find anything?
+		 */
+		for (ai = res; ai != NULL; ai = ai->ai_next) {
+			/*
+			 * Does it have an address?
+			 */
+			if (ai->ai_addr != NULL) {
+				/*
+				 * Yes.  Get a port number; we're done.
+				 */
+				if (ai->ai_addr->sa_family == AF_INET) {
+					in4 = (struct sockaddr_in *)ai->ai_addr;
+					udp_port = ntohs(in4->sin_port);
+					break;
+				}
+#ifdef INET6
+				if (ai->ai_addr->sa_family == AF_INET6) {
+					in6 = (struct sockaddr_in6 *)ai->ai_addr;
+					udp_port = ntohs(in6->sin6_port);
+					break;
+				}
+#endif
+			}
+		}
+		freeaddrinfo(res);
+	}
+
+	/*
+	 * We need to check /etc/services for ambiguous entries.
+	 * If we find an ambiguous entry, and it has the
+	 * same port number, change the proto to PROTO_UNDEF
+	 * so both TCP and UDP will be checked.
+	 */
+	if (tcp_port >= 0) {
+		*port = tcp_port;
+		*proto = IPPROTO_TCP;
+		if (udp_port >= 0) {
+			if (udp_port == tcp_port)
+				*proto = PROTO_UNDEF;
+#ifdef notdef
+			else
+				/* Can't handle ambiguous names that refer
+				   to different port numbers. */
+				warning("ambiguous port %s in /etc/services",
+					name);
+#endif
+		}
+		return 1;
+	}
+	if (udp_port >= 0) {
+		*port = udp_port;
+		*proto = IPPROTO_UDP;
+		return 1;
+	}
+#if defined(ultrix) || defined(__osf__)
+	/* Special hack in case NFS isn't in /etc/services */
+	if (strcmp(name, "nfs") == 0) {
+		*port = 2049;
+		*proto = PROTO_UNDEF;
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * Convert a string in the form PPP-PPP, where correspond to ports, to
+ * a starting and ending port in a port range.
+ * Return 0 on failure.
+ */
+int
+pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto)
+{
+	u_int p1, p2;
+	char *off, *cpy;
+	int save_proto;
+
+	if (sscanf(name, "%d-%d", &p1, &p2) != 2) {
+		if ((cpy = strdup(name)) == NULL)
+			return 0;
+
+		if ((off = strchr(cpy, '-')) == NULL) {
+			free(cpy);
+			return 0;
+		}
+
+		*off = '\0';
+
+		if (pcap_nametoport(cpy, port1, proto) == 0) {
+			free(cpy);
+			return 0;
+		}
+		save_proto = *proto;
+
+		if (pcap_nametoport(off + 1, port2, proto) == 0) {
+			free(cpy);
+			return 0;
+		}
+		free(cpy);
+
+		if (*proto != save_proto)
+			*proto = PROTO_UNDEF;
+	} else {
+		*port1 = p1;
+		*port2 = p2;
+		*proto = PROTO_UNDEF;
+	}
+
+	return 1;
+}
+
+/*
+ * XXX - not guaranteed to be thread-safe!  See below for platforms
+ * on which it is thread-safe and on which it isn't.
+ */
+int
+pcap_nametoproto(const char *str)
+{
+	struct protoent *p;
+  #if defined(HAVE_LINUX_GETNETBYNAME_R)
+	/*
+	 * We have Linux's reentrant getprotobyname_r().
+	 */
+	struct protoent result_buf;
+	char buf[1024];	/* arbitrary size */
+	int err;
+
+	err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p);
+	if (err != 0) {
+		/*
+		 * XXX - dynamically allocate the buffer, and make it
+		 * bigger if we get ERANGE back?
+		 */
+		return 0;
+	}
+  #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
+	/*
+	 * We have Solaris's and IRIX's reentrant getprotobyname_r().
+	 */
+	struct protoent result_buf;
+	char buf[1024];	/* arbitrary size */
+
+	p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf);
+  #elif defined(HAVE_AIX_GETNETBYNAME_R)
+	/*
+	 * We have AIX's reentrant getprotobyname_r().
+	 */
+	struct protoent result_buf;
+	struct protoent_data proto_data;
+
+	if (getprotobyname_r(str, &result_buf, &proto_data) == -1)
+		p = NULL;
+	else
+		p = &result_buf;
+  #else
+ 	/*
+ 	 * We don't have any getprotobyname_r(); either we have a
+ 	 * getprotobyname() that uses thread-specific data, in which
+ 	 * case we're thread-safe (sufficiently recent FreeBSD,
+ 	 * sufficiently recent Darwin-based OS, sufficiently recent
+ 	 * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have
+	 * the traditional getprotobyname() (everything else, including
+ 	 * current NetBSD and OpenBSD), in which case we're not
+ 	 * thread-safe.
+ 	 */
+	p = getprotobyname(str);
+  #endif
+	if (p != 0)
+		return p->p_proto;
+	else
+		return PROTO_UNDEF;
+}
+
+#include "ethertype.h"
+
+struct eproto {
+	const char *s;
+	u_short p;
+};
+
+/*
+ * Static data base of ether protocol types.
+ * tcpdump used to import this, and it's declared as an export on
+ * Debian, at least, so make it a public symbol, even though we
+ * don't officially export it by declaring it in a header file.
+ * (Programs *should* do this themselves, as tcpdump now does.)
+ *
+ * We declare it here, right before defining it, to squelch any
+ * warnings we might get from compilers about the lack of a
+ * declaration.
+ */
+PCAP_API struct eproto eproto_db[];
+PCAP_API_DEF struct eproto eproto_db[] = {
+	{ "aarp", ETHERTYPE_AARP },
+	{ "arp", ETHERTYPE_ARP },
+	{ "atalk", ETHERTYPE_ATALK },
+	{ "decnet", ETHERTYPE_DN },
+	{ "ip", ETHERTYPE_IP },
+#ifdef INET6
+	{ "ip6", ETHERTYPE_IPV6 },
+#endif
+	{ "lat", ETHERTYPE_LAT },
+	{ "loopback", ETHERTYPE_LOOPBACK },
+	{ "mopdl", ETHERTYPE_MOPDL },
+	{ "moprc", ETHERTYPE_MOPRC },
+	{ "rarp", ETHERTYPE_REVARP },
+	{ "sca", ETHERTYPE_SCA },
+	{ (char *)0, 0 }
+};
+
+int
+pcap_nametoeproto(const char *s)
+{
+	struct eproto *p = eproto_db;
+
+	while (p->s != 0) {
+		if (strcmp(p->s, s) == 0)
+			return p->p;
+		p += 1;
+	}
+	return PROTO_UNDEF;
+}
+
+#include "llc.h"
+
+/* Static data base of LLC values. */
+static struct eproto llc_db[] = {
+	{ "iso", LLCSAP_ISONS },
+	{ "stp", LLCSAP_8021D },
+	{ "ipx", LLCSAP_IPX },
+	{ "netbeui", LLCSAP_NETBEUI },
+	{ (char *)0, 0 }
+};
+
+int
+pcap_nametollc(const char *s)
+{
+	struct eproto *p = llc_db;
+
+	while (p->s != 0) {
+		if (strcmp(p->s, s) == 0)
+			return p->p;
+		p += 1;
+	}
+	return PROTO_UNDEF;
+}
+
+/* Hex digit to 8-bit unsigned integer. */
+static inline u_char
+xdtoi(u_char c)
+{
+	if (c >= '0' && c <= '9')
+		return (u_char)(c - '0');
+	else if (c >= 'a' && c <= 'f')
+		return (u_char)(c - 'a' + 10);
+	else
+		return (u_char)(c - 'A' + 10);
+}
+
+int
+__pcap_atoin(const char *s, bpf_u_int32 *addr)
+{
+	u_int n;
+	int len;
+
+	*addr = 0;
+	len = 0;
+	for (;;) {
+		n = 0;
+		while (*s && *s != '.') {
+			if (n > 25) {
+				/* The result will be > 255 */
+				return -1;
+			}
+			n = n * 10 + *s++ - '0';
+		}
+		if (n > 255)
+			return -1;
+		*addr <<= 8;
+		*addr |= n & 0xff;
+		len += 8;
+		if (*s == '\0')
+			return len;
+		++s;
+	}
+	/* NOTREACHED */
+}
+
+int
+__pcap_atodn(const char *s, bpf_u_int32 *addr)
+{
+#define AREASHIFT 10
+#define AREAMASK 0176000
+#define NODEMASK 01777
+
+	u_int node, area;
+
+	if (sscanf(s, "%d.%d", &area, &node) != 2)
+		return(0);
+
+	*addr = (area << AREASHIFT) & AREAMASK;
+	*addr |= (node & NODEMASK);
+
+	return(32);
+}
+
+/*
+ * 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 *
+pcap_ether_aton(const char *s)
+{
+	register u_char *ep, *e;
+	register u_char d;
+
+	e = ep = (u_char *)malloc(6);
+	if (e == NULL)
+		return (NULL);
+
+	while (*s) {
+		if (*s == ':' || *s == '.' || *s == '-')
+			s += 1;
+		d = xdtoi(*s++);
+		if (PCAP_ISXDIGIT(*s)) {
+			d <<= 4;
+			d |= xdtoi(*s++);
+		}
+		*ep++ = d;
+	}
+
+	return (e);
+}
+
+#ifndef HAVE_ETHER_HOSTTON
+/*
+ * Roll our own.
+ * XXX - not thread-safe, because pcap_next_etherent() isn't thread-
+ * safe!  Needs a mutex or a thread-safe pcap_next_etherent().
+ */
+u_char *
+pcap_ether_hostton(const char *name)
+{
+	register struct pcap_etherent *ep;
+	register u_char *ap;
+	static FILE *fp = NULL;
+	static int init = 0;
+
+	if (!init) {
+		fp = fopen(PCAP_ETHERS_FILE, "r");
+		++init;
+		if (fp == NULL)
+			return (NULL);
+	} else if (fp == NULL)
+		return (NULL);
+	else
+		rewind(fp);
+
+	while ((ep = pcap_next_etherent(fp)) != NULL) {
+		if (strcmp(ep->name, name) == 0) {
+			ap = (u_char *)malloc(6);
+			if (ap != NULL) {
+				memcpy(ap, ep->addr, 6);
+				return (ap);
+			}
+			break;
+		}
+	}
+	return (NULL);
+}
+#else
+/*
+ * Use the OS-supplied routine.
+ * This *should* be thread-safe; the API doesn't have a static buffer.
+ */
+u_char *
+pcap_ether_hostton(const char *name)
+{
+	register u_char *ap;
+	u_char a[6];
+
+	ap = NULL;
+	if (ether_hostton(name, (struct ether_addr *)a) == 0) {
+		ap = (u_char *)malloc(6);
+		if (ap != NULL)
+			memcpy((char *)ap, (char *)a, 6);
+	}
+	return (ap);
+}
+#endif
+
+/*
+ * XXX - not guaranteed to be thread-safe!
+ */
+int
+#ifdef	DECNETLIB
+__pcap_nametodnaddr(const char *name, u_short *res)
+{
+	struct nodeent *getnodebyname();
+	struct nodeent *nep;
+
+	nep = getnodebyname(name);
+	if (nep == ((struct nodeent *)0))
+		return(0);
+
+	memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short));
+	return(1);
+#else
+__pcap_nametodnaddr(const char *name _U_, u_short *res _U_)
+{
+	return(0);
+#endif
+}
diff --git a/nametoaddr.h b/nametoaddr.h
new file mode 100644
index 0000000..fd6b7e1
--- /dev/null
+++ b/nametoaddr.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1994, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Routines used for name-or-address-string-to-address resolution
+ * that are *not* exported to code using libpcap.
+ */
+int __pcap_atodn(const char *, bpf_u_int32 *);
+int __pcap_atoin(const char *, bpf_u_int32 *);
+int __pcap_nametodnaddr(const char *, u_short *);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/nlpid.h b/nlpid.h
new file mode 100644
index 0000000..9dfa752
--- /dev/null
+++ b/nlpid.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1996
+ *	Juniper Networks, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution.  The name of Juniper Networks may not
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* Types missing from some systems */
+
+/*
+ * Network layer prototocol identifiers
+ */
+#ifndef ISO8473_CLNP
+#define ISO8473_CLNP		0x81
+#endif
+#ifndef	ISO9542_ESIS
+#define	ISO9542_ESIS		0x82
+#endif
+#ifndef ISO9542X25_ESIS
+#define ISO9542X25_ESIS		0x8a
+#endif
+#ifndef	ISO10589_ISIS
+#define	ISO10589_ISIS		0x83
+#endif
+/*
+ * this does not really belong in the nlpid.h file
+ * however we need it for generating nice
+ * IS-IS related BPF filters
+ */
+#define ISIS_L1_LAN_IIH      15
+#define ISIS_L2_LAN_IIH      16
+#define ISIS_PTP_IIH         17
+#define ISIS_L1_LSP          18
+#define ISIS_L2_LSP          20
+#define ISIS_L1_CSNP         24
+#define ISIS_L2_CSNP         25
+#define ISIS_L1_PSNP         26
+#define ISIS_L2_PSNP         27
+
+#ifndef ISO8878A_CONS
+#define	ISO8878A_CONS		0x84
+#endif
+#ifndef	ISO10747_IDRP
+#define	ISO10747_IDRP		0x85
+#endif
diff --git a/optimize.c b/optimize.c
new file mode 100644
index 0000000..610a030
--- /dev/null
+++ b/optimize.c
@@ -0,0 +1,3093 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  Optimization module for BPF code intermediate representation.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <setjmp.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include "pcap-int.h"
+
+#include "gencode.h"
+#include "optimize.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef BDEBUG
+/*
+ * The internal "debug printout" flag for the filter expression optimizer.
+ * The code to print that stuff is present only if BDEBUG is defined, so
+ * the flag, and the routine to set it, are defined only if BDEBUG is
+ * defined.
+ */
+static int pcap_optimizer_debug;
+
+/*
+ * Routine to set that flag.
+ *
+ * This is intended for libpcap developers, not for general use.
+ * If you want to set these in a program, you'll have to declare this
+ * routine yourself, with the appropriate DLL import attribute on Windows;
+ * it's not declared in any header file, and won't be declared in any
+ * header file provided by libpcap.
+ */
+PCAP_API void pcap_set_optimizer_debug(int value);
+
+PCAP_API_DEF void
+pcap_set_optimizer_debug(int value)
+{
+	pcap_optimizer_debug = value;
+}
+
+/*
+ * The internal "print dot graph" flag for the filter expression optimizer.
+ * The code to print that stuff is present only if BDEBUG is defined, so
+ * the flag, and the routine to set it, are defined only if BDEBUG is
+ * defined.
+ */
+static int pcap_print_dot_graph;
+
+/*
+ * Routine to set that flag.
+ *
+ * This is intended for libpcap developers, not for general use.
+ * If you want to set these in a program, you'll have to declare this
+ * routine yourself, with the appropriate DLL import attribute on Windows;
+ * it's not declared in any header file, and won't be declared in any
+ * header file provided by libpcap.
+ */
+PCAP_API void pcap_set_print_dot_graph(int value);
+
+PCAP_API_DEF void
+pcap_set_print_dot_graph(int value)
+{
+	pcap_print_dot_graph = value;
+}
+
+#endif
+
+/*
+ * lowest_set_bit().
+ *
+ * Takes a 32-bit integer as an argument.
+ *
+ * If handed a non-zero value, returns the index of the lowest set bit,
+ * counting upwards from zero.
+ *
+ * If handed zero, the results are platform- and compiler-dependent.
+ * Keep it out of the light, don't give it any water, don't feed it
+ * after midnight, and don't pass zero to it.
+ *
+ * This is the same as the count of trailing zeroes in the word.
+ */
+#if PCAP_IS_AT_LEAST_GNUC_VERSION(3,4)
+  /*
+   * GCC 3.4 and later; we have __builtin_ctz().
+   */
+  #define lowest_set_bit(mask) ((u_int)__builtin_ctz(mask))
+#elif defined(_MSC_VER)
+  /*
+   * Visual Studio; we support only 2005 and later, so use
+   * _BitScanForward().
+   */
+#include <intrin.h>
+
+#ifndef __clang__
+#pragma intrinsic(_BitScanForward)
+#endif
+
+static __forceinline u_int
+lowest_set_bit(int mask)
+{
+	unsigned long bit;
+
+	/*
+	 * Don't sign-extend mask if long is longer than int.
+	 * (It's currently not, in MSVC, even on 64-bit platforms, but....)
+	 */
+	if (_BitScanForward(&bit, (unsigned int)mask) == 0)
+		abort();	/* mask is zero */
+	return (u_int)bit;
+}
+#elif defined(MSDOS) && defined(__DJGPP__)
+  /*
+   * MS-DOS with DJGPP, which declares ffs() in <string.h>, which
+   * we've already included.
+   */
+  #define lowest_set_bit(mask)	((u_int)(ffs((mask)) - 1))
+#elif (defined(MSDOS) && defined(__WATCOMC__)) || defined(STRINGS_H_DECLARES_FFS)
+  /*
+   * MS-DOS with Watcom C, which has <strings.h> and declares ffs() there,
+   * or some other platform (UN*X conforming to a sufficient recent version
+   * of the Single UNIX Specification).
+   */
+  #include <strings.h>
+  #define lowest_set_bit(mask)	(u_int)((ffs((mask)) - 1))
+#else
+/*
+ * None of the above.
+ * Use a perfect-hash-function-based function.
+ */
+static u_int
+lowest_set_bit(int mask)
+{
+	unsigned int v = (unsigned int)mask;
+
+	static const u_int MultiplyDeBruijnBitPosition[32] = {
+		0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+		31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+	};
+
+	/*
+	 * We strip off all but the lowermost set bit (v & ~v),
+	 * and perform a minimal perfect hash on it to look up the
+	 * number of low-order zero bits in a table.
+	 *
+	 * See:
+	 *
+	 *	http://7ooo.mooo.com/text/ComputingTrailingZerosHOWTO.pdf
+	 *
+	 *	http://supertech.csail.mit.edu/papers/debruijn.pdf
+	 */
+	return (MultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531U) >> 27]);
+}
+#endif
+
+/*
+ * Represents a deleted instruction.
+ */
+#define NOP -1
+
+/*
+ * Register numbers for use-def values.
+ * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory
+ * location.  A_ATOM is the accumulator and X_ATOM is the index
+ * register.
+ */
+#define A_ATOM BPF_MEMWORDS
+#define X_ATOM (BPF_MEMWORDS+1)
+
+/*
+ * This define is used to represent *both* the accumulator and
+ * x register in use-def computations.
+ * Currently, the use-def code assumes only one definition per instruction.
+ */
+#define AX_ATOM N_ATOMS
+
+/*
+ * These data structures are used in a Cocke and Shwarz style
+ * value numbering scheme.  Since the flowgraph is acyclic,
+ * exit values can be propagated from a node's predecessors
+ * provided it is uniquely defined.
+ */
+struct valnode {
+	int code;
+	bpf_u_int32 v0, v1;
+	int val;		/* the value number */
+	struct valnode *next;
+};
+
+/* Integer constants mapped with the load immediate opcode. */
+#define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0U)
+
+struct vmapinfo {
+	int is_const;
+	bpf_u_int32 const_val;
+};
+
+typedef struct {
+	/*
+	 * Place to longjmp to on an error.
+	 */
+	jmp_buf top_ctx;
+
+	/*
+	 * The buffer into which to put error message.
+	 */
+	char *errbuf;
+
+	/*
+	 * A flag to indicate that further optimization is needed.
+	 * Iterative passes are continued until a given pass yields no
+	 * code simplification or branch movement.
+	 */
+	int done;
+
+	/*
+	 * XXX - detect loops that do nothing but repeated AND/OR pullups
+	 * and edge moves.
+	 * If 100 passes in a row do nothing but that, treat that as a
+	 * sign that we're in a loop that just shuffles in a cycle in
+	 * which each pass just shuffles the code and we eventually
+	 * get back to the original configuration.
+	 *
+	 * XXX - we need a non-heuristic way of detecting, or preventing,
+	 * such a cycle.
+	 */
+	int non_branch_movement_performed;
+
+	u_int n_blocks;		/* number of blocks in the CFG; guaranteed to be > 0, as it's a RET instruction at a minimum */
+	struct block **blocks;
+	u_int n_edges;		/* twice n_blocks, so guaranteed to be > 0 */
+	struct edge **edges;
+
+	/*
+	 * A bit vector set representation of the dominators.
+	 * We round up the set size to the next power of two.
+	 */
+	u_int nodewords;	/* number of 32-bit words for a bit vector of "number of nodes" bits; guaranteed to be > 0 */
+	u_int edgewords;	/* number of 32-bit words for a bit vector of "number of edges" bits; guaranteed to be > 0 */
+	struct block **levels;
+	bpf_u_int32 *space;
+
+#define BITS_PER_WORD (8*sizeof(bpf_u_int32))
+/*
+ * True if a is in uset {p}
+ */
+#define SET_MEMBER(p, a) \
+((p)[(unsigned)(a) / BITS_PER_WORD] & ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)))
+
+/*
+ * Add 'a' to uset p.
+ */
+#define SET_INSERT(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] |= ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * Delete 'a' from uset p.
+ */
+#define SET_DELETE(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] &= ~((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * a := a intersect b
+ * n must be guaranteed to be > 0
+ */
+#define SET_INTERSECT(a, b, n)\
+{\
+	register bpf_u_int32 *_x = a, *_y = b;\
+	register u_int _n = n;\
+	do *_x++ &= *_y++; while (--_n != 0);\
+}
+
+/*
+ * a := a - b
+ * n must be guaranteed to be > 0
+ */
+#define SET_SUBTRACT(a, b, n)\
+{\
+	register bpf_u_int32 *_x = a, *_y = b;\
+	register u_int _n = n;\
+	do *_x++ &=~ *_y++; while (--_n != 0);\
+}
+
+/*
+ * a := a union b
+ * n must be guaranteed to be > 0
+ */
+#define SET_UNION(a, b, n)\
+{\
+	register bpf_u_int32 *_x = a, *_y = b;\
+	register u_int _n = n;\
+	do *_x++ |= *_y++; while (--_n != 0);\
+}
+
+	uset all_dom_sets;
+	uset all_closure_sets;
+	uset all_edge_sets;
+
+#define MODULUS 213
+	struct valnode *hashtbl[MODULUS];
+	bpf_u_int32 curval;
+	bpf_u_int32 maxval;
+
+	struct vmapinfo *vmap;
+	struct valnode *vnode_base;
+	struct valnode *next_vnode;
+} opt_state_t;
+
+typedef struct {
+	/*
+	 * Place to longjmp to on an error.
+	 */
+	jmp_buf top_ctx;
+
+	/*
+	 * The buffer into which to put error message.
+	 */
+	char *errbuf;
+
+	/*
+	 * Some pointers used to convert the basic block form of the code,
+	 * into the array form that BPF requires.  'fstart' will point to
+	 * the malloc'd array while 'ftail' is used during the recursive
+	 * traversal.
+	 */
+	struct bpf_insn *fstart;
+	struct bpf_insn *ftail;
+} conv_state_t;
+
+static void opt_init(opt_state_t *, struct icode *);
+static void opt_cleanup(opt_state_t *);
+static void PCAP_NORETURN opt_error(opt_state_t *, const char *, ...)
+    PCAP_PRINTFLIKE(2, 3);
+
+static void intern_blocks(opt_state_t *, struct icode *);
+
+static void find_inedges(opt_state_t *, struct block *);
+#ifdef BDEBUG
+static void opt_dump(opt_state_t *, struct icode *);
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+static void
+find_levels_r(opt_state_t *opt_state, struct icode *ic, struct block *b)
+{
+	int level;
+
+	if (isMarked(ic, b))
+		return;
+
+	Mark(ic, b);
+	b->link = 0;
+
+	if (JT(b)) {
+		find_levels_r(opt_state, ic, JT(b));
+		find_levels_r(opt_state, ic, JF(b));
+		level = MAX(JT(b)->level, JF(b)->level) + 1;
+	} else
+		level = 0;
+	b->level = level;
+	b->link = opt_state->levels[level];
+	opt_state->levels[level] = b;
+}
+
+/*
+ * Level graph.  The levels go from 0 at the leaves to
+ * N_LEVELS at the root.  The opt_state->levels[] array points to the
+ * first node of the level list, whose elements are linked
+ * with the 'link' field of the struct block.
+ */
+static void
+find_levels(opt_state_t *opt_state, struct icode *ic)
+{
+	memset((char *)opt_state->levels, 0, opt_state->n_blocks * sizeof(*opt_state->levels));
+	unMarkAll(ic);
+	find_levels_r(opt_state, ic, ic->root);
+}
+
+/*
+ * Find dominator relationships.
+ * Assumes graph has been leveled.
+ */
+static void
+find_dom(opt_state_t *opt_state, struct block *root)
+{
+	u_int i;
+	int level;
+	struct block *b;
+	bpf_u_int32 *x;
+
+	/*
+	 * Initialize sets to contain all nodes.
+	 */
+	x = opt_state->all_dom_sets;
+	/*
+	 * In opt_init(), we've made sure the product doesn't overflow.
+	 */
+	i = opt_state->n_blocks * opt_state->nodewords;
+	while (i != 0) {
+		--i;
+		*x++ = 0xFFFFFFFFU;
+	}
+	/* Root starts off empty. */
+	for (i = opt_state->nodewords; i != 0;) {
+		--i;
+		root->dom[i] = 0;
+	}
+
+	/* root->level is the highest level no found. */
+	for (level = root->level; level >= 0; --level) {
+		for (b = opt_state->levels[level]; b; b = b->link) {
+			SET_INSERT(b->dom, b->id);
+			if (JT(b) == 0)
+				continue;
+			SET_INTERSECT(JT(b)->dom, b->dom, opt_state->nodewords);
+			SET_INTERSECT(JF(b)->dom, b->dom, opt_state->nodewords);
+		}
+	}
+}
+
+static void
+propedom(opt_state_t *opt_state, struct edge *ep)
+{
+	SET_INSERT(ep->edom, ep->id);
+	if (ep->succ) {
+		SET_INTERSECT(ep->succ->et.edom, ep->edom, opt_state->edgewords);
+		SET_INTERSECT(ep->succ->ef.edom, ep->edom, opt_state->edgewords);
+	}
+}
+
+/*
+ * Compute edge dominators.
+ * Assumes graph has been leveled and predecessors established.
+ */
+static void
+find_edom(opt_state_t *opt_state, struct block *root)
+{
+	u_int i;
+	uset x;
+	int level;
+	struct block *b;
+
+	x = opt_state->all_edge_sets;
+	/*
+	 * In opt_init(), we've made sure the product doesn't overflow.
+	 */
+	for (i = opt_state->n_edges * opt_state->edgewords; i != 0; ) {
+		--i;
+		x[i] = 0xFFFFFFFFU;
+	}
+
+	/* root->level is the highest level no found. */
+	memset(root->et.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
+	memset(root->ef.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
+	for (level = root->level; level >= 0; --level) {
+		for (b = opt_state->levels[level]; b != 0; b = b->link) {
+			propedom(opt_state, &b->et);
+			propedom(opt_state, &b->ef);
+		}
+	}
+}
+
+/*
+ * Find the backwards transitive closure of the flow graph.  These sets
+ * are backwards in the sense that we find the set of nodes that reach
+ * a given node, not the set of nodes that can be reached by a node.
+ *
+ * Assumes graph has been leveled.
+ */
+static void
+find_closure(opt_state_t *opt_state, struct block *root)
+{
+	int level;
+	struct block *b;
+
+	/*
+	 * Initialize sets to contain no nodes.
+	 */
+	memset((char *)opt_state->all_closure_sets, 0,
+	      opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->all_closure_sets));
+
+	/* root->level is the highest level no found. */
+	for (level = root->level; level >= 0; --level) {
+		for (b = opt_state->levels[level]; b; b = b->link) {
+			SET_INSERT(b->closure, b->id);
+			if (JT(b) == 0)
+				continue;
+			SET_UNION(JT(b)->closure, b->closure, opt_state->nodewords);
+			SET_UNION(JF(b)->closure, b->closure, opt_state->nodewords);
+		}
+	}
+}
+
+/*
+ * Return the register number that is used by s.
+ *
+ * Returns ATOM_A if A is used, ATOM_X if X is used, AX_ATOM if both A and X
+ * are used, the scratch memory location's number if a scratch memory
+ * location is used (e.g., 0 for M[0]), or -1 if none of those are used.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomuse(struct stmt *s)
+{
+	register int c = s->code;
+
+	if (c == NOP)
+		return -1;
+
+	switch (BPF_CLASS(c)) {
+
+	case BPF_RET:
+		return (BPF_RVAL(c) == BPF_A) ? A_ATOM :
+			(BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
+
+	case BPF_LD:
+	case BPF_LDX:
+		/*
+		 * As there are fewer than 2^31 memory locations,
+		 * s->k should be convertible to int without problems.
+		 */
+		return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
+			(BPF_MODE(c) == BPF_MEM) ? (int)s->k : -1;
+
+	case BPF_ST:
+		return A_ATOM;
+
+	case BPF_STX:
+		return X_ATOM;
+
+	case BPF_JMP:
+	case BPF_ALU:
+		if (BPF_SRC(c) == BPF_X)
+			return AX_ATOM;
+		return A_ATOM;
+
+	case BPF_MISC:
+		return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
+	}
+	abort();
+	/* NOTREACHED */
+}
+
+/*
+ * Return the register number that is defined by 's'.  We assume that
+ * a single stmt cannot define more than one register.  If no register
+ * is defined, return -1.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomdef(struct stmt *s)
+{
+	if (s->code == NOP)
+		return -1;
+
+	switch (BPF_CLASS(s->code)) {
+
+	case BPF_LD:
+	case BPF_ALU:
+		return A_ATOM;
+
+	case BPF_LDX:
+		return X_ATOM;
+
+	case BPF_ST:
+	case BPF_STX:
+		return s->k;
+
+	case BPF_MISC:
+		return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
+	}
+	return -1;
+}
+
+/*
+ * Compute the sets of registers used, defined, and killed by 'b'.
+ *
+ * "Used" means that a statement in 'b' uses the register before any
+ * statement in 'b' defines it, i.e. it uses the value left in
+ * that register by a predecessor block of this block.
+ * "Defined" means that a statement in 'b' defines it.
+ * "Killed" means that a statement in 'b' defines it before any
+ * statement in 'b' uses it, i.e. it kills the value left in that
+ * register by a predecessor block of this block.
+ */
+static void
+compute_local_ud(struct block *b)
+{
+	struct slist *s;
+	atomset def = 0, use = 0, killed = 0;
+	int atom;
+
+	for (s = b->stmts; s; s = s->next) {
+		if (s->s.code == NOP)
+			continue;
+		atom = atomuse(&s->s);
+		if (atom >= 0) {
+			if (atom == AX_ATOM) {
+				if (!ATOMELEM(def, X_ATOM))
+					use |= ATOMMASK(X_ATOM);
+				if (!ATOMELEM(def, A_ATOM))
+					use |= ATOMMASK(A_ATOM);
+			}
+			else if (atom < N_ATOMS) {
+				if (!ATOMELEM(def, atom))
+					use |= ATOMMASK(atom);
+			}
+			else
+				abort();
+		}
+		atom = atomdef(&s->s);
+		if (atom >= 0) {
+			if (!ATOMELEM(use, atom))
+				killed |= ATOMMASK(atom);
+			def |= ATOMMASK(atom);
+		}
+	}
+	if (BPF_CLASS(b->s.code) == BPF_JMP) {
+		/*
+		 * XXX - what about RET?
+		 */
+		atom = atomuse(&b->s);
+		if (atom >= 0) {
+			if (atom == AX_ATOM) {
+				if (!ATOMELEM(def, X_ATOM))
+					use |= ATOMMASK(X_ATOM);
+				if (!ATOMELEM(def, A_ATOM))
+					use |= ATOMMASK(A_ATOM);
+			}
+			else if (atom < N_ATOMS) {
+				if (!ATOMELEM(def, atom))
+					use |= ATOMMASK(atom);
+			}
+			else
+				abort();
+		}
+	}
+
+	b->def = def;
+	b->kill = killed;
+	b->in_use = use;
+}
+
+/*
+ * Assume graph is already leveled.
+ */
+static void
+find_ud(opt_state_t *opt_state, struct block *root)
+{
+	int i, maxlevel;
+	struct block *p;
+
+	/*
+	 * root->level is the highest level no found;
+	 * count down from there.
+	 */
+	maxlevel = root->level;
+	for (i = maxlevel; i >= 0; --i)
+		for (p = opt_state->levels[i]; p; p = p->link) {
+			compute_local_ud(p);
+			p->out_use = 0;
+		}
+
+	for (i = 1; i <= maxlevel; ++i) {
+		for (p = opt_state->levels[i]; p; p = p->link) {
+			p->out_use |= JT(p)->in_use | JF(p)->in_use;
+			p->in_use |= p->out_use &~ p->kill;
+		}
+	}
+}
+static void
+init_val(opt_state_t *opt_state)
+{
+	opt_state->curval = 0;
+	opt_state->next_vnode = opt_state->vnode_base;
+	memset((char *)opt_state->vmap, 0, opt_state->maxval * sizeof(*opt_state->vmap));
+	memset((char *)opt_state->hashtbl, 0, sizeof opt_state->hashtbl);
+}
+
+/*
+ * Because we really don't have an IR, this stuff is a little messy.
+ *
+ * This routine looks in the table of existing value number for a value
+ * with generated from an operation with the specified opcode and
+ * the specified values.  If it finds it, it returns its value number,
+ * otherwise it makes a new entry in the table and returns the
+ * value number of that entry.
+ */
+static bpf_u_int32
+F(opt_state_t *opt_state, int code, bpf_u_int32 v0, bpf_u_int32 v1)
+{
+	u_int hash;
+	bpf_u_int32 val;
+	struct valnode *p;
+
+	hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
+	hash %= MODULUS;
+
+	for (p = opt_state->hashtbl[hash]; p; p = p->next)
+		if (p->code == code && p->v0 == v0 && p->v1 == v1)
+			return p->val;
+
+	/*
+	 * Not found.  Allocate a new value, and assign it a new
+	 * value number.
+	 *
+	 * opt_state->curval starts out as 0, which means VAL_UNKNOWN; we
+	 * increment it before using it as the new value number, which
+	 * means we never assign VAL_UNKNOWN.
+	 *
+	 * XXX - unless we overflow, but we probably won't have 2^32-1
+	 * values; we treat 32 bits as effectively infinite.
+	 */
+	val = ++opt_state->curval;
+	if (BPF_MODE(code) == BPF_IMM &&
+	    (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
+		opt_state->vmap[val].const_val = v0;
+		opt_state->vmap[val].is_const = 1;
+	}
+	p = opt_state->next_vnode++;
+	p->val = val;
+	p->code = code;
+	p->v0 = v0;
+	p->v1 = v1;
+	p->next = opt_state->hashtbl[hash];
+	opt_state->hashtbl[hash] = p;
+
+	return val;
+}
+
+static inline void
+vstore(struct stmt *s, bpf_u_int32 *valp, bpf_u_int32 newval, int alter)
+{
+	if (alter && newval != VAL_UNKNOWN && *valp == newval)
+		s->code = NOP;
+	else
+		*valp = newval;
+}
+
+/*
+ * Do constant-folding on binary operators.
+ * (Unary operators are handled elsewhere.)
+ */
+static void
+fold_op(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 v0, bpf_u_int32 v1)
+{
+	bpf_u_int32 a, b;
+
+	a = opt_state->vmap[v0].const_val;
+	b = opt_state->vmap[v1].const_val;
+
+	switch (BPF_OP(s->code)) {
+	case BPF_ADD:
+		a += b;
+		break;
+
+	case BPF_SUB:
+		a -= b;
+		break;
+
+	case BPF_MUL:
+		a *= b;
+		break;
+
+	case BPF_DIV:
+		if (b == 0)
+			opt_error(opt_state, "division by zero");
+		a /= b;
+		break;
+
+	case BPF_MOD:
+		if (b == 0)
+			opt_error(opt_state, "modulus by zero");
+		a %= b;
+		break;
+
+	case BPF_AND:
+		a &= b;
+		break;
+
+	case BPF_OR:
+		a |= b;
+		break;
+
+	case BPF_XOR:
+		a ^= b;
+		break;
+
+	case BPF_LSH:
+		/*
+		 * A left shift of more than the width of the type
+		 * is undefined in C; we'll just treat it as shifting
+		 * all the bits out.
+		 *
+		 * XXX - the BPF interpreter doesn't check for this,
+		 * so its behavior is dependent on the behavior of
+		 * the processor on which it's running.  There are
+		 * processors on which it shifts all the bits out
+		 * and processors on which it does no shift.
+		 */
+		if (b < 32)
+			a <<= b;
+		else
+			a = 0;
+		break;
+
+	case BPF_RSH:
+		/*
+		 * A right shift of more than the width of the type
+		 * is undefined in C; we'll just treat it as shifting
+		 * all the bits out.
+		 *
+		 * XXX - the BPF interpreter doesn't check for this,
+		 * so its behavior is dependent on the behavior of
+		 * the processor on which it's running.  There are
+		 * processors on which it shifts all the bits out
+		 * and processors on which it does no shift.
+		 */
+		if (b < 32)
+			a >>= b;
+		else
+			a = 0;
+		break;
+
+	default:
+		abort();
+	}
+	s->k = a;
+	s->code = BPF_LD|BPF_IMM;
+	/*
+	 * XXX - optimizer loop detection.
+	 */
+	opt_state->non_branch_movement_performed = 1;
+	opt_state->done = 0;
+}
+
+static inline struct slist *
+this_op(struct slist *s)
+{
+	while (s != 0 && s->s.code == NOP)
+		s = s->next;
+	return s;
+}
+
+static void
+opt_not(struct block *b)
+{
+	struct block *tmp = JT(b);
+
+	JT(b) = JF(b);
+	JF(b) = tmp;
+}
+
+static void
+opt_peep(opt_state_t *opt_state, struct block *b)
+{
+	struct slist *s;
+	struct slist *next, *last;
+	bpf_u_int32 val;
+
+	s = b->stmts;
+	if (s == 0)
+		return;
+
+	last = s;
+	for (/*empty*/; /*empty*/; s = next) {
+		/*
+		 * Skip over nops.
+		 */
+		s = this_op(s);
+		if (s == 0)
+			break;	/* nothing left in the block */
+
+		/*
+		 * Find the next real instruction after that one
+		 * (skipping nops).
+		 */
+		next = this_op(s->next);
+		if (next == 0)
+			break;	/* no next instruction */
+		last = next;
+
+		/*
+		 * st  M[k]	-->	st  M[k]
+		 * ldx M[k]		tax
+		 */
+		if (s->s.code == BPF_ST &&
+		    next->s.code == (BPF_LDX|BPF_MEM) &&
+		    s->s.k == next->s.k) {
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+			next->s.code = BPF_MISC|BPF_TAX;
+		}
+		/*
+		 * ld  #k	-->	ldx  #k
+		 * tax			txa
+		 */
+		if (s->s.code == (BPF_LD|BPF_IMM) &&
+		    next->s.code == (BPF_MISC|BPF_TAX)) {
+			s->s.code = BPF_LDX|BPF_IMM;
+			next->s.code = BPF_MISC|BPF_TXA;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+		/*
+		 * This is an ugly special case, but it happens
+		 * when you say tcp[k] or udp[k] where k is a constant.
+		 */
+		if (s->s.code == (BPF_LD|BPF_IMM)) {
+			struct slist *add, *tax, *ild;
+
+			/*
+			 * Check that X isn't used on exit from this
+			 * block (which the optimizer might cause).
+			 * We know the code generator won't generate
+			 * any local dependencies.
+			 */
+			if (ATOMELEM(b->out_use, X_ATOM))
+				continue;
+
+			/*
+			 * Check that the instruction following the ldi
+			 * is an addx, or it's an ldxms with an addx
+			 * following it (with 0 or more nops between the
+			 * ldxms and addx).
+			 */
+			if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
+				add = next;
+			else
+				add = this_op(next->next);
+			if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X))
+				continue;
+
+			/*
+			 * Check that a tax follows that (with 0 or more
+			 * nops between them).
+			 */
+			tax = this_op(add->next);
+			if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX))
+				continue;
+
+			/*
+			 * Check that an ild follows that (with 0 or more
+			 * nops between them).
+			 */
+			ild = this_op(tax->next);
+			if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD ||
+			    BPF_MODE(ild->s.code) != BPF_IND)
+				continue;
+			/*
+			 * We want to turn this sequence:
+			 *
+			 * (004) ldi     #0x2		{s}
+			 * (005) ldxms   [14]		{next}  -- optional
+			 * (006) addx			{add}
+			 * (007) tax			{tax}
+			 * (008) ild     [x+0]		{ild}
+			 *
+			 * into this sequence:
+			 *
+			 * (004) nop
+			 * (005) ldxms   [14]
+			 * (006) nop
+			 * (007) nop
+			 * (008) ild     [x+2]
+			 *
+			 * XXX We need to check that X is not
+			 * subsequently used, because we want to change
+			 * what'll be in it after this sequence.
+			 *
+			 * We know we can eliminate the accumulator
+			 * modifications earlier in the sequence since
+			 * it is defined by the last stmt of this sequence
+			 * (i.e., the last statement of the sequence loads
+			 * a value into the accumulator, so we can eliminate
+			 * earlier operations on the accumulator).
+			 */
+			ild->s.k += s->s.k;
+			s->s.code = NOP;
+			add->s.code = NOP;
+			tax->s.code = NOP;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+	}
+	/*
+	 * If the comparison at the end of a block is an equality
+	 * comparison against a constant, and nobody uses the value
+	 * we leave in the A register at the end of a block, and
+	 * the operation preceding the comparison is an arithmetic
+	 * operation, we can sometime optimize it away.
+	 */
+	if (b->s.code == (BPF_JMP|BPF_JEQ|BPF_K) &&
+	    !ATOMELEM(b->out_use, A_ATOM)) {
+		/*
+		 * We can optimize away certain subtractions of the
+		 * X register.
+		 */
+		if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) {
+			val = b->val[X_ATOM];
+			if (opt_state->vmap[val].is_const) {
+				/*
+				 * If we have a subtract to do a comparison,
+				 * and the X register is a known constant,
+				 * we can merge this value into the
+				 * comparison:
+				 *
+				 * sub x  ->	nop
+				 * jeq #y	jeq #(x+y)
+				 */
+				b->s.k += opt_state->vmap[val].const_val;
+				last->s.code = NOP;
+				/*
+				 * XXX - optimizer loop detection.
+				 */
+				opt_state->non_branch_movement_performed = 1;
+				opt_state->done = 0;
+			} else if (b->s.k == 0) {
+				/*
+				 * If the X register isn't a constant,
+				 * and the comparison in the test is
+				 * against 0, we can compare with the
+				 * X register, instead:
+				 *
+				 * sub x  ->	nop
+				 * jeq #0	jeq x
+				 */
+				last->s.code = NOP;
+				b->s.code = BPF_JMP|BPF_JEQ|BPF_X;
+				/*
+				 * XXX - optimizer loop detection.
+				 */
+				opt_state->non_branch_movement_performed = 1;
+				opt_state->done = 0;
+			}
+		}
+		/*
+		 * Likewise, a constant subtract can be simplified:
+		 *
+		 * sub #x ->	nop
+		 * jeq #y ->	jeq #(x+y)
+		 */
+		else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) {
+			last->s.code = NOP;
+			b->s.k += last->s.k;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+		/*
+		 * And, similarly, a constant AND can be simplified
+		 * if we're testing against 0, i.e.:
+		 *
+		 * and #k	nop
+		 * jeq #0  ->	jset #k
+		 */
+		else if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) &&
+		    b->s.k == 0) {
+			b->s.k = last->s.k;
+			b->s.code = BPF_JMP|BPF_K|BPF_JSET;
+			last->s.code = NOP;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+			opt_not(b);
+		}
+	}
+	/*
+	 * jset #0        ->   never
+	 * jset #ffffffff ->   always
+	 */
+	if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) {
+		if (b->s.k == 0)
+			JT(b) = JF(b);
+		if (b->s.k == 0xffffffffU)
+			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 (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) {
+		bpf_u_int32 v = opt_state->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.
+	 */
+	val = b->val[A_ATOM];
+	if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
+		bpf_u_int32 v = opt_state->vmap[val].const_val;
+		switch (BPF_OP(b->s.code)) {
+
+		case BPF_JEQ:
+			v = v == b->s.k;
+			break;
+
+		case BPF_JGT:
+			v = v > b->s.k;
+			break;
+
+		case BPF_JGE:
+			v = v >= b->s.k;
+			break;
+
+		case BPF_JSET:
+			v &= b->s.k;
+			break;
+
+		default:
+			abort();
+		}
+		if (JF(b) != JT(b)) {
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+		if (v)
+			JF(b) = JT(b);
+		else
+			JT(b) = JF(b);
+	}
+}
+
+/*
+ * Compute the symbolic value of expression of 's', and update
+ * anything it defines in the value table 'val'.  If 'alter' is true,
+ * do various optimizations.  This code would be cleaner if symbolic
+ * evaluation and code transformations weren't folded together.
+ */
+static void
+opt_stmt(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 val[], int alter)
+{
+	int op;
+	bpf_u_int32 v;
+
+	switch (s->code) {
+
+	case BPF_LD|BPF_ABS|BPF_W:
+	case BPF_LD|BPF_ABS|BPF_H:
+	case BPF_LD|BPF_ABS|BPF_B:
+		v = F(opt_state, s->code, s->k, 0L);
+		vstore(s, &val[A_ATOM], v, alter);
+		break;
+
+	case BPF_LD|BPF_IND|BPF_W:
+	case BPF_LD|BPF_IND|BPF_H:
+	case BPF_LD|BPF_IND|BPF_B:
+		v = val[X_ATOM];
+		if (alter && opt_state->vmap[v].is_const) {
+			s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
+			s->k += opt_state->vmap[v].const_val;
+			v = F(opt_state, s->code, s->k, 0L);
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+		else
+			v = F(opt_state, s->code, s->k, v);
+		vstore(s, &val[A_ATOM], v, alter);
+		break;
+
+	case BPF_LD|BPF_LEN:
+		v = F(opt_state, s->code, 0L, 0L);
+		vstore(s, &val[A_ATOM], v, alter);
+		break;
+
+	case BPF_LD|BPF_IMM:
+		v = K(s->k);
+		vstore(s, &val[A_ATOM], v, alter);
+		break;
+
+	case BPF_LDX|BPF_IMM:
+		v = K(s->k);
+		vstore(s, &val[X_ATOM], v, alter);
+		break;
+
+	case BPF_LDX|BPF_MSH|BPF_B:
+		v = F(opt_state, s->code, s->k, 0L);
+		vstore(s, &val[X_ATOM], v, alter);
+		break;
+
+	case BPF_ALU|BPF_NEG:
+		if (alter && opt_state->vmap[val[A_ATOM]].is_const) {
+			s->code = BPF_LD|BPF_IMM;
+			/*
+			 * Do this negation as unsigned arithmetic; that's
+			 * what modern BPF engines do, and it guarantees
+			 * that all possible values can be negated.  (Yeah,
+			 * negating 0x80000000, the minimum signed 32-bit
+			 * two's-complement value, results in 0x80000000,
+			 * so it's still negative, but we *should* be doing
+			 * all unsigned arithmetic here, to match what
+			 * modern BPF engines do.)
+			 *
+			 * Express it as 0U - (unsigned value) so that we
+			 * don't get compiler warnings about negating an
+			 * unsigned value and don't get UBSan warnings
+			 * about the result of negating 0x80000000 being
+			 * undefined.
+			 */
+			s->k = 0U - opt_state->vmap[val[A_ATOM]].const_val;
+			val[A_ATOM] = K(s->k);
+		}
+		else
+			val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], 0L);
+		break;
+
+	case BPF_ALU|BPF_ADD|BPF_K:
+	case BPF_ALU|BPF_SUB|BPF_K:
+	case BPF_ALU|BPF_MUL|BPF_K:
+	case BPF_ALU|BPF_DIV|BPF_K:
+	case BPF_ALU|BPF_MOD|BPF_K:
+	case BPF_ALU|BPF_AND|BPF_K:
+	case BPF_ALU|BPF_OR|BPF_K:
+	case BPF_ALU|BPF_XOR|BPF_K:
+	case BPF_ALU|BPF_LSH|BPF_K:
+	case BPF_ALU|BPF_RSH|BPF_K:
+		op = BPF_OP(s->code);
+		if (alter) {
+			if (s->k == 0) {
+				/*
+				 * Optimize operations where the constant
+				 * is zero.
+				 *
+				 * Don't optimize away "sub #0"
+				 * as it may be needed later to
+				 * fixup the generated math code.
+				 *
+				 * Fail if we're dividing by zero or taking
+				 * a modulus by zero.
+				 */
+				if (op == BPF_ADD ||
+				    op == BPF_LSH || op == BPF_RSH ||
+				    op == BPF_OR || op == BPF_XOR) {
+					s->code = NOP;
+					break;
+				}
+				if (op == BPF_MUL || op == BPF_AND) {
+					s->code = BPF_LD|BPF_IMM;
+					val[A_ATOM] = K(s->k);
+					break;
+				}
+				if (op == BPF_DIV)
+					opt_error(opt_state,
+					    "division by zero");
+				if (op == BPF_MOD)
+					opt_error(opt_state,
+					    "modulus by zero");
+			}
+			if (opt_state->vmap[val[A_ATOM]].is_const) {
+				fold_op(opt_state, s, val[A_ATOM], K(s->k));
+				val[A_ATOM] = K(s->k);
+				break;
+			}
+		}
+		val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], K(s->k));
+		break;
+
+	case BPF_ALU|BPF_ADD|BPF_X:
+	case BPF_ALU|BPF_SUB|BPF_X:
+	case BPF_ALU|BPF_MUL|BPF_X:
+	case BPF_ALU|BPF_DIV|BPF_X:
+	case BPF_ALU|BPF_MOD|BPF_X:
+	case BPF_ALU|BPF_AND|BPF_X:
+	case BPF_ALU|BPF_OR|BPF_X:
+	case BPF_ALU|BPF_XOR|BPF_X:
+	case BPF_ALU|BPF_LSH|BPF_X:
+	case BPF_ALU|BPF_RSH|BPF_X:
+		op = BPF_OP(s->code);
+		if (alter && opt_state->vmap[val[X_ATOM]].is_const) {
+			if (opt_state->vmap[val[A_ATOM]].is_const) {
+				fold_op(opt_state, s, val[A_ATOM], val[X_ATOM]);
+				val[A_ATOM] = K(s->k);
+			}
+			else {
+				s->code = BPF_ALU|BPF_K|op;
+				s->k = opt_state->vmap[val[X_ATOM]].const_val;
+				if ((op == BPF_LSH || op == BPF_RSH) &&
+				    s->k > 31)
+					opt_error(opt_state,
+					    "shift by more than 31 bits");
+				/*
+				 * XXX - optimizer loop detection.
+				 */
+				opt_state->non_branch_movement_performed = 1;
+				opt_state->done = 0;
+				val[A_ATOM] =
+					F(opt_state, s->code, val[A_ATOM], K(s->k));
+			}
+			break;
+		}
+		/*
+		 * Check if we're doing something to an accumulator
+		 * that is 0, and simplify.  This may not seem like
+		 * much of a simplification but it could open up further
+		 * optimizations.
+		 * XXX We could also check for mul by 1, etc.
+		 */
+		if (alter && opt_state->vmap[val[A_ATOM]].is_const
+		    && opt_state->vmap[val[A_ATOM]].const_val == 0) {
+			if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) {
+				s->code = BPF_MISC|BPF_TXA;
+				vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+				break;
+			}
+			else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD ||
+				 op == BPF_AND || op == BPF_LSH || op == BPF_RSH) {
+				s->code = BPF_LD|BPF_IMM;
+				s->k = 0;
+				vstore(s, &val[A_ATOM], K(s->k), alter);
+				break;
+			}
+			else if (op == BPF_NEG) {
+				s->code = NOP;
+				break;
+			}
+		}
+		val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], val[X_ATOM]);
+		break;
+
+	case BPF_MISC|BPF_TXA:
+		vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+		break;
+
+	case BPF_LD|BPF_MEM:
+		v = val[s->k];
+		if (alter && opt_state->vmap[v].is_const) {
+			s->code = BPF_LD|BPF_IMM;
+			s->k = opt_state->vmap[v].const_val;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+		vstore(s, &val[A_ATOM], v, alter);
+		break;
+
+	case BPF_MISC|BPF_TAX:
+		vstore(s, &val[X_ATOM], val[A_ATOM], alter);
+		break;
+
+	case BPF_LDX|BPF_MEM:
+		v = val[s->k];
+		if (alter && opt_state->vmap[v].is_const) {
+			s->code = BPF_LDX|BPF_IMM;
+			s->k = opt_state->vmap[v].const_val;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+		vstore(s, &val[X_ATOM], v, alter);
+		break;
+
+	case BPF_ST:
+		vstore(s, &val[s->k], val[A_ATOM], alter);
+		break;
+
+	case BPF_STX:
+		vstore(s, &val[s->k], val[X_ATOM], alter);
+		break;
+	}
+}
+
+static void
+deadstmt(opt_state_t *opt_state, register struct stmt *s, register struct stmt *last[])
+{
+	register int atom;
+
+	atom = atomuse(s);
+	if (atom >= 0) {
+		if (atom == AX_ATOM) {
+			last[X_ATOM] = 0;
+			last[A_ATOM] = 0;
+		}
+		else
+			last[atom] = 0;
+	}
+	atom = atomdef(s);
+	if (atom >= 0) {
+		if (last[atom]) {
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+			last[atom]->code = NOP;
+		}
+		last[atom] = s;
+	}
+}
+
+static void
+opt_deadstores(opt_state_t *opt_state, register struct block *b)
+{
+	register struct slist *s;
+	register int atom;
+	struct stmt *last[N_ATOMS];
+
+	memset((char *)last, 0, sizeof last);
+
+	for (s = b->stmts; s != 0; s = s->next)
+		deadstmt(opt_state, &s->s, last);
+	deadstmt(opt_state, &b->s, last);
+
+	for (atom = 0; atom < N_ATOMS; ++atom)
+		if (last[atom] && !ATOMELEM(b->out_use, atom)) {
+			last[atom]->code = NOP;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+}
+
+static void
+opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts)
+{
+	struct slist *s;
+	struct edge *p;
+	int i;
+	bpf_u_int32 aval, xval;
+
+#if 0
+	for (s = b->stmts; s && s->next; s = s->next)
+		if (BPF_CLASS(s->s.code) == BPF_JMP) {
+			do_stmts = 0;
+			break;
+		}
+#endif
+
+	/*
+	 * Initialize the atom values.
+	 */
+	p = b->in_edges;
+	if (p == 0) {
+		/*
+		 * We have no predecessors, so everything is undefined
+		 * upon entry to this block.
+		 */
+		memset((char *)b->val, 0, sizeof(b->val));
+	} else {
+		/*
+		 * Inherit values from our predecessors.
+		 *
+		 * First, get the values from the predecessor along the
+		 * first edge leading to this node.
+		 */
+		memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val));
+		/*
+		 * Now look at all the other nodes leading to this node.
+		 * If, for the predecessor along that edge, a register
+		 * has a different value from the one we have (i.e.,
+		 * control paths are merging, and the merging paths
+		 * assign different values to that register), give the
+		 * register the undefined value of 0.
+		 */
+		while ((p = p->next) != NULL) {
+			for (i = 0; i < N_ATOMS; ++i)
+				if (b->val[i] != p->pred->val[i])
+					b->val[i] = 0;
+		}
+	}
+	aval = b->val[A_ATOM];
+	xval = b->val[X_ATOM];
+	for (s = b->stmts; s; s = s->next)
+		opt_stmt(opt_state, &s->s, b->val, do_stmts);
+
+	/*
+	 * This is a special case: if we don't use anything from this
+	 * block, and we load the accumulator or index register with a
+	 * value that is already there, or if this block is a return,
+	 * eliminate all the statements.
+	 *
+	 * XXX - what if it does a store?  Presumably that falls under
+	 * the heading of "if we don't use anything from this block",
+	 * i.e., if we use any memory location set to a different
+	 * value by this block, then we use something from this block.
+	 *
+	 * XXX - why does it matter whether we use anything from this
+	 * block?  If the accumulator or index register doesn't change
+	 * its value, isn't that OK even if we use that value?
+	 *
+	 * XXX - if we load the accumulator with a different value,
+	 * and the block ends with a conditional branch, we obviously
+	 * can't eliminate it, as the branch depends on that value.
+	 * For the index register, the conditional branch only depends
+	 * on the index register value if the test is against the index
+	 * register value rather than a constant; if nothing uses the
+	 * value we put into the index register, and we're not testing
+	 * against the index register's value, and there aren't any
+	 * other problems that would keep us from eliminating this
+	 * block, can we eliminate it?
+	 */
+	if (do_stmts &&
+	    ((b->out_use == 0 &&
+	      aval != VAL_UNKNOWN && b->val[A_ATOM] == aval &&
+	      xval != VAL_UNKNOWN && b->val[X_ATOM] == xval) ||
+	     BPF_CLASS(b->s.code) == BPF_RET)) {
+		if (b->stmts != 0) {
+			b->stmts = 0;
+			/*
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+		}
+	} else {
+		opt_peep(opt_state, b);
+		opt_deadstores(opt_state, b);
+	}
+	/*
+	 * Set up values for branch optimizer.
+	 */
+	if (BPF_SRC(b->s.code) == BPF_K)
+		b->oval = K(b->s.k);
+	else
+		b->oval = b->val[X_ATOM];
+	b->et.code = b->s.code;
+	b->ef.code = -b->s.code;
+}
+
+/*
+ * Return true if any register that is used on exit from 'succ', has
+ * an exit value that is different from the corresponding exit value
+ * from 'b'.
+ */
+static int
+use_conflict(struct block *b, struct block *succ)
+{
+	int atom;
+	atomset use = succ->out_use;
+
+	if (use == 0)
+		return 0;
+
+	for (atom = 0; atom < N_ATOMS; ++atom)
+		if (ATOMELEM(use, atom))
+			if (b->val[atom] != succ->val[atom])
+				return 1;
+	return 0;
+}
+
+/*
+ * Given a block that is the successor of an edge, and an edge that
+ * dominates that edge, return either a pointer to a child of that
+ * block (a block to which that block jumps) if that block is a
+ * candidate to replace the successor of the latter edge or NULL
+ * if neither of the children of the first block are candidates.
+ */
+static struct block *
+fold_edge(struct block *child, struct edge *ep)
+{
+	int sense;
+	bpf_u_int32 aval0, aval1, oval0, oval1;
+	int code = ep->code;
+
+	if (code < 0) {
+		/*
+		 * This edge is a "branch if false" edge.
+		 */
+		code = -code;
+		sense = 0;
+	} else {
+		/*
+		 * This edge is a "branch if true" edge.
+		 */
+		sense = 1;
+	}
+
+	/*
+	 * If the opcode for the branch at the end of the block we
+	 * were handed isn't the same as the opcode for the branch
+	 * to which the edge we were handed corresponds, the tests
+	 * for those branches aren't testing the same conditions,
+	 * so the blocks to which the first block branches aren't
+	 * candidates to replace the successor of the edge.
+	 */
+	if (child->s.code != code)
+		return 0;
+
+	aval0 = child->val[A_ATOM];
+	oval0 = child->oval;
+	aval1 = ep->pred->val[A_ATOM];
+	oval1 = ep->pred->oval;
+
+	/*
+	 * If the A register value on exit from the successor block
+	 * isn't the same as the A register value on exit from the
+	 * predecessor of the edge, the blocks to which the first
+	 * block branches aren't candidates to replace the successor
+	 * of the edge.
+	 */
+	if (aval0 != aval1)
+		return 0;
+
+	if (oval0 == oval1)
+		/*
+		 * The operands of the branch instructions are
+		 * identical, so the branches are testing the
+		 * same condition, and the result is true if a true
+		 * branch was taken to get here, otherwise false.
+		 */
+		return sense ? JT(child) : JF(child);
+
+	if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
+		/*
+		 * At this point, we only know the comparison if we
+		 * came down the true branch, and it was an equality
+		 * comparison with a constant.
+		 *
+		 * I.e., if we came down the true branch, and the branch
+		 * was an equality comparison with a constant, we know the
+		 * accumulator contains that constant.  If we came down
+		 * the false branch, or the comparison wasn't with a
+		 * constant, we don't know what was in the accumulator.
+		 *
+		 * We rely on the fact that distinct constants have distinct
+		 * value numbers.
+		 */
+		return JF(child);
+
+	return 0;
+}
+
+/*
+ * If we can make this edge go directly to a child of the edge's current
+ * successor, do so.
+ */
+static void
+opt_j(opt_state_t *opt_state, struct edge *ep)
+{
+	register u_int i, k;
+	register struct block *target;
+
+	/*
+	 * Does this edge go to a block where, if the test
+	 * at the end of it succeeds, it goes to a block
+	 * that's a leaf node of the DAG, i.e. a return
+	 * statement?
+	 * If so, there's nothing to optimize.
+	 */
+	if (JT(ep->succ) == 0)
+		return;
+
+	/*
+	 * Does this edge go to a block that goes, in turn, to
+	 * the same block regardless of whether the test at the
+	 * end succeeds or fails?
+	 */
+	if (JT(ep->succ) == JF(ep->succ)) {
+		/*
+		 * Common branch targets can be eliminated, provided
+		 * there is no data dependency.
+		 *
+		 * Check whether any register used on exit from the
+		 * block to which the successor of this edge goes
+		 * has a value at that point that's different from
+		 * the value it has on exit from the predecessor of
+		 * this edge.  If not, the predecessor of this edge
+		 * can just go to the block to which the successor
+		 * of this edge goes, bypassing the successor of this
+		 * edge, as the successor of this edge isn't doing
+		 * any calculations whose results are different
+		 * from what the blocks before it did and isn't
+		 * doing any tests the results of which matter.
+		 */
+		if (!use_conflict(ep->pred, JT(ep->succ))) {
+			/*
+			 * No, there isn't.
+			 * Make this edge go to the block to
+			 * which the successor of that edge
+			 * goes.
+			 *
+			 * XXX - optimizer loop detection.
+			 */
+			opt_state->non_branch_movement_performed = 1;
+			opt_state->done = 0;
+			ep->succ = JT(ep->succ);
+		}
+	}
+	/*
+	 * For each edge dominator that matches the successor of this
+	 * edge, promote the edge successor to the its grandchild.
+	 *
+	 * XXX We violate the set abstraction here in favor a reasonably
+	 * efficient loop.
+	 */
+ top:
+	for (i = 0; i < opt_state->edgewords; ++i) {
+		/* i'th word in the bitset of dominators */
+		register bpf_u_int32 x = ep->edom[i];
+
+		while (x != 0) {
+			/* Find the next dominator in that word and mark it as found */
+			k = lowest_set_bit(x);
+			x &=~ ((bpf_u_int32)1 << k);
+			k += i * BITS_PER_WORD;
+
+			target = fold_edge(ep->succ, opt_state->edges[k]);
+			/*
+			 * We have a candidate to replace the successor
+			 * of ep.
+			 *
+			 * Check that there is no data dependency between
+			 * nodes that will be violated if we move the edge;
+			 * i.e., if any register used on exit from the
+			 * candidate has a value at that point different
+			 * from the value it has when we exit the
+			 * predecessor of that edge, there's a data
+			 * dependency that will be violated.
+			 */
+			if (target != 0 && !use_conflict(ep->pred, target)) {
+				/*
+				 * It's safe to replace the successor of
+				 * ep; do so, and note that we've made
+				 * at least one change.
+				 *
+				 * XXX - this is one of the operations that
+				 * happens when the optimizer gets into
+				 * one of those infinite loops.
+				 */
+				opt_state->done = 0;
+				ep->succ = target;
+				if (JT(target) != 0)
+					/*
+					 * Start over unless we hit a leaf.
+					 */
+					goto top;
+				return;
+			}
+		}
+	}
+}
+
+/*
+ * XXX - is this, and and_pullup(), what's described in section 6.1.2
+ * "Predicate Assertion Propagation" in the BPF+ paper?
+ *
+ * Note that this looks at block dominators, not edge dominators.
+ * Don't think so.
+ *
+ * "A or B" compiles into
+ *
+ *          A
+ *       t / \ f
+ *        /   B
+ *       / t / \ f
+ *      \   /
+ *       \ /
+ *        X
+ *
+ *
+ */
+static void
+or_pullup(opt_state_t *opt_state, struct block *b)
+{
+	bpf_u_int32 val;
+	int at_top;
+	struct block *pull;
+	struct block **diffp, **samep;
+	struct edge *ep;
+
+	ep = b->in_edges;
+	if (ep == 0)
+		return;
+
+	/*
+	 * Make sure each predecessor loads the same value.
+	 * XXX why?
+	 */
+	val = ep->pred->val[A_ATOM];
+	for (ep = ep->next; ep != 0; ep = ep->next)
+		if (val != ep->pred->val[A_ATOM])
+			return;
+
+	/*
+	 * For the first edge in the list of edges coming into this block,
+	 * see whether the predecessor of that edge comes here via a true
+	 * branch or a false branch.
+	 */
+	if (JT(b->in_edges->pred) == b)
+		diffp = &JT(b->in_edges->pred);	/* jt */
+	else
+		diffp = &JF(b->in_edges->pred);	/* jf */
+
+	/*
+	 * diffp is a pointer to a pointer to the block.
+	 *
+	 * Go down the false chain looking as far as you can,
+	 * making sure that each jump-compare is doing the
+	 * same as the original block.
+	 *
+	 * If you reach the bottom before you reach a
+	 * different jump-compare, just exit.  There's nothing
+	 * to do here.  XXX - no, this version is checking for
+	 * the value leaving the block; that's from the BPF+
+	 * pullup routine.
+	 */
+	at_top = 1;
+	for (;;) {
+		/*
+		 * Done if that's not going anywhere XXX
+		 */
+		if (*diffp == 0)
+			return;
+
+		/*
+		 * Done if that predecessor blah blah blah isn't
+		 * going the same place we're going XXX
+		 *
+		 * Does the true edge of this block point to the same
+		 * location as the true edge of b?
+		 */
+		if (JT(*diffp) != JT(b))
+			return;
+
+		/*
+		 * Done if this node isn't a dominator of that
+		 * node blah blah blah XXX
+		 *
+		 * Does b dominate diffp?
+		 */
+		if (!SET_MEMBER((*diffp)->dom, b->id))
+			return;
+
+		/*
+		 * Break out of the loop if that node's value of A
+		 * isn't the value of A above XXX
+		 */
+		if ((*diffp)->val[A_ATOM] != val)
+			break;
+
+		/*
+		 * Get the JF for that node XXX
+		 * Go down the false path.
+		 */
+		diffp = &JF(*diffp);
+		at_top = 0;
+	}
+
+	/*
+	 * Now that we've found a different jump-compare in a chain
+	 * below b, search further down until we find another
+	 * jump-compare that looks at the original value.  This
+	 * jump-compare should get pulled up.  XXX again we're
+	 * comparing values not jump-compares.
+	 */
+	samep = &JF(*diffp);
+	for (;;) {
+		/*
+		 * Done if that's not going anywhere XXX
+		 */
+		if (*samep == 0)
+			return;
+
+		/*
+		 * Done if that predecessor blah blah blah isn't
+		 * going the same place we're going XXX
+		 */
+		if (JT(*samep) != JT(b))
+			return;
+
+		/*
+		 * Done if this node isn't a dominator of that
+		 * node blah blah blah XXX
+		 *
+		 * Does b dominate samep?
+		 */
+		if (!SET_MEMBER((*samep)->dom, b->id))
+			return;
+
+		/*
+		 * Break out of the loop if that node's value of A
+		 * is the value of A above XXX
+		 */
+		if ((*samep)->val[A_ATOM] == val)
+			break;
+
+		/* XXX Need to check that there are no data dependencies
+		   between dp0 and dp1.  Currently, the code generator
+		   will not produce such dependencies. */
+		samep = &JF(*samep);
+	}
+#ifdef notdef
+	/* XXX This doesn't cover everything. */
+	for (i = 0; i < N_ATOMS; ++i)
+		if ((*samep)->val[i] != pred->val[i])
+			return;
+#endif
+	/* Pull up the node. */
+	pull = *samep;
+	*samep = JF(pull);
+	JF(pull) = *diffp;
+
+	/*
+	 * At the top of the chain, each predecessor needs to point at the
+	 * pulled up node.  Inside the chain, there is only one predecessor
+	 * to worry about.
+	 */
+	if (at_top) {
+		for (ep = b->in_edges; ep != 0; ep = ep->next) {
+			if (JT(ep->pred) == b)
+				JT(ep->pred) = pull;
+			else
+				JF(ep->pred) = pull;
+		}
+	}
+	else
+		*diffp = pull;
+
+	/*
+	 * XXX - this is one of the operations that happens when the
+	 * optimizer gets into one of those infinite loops.
+	 */
+	opt_state->done = 0;
+}
+
+static void
+and_pullup(opt_state_t *opt_state, struct block *b)
+{
+	bpf_u_int32 val;
+	int at_top;
+	struct block *pull;
+	struct block **diffp, **samep;
+	struct edge *ep;
+
+	ep = b->in_edges;
+	if (ep == 0)
+		return;
+
+	/*
+	 * Make sure each predecessor loads the same value.
+	 */
+	val = ep->pred->val[A_ATOM];
+	for (ep = ep->next; ep != 0; ep = ep->next)
+		if (val != ep->pred->val[A_ATOM])
+			return;
+
+	if (JT(b->in_edges->pred) == b)
+		diffp = &JT(b->in_edges->pred);
+	else
+		diffp = &JF(b->in_edges->pred);
+
+	at_top = 1;
+	for (;;) {
+		if (*diffp == 0)
+			return;
+
+		if (JF(*diffp) != JF(b))
+			return;
+
+		if (!SET_MEMBER((*diffp)->dom, b->id))
+			return;
+
+		if ((*diffp)->val[A_ATOM] != val)
+			break;
+
+		diffp = &JT(*diffp);
+		at_top = 0;
+	}
+	samep = &JT(*diffp);
+	for (;;) {
+		if (*samep == 0)
+			return;
+
+		if (JF(*samep) != JF(b))
+			return;
+
+		if (!SET_MEMBER((*samep)->dom, b->id))
+			return;
+
+		if ((*samep)->val[A_ATOM] == val)
+			break;
+
+		/* XXX Need to check that there are no data dependencies
+		   between diffp and samep.  Currently, the code generator
+		   will not produce such dependencies. */
+		samep = &JT(*samep);
+	}
+#ifdef notdef
+	/* XXX This doesn't cover everything. */
+	for (i = 0; i < N_ATOMS; ++i)
+		if ((*samep)->val[i] != pred->val[i])
+			return;
+#endif
+	/* Pull up the node. */
+	pull = *samep;
+	*samep = JT(pull);
+	JT(pull) = *diffp;
+
+	/*
+	 * At the top of the chain, each predecessor needs to point at the
+	 * pulled up node.  Inside the chain, there is only one predecessor
+	 * to worry about.
+	 */
+	if (at_top) {
+		for (ep = b->in_edges; ep != 0; ep = ep->next) {
+			if (JT(ep->pred) == b)
+				JT(ep->pred) = pull;
+			else
+				JF(ep->pred) = pull;
+		}
+	}
+	else
+		*diffp = pull;
+
+	/*
+	 * XXX - this is one of the operations that happens when the
+	 * optimizer gets into one of those infinite loops.
+	 */
+	opt_state->done = 0;
+}
+
+static void
+opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts)
+{
+	int i, maxlevel;
+	struct block *p;
+
+	init_val(opt_state);
+	maxlevel = ic->root->level;
+
+	find_inedges(opt_state, ic->root);
+	for (i = maxlevel; i >= 0; --i)
+		for (p = opt_state->levels[i]; p; p = p->link)
+			opt_blk(opt_state, p, do_stmts);
+
+	if (do_stmts)
+		/*
+		 * No point trying to move branches; it can't possibly
+		 * make a difference at this point.
+		 *
+		 * XXX - this might be after we detect a loop where
+		 * we were just looping infinitely moving branches
+		 * in such a fashion that we went through two or more
+		 * versions of the machine code, eventually returning
+		 * to the first version.  (We're really not doing a
+		 * full loop detection, we're just testing for two
+		 * passes in a row where where we do nothing but
+		 * move branches.)
+		 */
+		return;
+
+	/*
+	 * Is this what the BPF+ paper describes in sections 6.1.1,
+	 * 6.1.2, and 6.1.3?
+	 */
+	for (i = 1; i <= maxlevel; ++i) {
+		for (p = opt_state->levels[i]; p; p = p->link) {
+			opt_j(opt_state, &p->et);
+			opt_j(opt_state, &p->ef);
+		}
+	}
+
+	find_inedges(opt_state, ic->root);
+	for (i = 1; i <= maxlevel; ++i) {
+		for (p = opt_state->levels[i]; p; p = p->link) {
+			or_pullup(opt_state, p);
+			and_pullup(opt_state, p);
+		}
+	}
+}
+
+static inline void
+link_inedge(struct edge *parent, struct block *child)
+{
+	parent->next = child->in_edges;
+	child->in_edges = parent;
+}
+
+static void
+find_inedges(opt_state_t *opt_state, struct block *root)
+{
+	u_int i;
+	int level;
+	struct block *b;
+
+	for (i = 0; i < opt_state->n_blocks; ++i)
+		opt_state->blocks[i]->in_edges = 0;
+
+	/*
+	 * Traverse the graph, adding each edge to the predecessor
+	 * list of its successors.  Skip the leaves (i.e. level 0).
+	 */
+	for (level = root->level; level > 0; --level) {
+		for (b = opt_state->levels[level]; b != 0; b = b->link) {
+			link_inedge(&b->et, JT(b));
+			link_inedge(&b->ef, JF(b));
+		}
+	}
+}
+
+static void
+opt_root(struct block **b)
+{
+	struct slist *tmp, *s;
+
+	s = (*b)->stmts;
+	(*b)->stmts = 0;
+	while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
+		*b = JT(*b);
+
+	tmp = (*b)->stmts;
+	if (tmp != 0)
+		sappend(s, tmp);
+	(*b)->stmts = s;
+
+	/*
+	 * If the root node is a return, then there is no
+	 * point executing any statements (since the bpf machine
+	 * has no side effects).
+	 */
+	if (BPF_CLASS((*b)->s.code) == BPF_RET)
+		(*b)->stmts = 0;
+}
+
+static void
+opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts)
+{
+
+#ifdef BDEBUG
+	if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+		printf("opt_loop(root, %d) begin\n", do_stmts);
+		opt_dump(opt_state, ic);
+	}
+#endif
+
+	/*
+	 * XXX - optimizer loop detection.
+	 */
+	int loop_count = 0;
+	for (;;) {
+		opt_state->done = 1;
+		/*
+		 * XXX - optimizer loop detection.
+		 */
+		opt_state->non_branch_movement_performed = 0;
+		find_levels(opt_state, ic);
+		find_dom(opt_state, ic->root);
+		find_closure(opt_state, ic->root);
+		find_ud(opt_state, ic->root);
+		find_edom(opt_state, ic->root);
+		opt_blks(opt_state, ic, do_stmts);
+#ifdef BDEBUG
+		if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+			printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done);
+			opt_dump(opt_state, ic);
+		}
+#endif
+
+		/*
+		 * Was anything done in this optimizer pass?
+		 */
+		if (opt_state->done) {
+			/*
+			 * No, so we've reached a fixed point.
+			 * We're done.
+			 */
+			break;
+		}
+
+		/*
+		 * XXX - was anything done other than branch movement
+		 * in this pass?
+		 */
+		if (opt_state->non_branch_movement_performed) {
+			/*
+			 * Yes.  Clear any loop-detection counter;
+			 * we're making some form of progress (assuming
+			 * we can't get into a cycle doing *other*
+			 * optimizations...).
+			 */
+			loop_count = 0;
+		} else {
+			/*
+			 * No - increment the counter, and quit if
+			 * it's up to 100.
+			 */
+			loop_count++;
+			if (loop_count >= 100) {
+				/*
+				 * We've done nothing but branch movement
+				 * for 100 passes; we're probably
+				 * in a cycle and will never reach a
+				 * fixed point.
+				 *
+				 * XXX - yes, we really need a non-
+				 * heuristic way of detecting a cycle.
+				 */
+				opt_state->done = 1;
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * Optimize the filter code in its dag representation.
+ * Return 0 on success, -1 on error.
+ */
+int
+bpf_optimize(struct icode *ic, char *errbuf)
+{
+	opt_state_t opt_state;
+
+	memset(&opt_state, 0, sizeof(opt_state));
+	opt_state.errbuf = errbuf;
+	opt_state.non_branch_movement_performed = 0;
+	if (setjmp(opt_state.top_ctx)) {
+		opt_cleanup(&opt_state);
+		return -1;
+	}
+	opt_init(&opt_state, ic);
+	opt_loop(&opt_state, ic, 0);
+	opt_loop(&opt_state, ic, 1);
+	intern_blocks(&opt_state, ic);
+#ifdef BDEBUG
+	if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+		printf("after intern_blocks()\n");
+		opt_dump(&opt_state, ic);
+	}
+#endif
+	opt_root(&ic->root);
+#ifdef BDEBUG
+	if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+		printf("after opt_root()\n");
+		opt_dump(&opt_state, ic);
+	}
+#endif
+	opt_cleanup(&opt_state);
+	return 0;
+}
+
+static void
+make_marks(struct icode *ic, struct block *p)
+{
+	if (!isMarked(ic, p)) {
+		Mark(ic, p);
+		if (BPF_CLASS(p->s.code) != BPF_RET) {
+			make_marks(ic, JT(p));
+			make_marks(ic, JF(p));
+		}
+	}
+}
+
+/*
+ * Mark code array such that isMarked(ic->cur_mark, i) is true
+ * only for nodes that are alive.
+ */
+static void
+mark_code(struct icode *ic)
+{
+	ic->cur_mark += 1;
+	make_marks(ic, ic->root);
+}
+
+/*
+ * True iff the two stmt lists load the same value from the packet into
+ * the accumulator.
+ */
+static int
+eq_slist(struct slist *x, struct slist *y)
+{
+	for (;;) {
+		while (x && x->s.code == NOP)
+			x = x->next;
+		while (y && y->s.code == NOP)
+			y = y->next;
+		if (x == 0)
+			return y == 0;
+		if (y == 0)
+			return x == 0;
+		if (x->s.code != y->s.code || x->s.k != y->s.k)
+			return 0;
+		x = x->next;
+		y = y->next;
+	}
+}
+
+static inline int
+eq_blk(struct block *b0, struct block *b1)
+{
+	if (b0->s.code == b1->s.code &&
+	    b0->s.k == b1->s.k &&
+	    b0->et.succ == b1->et.succ &&
+	    b0->ef.succ == b1->ef.succ)
+		return eq_slist(b0->stmts, b1->stmts);
+	return 0;
+}
+
+static void
+intern_blocks(opt_state_t *opt_state, struct icode *ic)
+{
+	struct block *p;
+	u_int i, j;
+	int done1; /* don't shadow global */
+ top:
+	done1 = 1;
+	for (i = 0; i < opt_state->n_blocks; ++i)
+		opt_state->blocks[i]->link = 0;
+
+	mark_code(ic);
+
+	for (i = opt_state->n_blocks - 1; i != 0; ) {
+		--i;
+		if (!isMarked(ic, opt_state->blocks[i]))
+			continue;
+		for (j = i + 1; j < opt_state->n_blocks; ++j) {
+			if (!isMarked(ic, opt_state->blocks[j]))
+				continue;
+			if (eq_blk(opt_state->blocks[i], opt_state->blocks[j])) {
+				opt_state->blocks[i]->link = opt_state->blocks[j]->link ?
+					opt_state->blocks[j]->link : opt_state->blocks[j];
+				break;
+			}
+		}
+	}
+	for (i = 0; i < opt_state->n_blocks; ++i) {
+		p = opt_state->blocks[i];
+		if (JT(p) == 0)
+			continue;
+		if (JT(p)->link) {
+			done1 = 0;
+			JT(p) = JT(p)->link;
+		}
+		if (JF(p)->link) {
+			done1 = 0;
+			JF(p) = JF(p)->link;
+		}
+	}
+	if (!done1)
+		goto top;
+}
+
+static void
+opt_cleanup(opt_state_t *opt_state)
+{
+	free((void *)opt_state->vnode_base);
+	free((void *)opt_state->vmap);
+	free((void *)opt_state->edges);
+	free((void *)opt_state->space);
+	free((void *)opt_state->levels);
+	free((void *)opt_state->blocks);
+}
+
+/*
+ * For optimizer errors.
+ */
+static void PCAP_NORETURN
+opt_error(opt_state_t *opt_state, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (opt_state->errbuf != NULL) {
+		va_start(ap, fmt);
+		(void)vsnprintf(opt_state->errbuf,
+		    PCAP_ERRBUF_SIZE, fmt, ap);
+		va_end(ap);
+	}
+	longjmp(opt_state->top_ctx, 1);
+	/* NOTREACHED */
+}
+
+/*
+ * Return the number of stmts in 's'.
+ */
+static u_int
+slength(struct slist *s)
+{
+	u_int n = 0;
+
+	for (; s; s = s->next)
+		if (s->s.code != NOP)
+			++n;
+	return n;
+}
+
+/*
+ * Return the number of nodes reachable by 'p'.
+ * All nodes should be initially unmarked.
+ */
+static int
+count_blocks(struct icode *ic, struct block *p)
+{
+	if (p == 0 || isMarked(ic, p))
+		return 0;
+	Mark(ic, p);
+	return count_blocks(ic, JT(p)) + count_blocks(ic, JF(p)) + 1;
+}
+
+/*
+ * Do a depth first search on the flow graph, numbering the
+ * the basic blocks, and entering them into the 'blocks' array.`
+ */
+static void
+number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p)
+{
+	u_int n;
+
+	if (p == 0 || isMarked(ic, p))
+		return;
+
+	Mark(ic, p);
+	n = opt_state->n_blocks++;
+	if (opt_state->n_blocks == 0) {
+		/*
+		 * Overflow.
+		 */
+		opt_error(opt_state, "filter is too complex to optimize");
+	}
+	p->id = n;
+	opt_state->blocks[n] = p;
+
+	number_blks_r(opt_state, ic, JT(p));
+	number_blks_r(opt_state, ic, JF(p));
+}
+
+/*
+ * Return the number of stmts in the flowgraph reachable by 'p'.
+ * The nodes should be unmarked before calling.
+ *
+ * Note that "stmts" means "instructions", and that this includes
+ *
+ *	side-effect statements in 'p' (slength(p->stmts));
+ *
+ *	statements in the true branch from 'p' (count_stmts(JT(p)));
+ *
+ *	statements in the false branch from 'p' (count_stmts(JF(p)));
+ *
+ *	the conditional jump itself (1);
+ *
+ *	an extra long jump if the true branch requires it (p->longjt);
+ *
+ *	an extra long jump if the false branch requires it (p->longjf).
+ */
+static u_int
+count_stmts(struct icode *ic, struct block *p)
+{
+	u_int n;
+
+	if (p == 0 || isMarked(ic, p))
+		return 0;
+	Mark(ic, p);
+	n = count_stmts(ic, JT(p)) + count_stmts(ic, JF(p));
+	return slength(p->stmts) + n + 1 + p->longjt + p->longjf;
+}
+
+/*
+ * Allocate memory.  All allocation is done before optimization
+ * is begun.  A linear bound on the size of all data structures is computed
+ * from the total number of blocks and/or statements.
+ */
+static void
+opt_init(opt_state_t *opt_state, struct icode *ic)
+{
+	bpf_u_int32 *p;
+	int i, n, max_stmts;
+	u_int product;
+	size_t block_memsize, edge_memsize;
+
+	/*
+	 * First, count the blocks, so we can malloc an array to map
+	 * block number to block.  Then, put the blocks into the array.
+	 */
+	unMarkAll(ic);
+	n = count_blocks(ic, ic->root);
+	opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks));
+	if (opt_state->blocks == NULL)
+		opt_error(opt_state, "malloc");
+	unMarkAll(ic);
+	opt_state->n_blocks = 0;
+	number_blks_r(opt_state, ic, ic->root);
+
+	/*
+	 * This "should not happen".
+	 */
+	if (opt_state->n_blocks == 0)
+		opt_error(opt_state, "filter has no instructions; please report this as a libpcap issue");
+
+	opt_state->n_edges = 2 * opt_state->n_blocks;
+	if ((opt_state->n_edges / 2) != opt_state->n_blocks) {
+		/*
+		 * Overflow.
+		 */
+		opt_error(opt_state, "filter is too complex to optimize");
+	}
+	opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges));
+	if (opt_state->edges == NULL) {
+		opt_error(opt_state, "malloc");
+	}
+
+	/*
+	 * The number of levels is bounded by the number of nodes.
+	 */
+	opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels));
+	if (opt_state->levels == NULL) {
+		opt_error(opt_state, "malloc");
+	}
+
+	opt_state->edgewords = opt_state->n_edges / BITS_PER_WORD + 1;
+	opt_state->nodewords = opt_state->n_blocks / BITS_PER_WORD + 1;
+
+	/*
+	 * Make sure opt_state->n_blocks * opt_state->nodewords fits
+	 * in a u_int; we use it as a u_int number-of-iterations
+	 * value.
+	 */
+	product = opt_state->n_blocks * opt_state->nodewords;
+	if ((product / opt_state->n_blocks) != opt_state->nodewords) {
+		/*
+		 * XXX - just punt and don't try to optimize?
+		 * In practice, this is unlikely to happen with
+		 * a normal filter.
+		 */
+		opt_error(opt_state, "filter is too complex to optimize");
+	}
+
+	/*
+	 * Make sure the total memory required for that doesn't
+	 * overflow.
+	 */
+	block_memsize = (size_t)2 * product * sizeof(*opt_state->space);
+	if ((block_memsize / product) != 2 * sizeof(*opt_state->space)) {
+		opt_error(opt_state, "filter is too complex to optimize");
+	}
+
+	/*
+	 * Make sure opt_state->n_edges * opt_state->edgewords fits
+	 * in a u_int; we use it as a u_int number-of-iterations
+	 * value.
+	 */
+	product = opt_state->n_edges * opt_state->edgewords;
+	if ((product / opt_state->n_edges) != opt_state->edgewords) {
+		opt_error(opt_state, "filter is too complex to optimize");
+	}
+
+	/*
+	 * Make sure the total memory required for that doesn't
+	 * overflow.
+	 */
+	edge_memsize = (size_t)product * sizeof(*opt_state->space);
+	if (edge_memsize / product != sizeof(*opt_state->space)) {
+		opt_error(opt_state, "filter is too complex to optimize");
+	}
+
+	/*
+	 * Make sure the total memory required for both of them dosn't
+	 * overflow.
+	 */
+	if (block_memsize > SIZE_MAX - edge_memsize) {
+		opt_error(opt_state, "filter is too complex to optimize");
+	}
+
+	/* XXX */
+	opt_state->space = (bpf_u_int32 *)malloc(block_memsize + edge_memsize);
+	if (opt_state->space == NULL) {
+		opt_error(opt_state, "malloc");
+	}
+	p = opt_state->space;
+	opt_state->all_dom_sets = p;
+	for (i = 0; i < n; ++i) {
+		opt_state->blocks[i]->dom = p;
+		p += opt_state->nodewords;
+	}
+	opt_state->all_closure_sets = p;
+	for (i = 0; i < n; ++i) {
+		opt_state->blocks[i]->closure = p;
+		p += opt_state->nodewords;
+	}
+	opt_state->all_edge_sets = p;
+	for (i = 0; i < n; ++i) {
+		register struct block *b = opt_state->blocks[i];
+
+		b->et.edom = p;
+		p += opt_state->edgewords;
+		b->ef.edom = p;
+		p += opt_state->edgewords;
+		b->et.id = i;
+		opt_state->edges[i] = &b->et;
+		b->ef.id = opt_state->n_blocks + i;
+		opt_state->edges[opt_state->n_blocks + i] = &b->ef;
+		b->et.pred = b;
+		b->ef.pred = b;
+	}
+	max_stmts = 0;
+	for (i = 0; i < n; ++i)
+		max_stmts += slength(opt_state->blocks[i]->stmts) + 1;
+	/*
+	 * We allocate at most 3 value numbers per statement,
+	 * so this is an upper bound on the number of valnodes
+	 * we'll need.
+	 */
+	opt_state->maxval = 3 * max_stmts;
+	opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap));
+	if (opt_state->vmap == NULL) {
+		opt_error(opt_state, "malloc");
+	}
+	opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base));
+	if (opt_state->vnode_base == NULL) {
+		opt_error(opt_state, "malloc");
+	}
+}
+
+/*
+ * This is only used when supporting optimizer debugging.  It is
+ * global state, so do *not* do more than one compile in parallel
+ * and expect it to provide meaningful information.
+ */
+#ifdef BDEBUG
+int bids[NBIDS];
+#endif
+
+static void PCAP_NORETURN conv_error(conv_state_t *, const char *, ...)
+    PCAP_PRINTFLIKE(2, 3);
+
+/*
+ * Returns true if successful.  Returns false if a branch has
+ * an offset that is too large.  If so, we have marked that
+ * branch so that on a subsequent iteration, it will be treated
+ * properly.
+ */
+static int
+convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p)
+{
+	struct bpf_insn *dst;
+	struct slist *src;
+	u_int slen;
+	u_int off;
+	struct slist **offset = NULL;
+
+	if (p == 0 || isMarked(ic, p))
+		return (1);
+	Mark(ic, p);
+
+	if (convert_code_r(conv_state, ic, JF(p)) == 0)
+		return (0);
+	if (convert_code_r(conv_state, ic, JT(p)) == 0)
+		return (0);
+
+	slen = slength(p->stmts);
+	dst = conv_state->ftail -= (slen + 1 + p->longjt + p->longjf);
+		/* inflate length by any extra jumps */
+
+	p->offset = (int)(dst - conv_state->fstart);
+
+	/* generate offset[] for convenience  */
+	if (slen) {
+		offset = (struct slist **)calloc(slen, sizeof(struct slist *));
+		if (!offset) {
+			conv_error(conv_state, "not enough core");
+			/*NOTREACHED*/
+		}
+	}
+	src = p->stmts;
+	for (off = 0; off < slen && src; off++) {
+#if 0
+		printf("off=%d src=%x\n", off, src);
+#endif
+		offset[off] = src;
+		src = src->next;
+	}
+
+	off = 0;
+	for (src = p->stmts; src; src = src->next) {
+		if (src->s.code == NOP)
+			continue;
+		dst->code = (u_short)src->s.code;
+		dst->k = src->s.k;
+
+		/* fill block-local relative jump */
+		if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) {
+#if 0
+			if (src->s.jt || src->s.jf) {
+				free(offset);
+				conv_error(conv_state, "illegal jmp destination");
+				/*NOTREACHED*/
+			}
+#endif
+			goto filled;
+		}
+		if (off == slen - 2)	/*???*/
+			goto filled;
+
+	    {
+		u_int i;
+		int jt, jf;
+		const char ljerr[] = "%s for block-local relative jump: off=%d";
+
+#if 0
+		printf("code=%x off=%d %x %x\n", src->s.code,
+			off, src->s.jt, src->s.jf);
+#endif
+
+		if (!src->s.jt || !src->s.jf) {
+			free(offset);
+			conv_error(conv_state, ljerr, "no jmp destination", off);
+			/*NOTREACHED*/
+		}
+
+		jt = jf = 0;
+		for (i = 0; i < slen; i++) {
+			if (offset[i] == src->s.jt) {
+				if (jt) {
+					free(offset);
+					conv_error(conv_state, ljerr, "multiple matches", off);
+					/*NOTREACHED*/
+				}
+
+				if (i - off - 1 >= 256) {
+					free(offset);
+					conv_error(conv_state, ljerr, "out-of-range jump", off);
+					/*NOTREACHED*/
+				}
+				dst->jt = (u_char)(i - off - 1);
+				jt++;
+			}
+			if (offset[i] == src->s.jf) {
+				if (jf) {
+					free(offset);
+					conv_error(conv_state, ljerr, "multiple matches", off);
+					/*NOTREACHED*/
+				}
+				if (i - off - 1 >= 256) {
+					free(offset);
+					conv_error(conv_state, ljerr, "out-of-range jump", off);
+					/*NOTREACHED*/
+				}
+				dst->jf = (u_char)(i - off - 1);
+				jf++;
+			}
+		}
+		if (!jt || !jf) {
+			free(offset);
+			conv_error(conv_state, ljerr, "no destination found", off);
+			/*NOTREACHED*/
+		}
+	    }
+filled:
+		++dst;
+		++off;
+	}
+	if (offset)
+		free(offset);
+
+#ifdef BDEBUG
+	if (dst - conv_state->fstart < NBIDS)
+		bids[dst - conv_state->fstart] = p->id + 1;
+#endif
+	dst->code = (u_short)p->s.code;
+	dst->k = p->s.k;
+	if (JT(p)) {
+		/* number of extra jumps inserted */
+		u_char extrajmps = 0;
+		off = JT(p)->offset - (p->offset + slen) - 1;
+		if (off >= 256) {
+		    /* offset too large for branch, must add a jump */
+		    if (p->longjt == 0) {
+			/* mark this instruction and retry */
+			p->longjt++;
+			return(0);
+		    }
+		    dst->jt = extrajmps;
+		    extrajmps++;
+		    dst[extrajmps].code = BPF_JMP|BPF_JA;
+		    dst[extrajmps].k = off - extrajmps;
+		}
+		else
+		    dst->jt = (u_char)off;
+		off = JF(p)->offset - (p->offset + slen) - 1;
+		if (off >= 256) {
+		    /* offset too large for branch, must add a jump */
+		    if (p->longjf == 0) {
+			/* mark this instruction and retry */
+			p->longjf++;
+			return(0);
+		    }
+		    /* branch if F to following jump */
+		    /* if two jumps are inserted, F goes to second one */
+		    dst->jf = extrajmps;
+		    extrajmps++;
+		    dst[extrajmps].code = BPF_JMP|BPF_JA;
+		    dst[extrajmps].k = off - extrajmps;
+		}
+		else
+		    dst->jf = (u_char)off;
+	}
+	return (1);
+}
+
+
+/*
+ * Convert flowgraph intermediate representation to the
+ * BPF array representation.  Set *lenp to the number of instructions.
+ *
+ * This routine does *NOT* leak the memory pointed to by fp.  It *must
+ * not* do free(fp) before returning fp; doing so would make no sense,
+ * as the BPF array pointed to by the return value of icode_to_fcode()
+ * must be valid - it's being returned for use in a bpf_program structure.
+ *
+ * If it appears that icode_to_fcode() is leaking, the problem is that
+ * the program using pcap_compile() is failing to free the memory in
+ * the BPF program when it's done - the leak is in the program, not in
+ * the routine that happens to be allocating the memory.  (By analogy, if
+ * a program calls fopen() without ever calling fclose() on the FILE *,
+ * it will leak the FILE structure; the leak is not in fopen(), it's in
+ * the program.)  Change the program to use pcap_freecode() when it's
+ * done with the filter program.  See the pcap man page.
+ */
+struct bpf_insn *
+icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
+    char *errbuf)
+{
+	u_int n;
+	struct bpf_insn *fp;
+	conv_state_t conv_state;
+
+	conv_state.fstart = NULL;
+	conv_state.errbuf = errbuf;
+	if (setjmp(conv_state.top_ctx) != 0) {
+		free(conv_state.fstart);
+		return NULL;
+	}
+
+	/*
+	 * Loop doing convert_code_r() until no branches remain
+	 * with too-large offsets.
+	 */
+	for (;;) {
+	    unMarkAll(ic);
+	    n = *lenp = count_stmts(ic, root);
+
+	    fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
+	    if (fp == NULL) {
+		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "malloc");
+		free(fp);
+		return NULL;
+	    }
+	    memset((char *)fp, 0, sizeof(*fp) * n);
+	    conv_state.fstart = fp;
+	    conv_state.ftail = fp + n;
+
+	    unMarkAll(ic);
+	    if (convert_code_r(&conv_state, ic, root))
+		break;
+	    free(fp);
+	}
+
+	return fp;
+}
+
+/*
+ * For iconv_to_fconv() errors.
+ */
+static void PCAP_NORETURN
+conv_error(conv_state_t *conv_state, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void)vsnprintf(conv_state->errbuf,
+	    PCAP_ERRBUF_SIZE, fmt, ap);
+	va_end(ap);
+	longjmp(conv_state->top_ctx, 1);
+	/* NOTREACHED */
+}
+
+/*
+ * Make a copy of a BPF program and put it in the "fcode" member of
+ * a "pcap_t".
+ *
+ * If we fail to allocate memory for the copy, fill in the "errbuf"
+ * member of the "pcap_t" with an error message, and return -1;
+ * otherwise, return 0.
+ */
+int
+install_bpf_program(pcap_t *p, struct bpf_program *fp)
+{
+	size_t prog_size;
+
+	/*
+	 * Validate the program.
+	 */
+	if (!pcap_validate_filter(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);
+
+	prog_size = sizeof(*fp->bf_insns) * fp->bf_len;
+	p->fcode.bf_len = fp->bf_len;
+	p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size);
+	if (p->fcode.bf_insns == NULL) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+		    errno, "malloc");
+		return (-1);
+	}
+	memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size);
+	return (0);
+}
+
+#ifdef BDEBUG
+static void
+dot_dump_node(struct icode *ic, struct block *block, struct bpf_program *prog,
+    FILE *out)
+{
+	int icount, noffset;
+	int i;
+
+	if (block == NULL || isMarked(ic, block))
+		return;
+	Mark(ic, block);
+
+	icount = slength(block->stmts) + 1 + block->longjt + block->longjf;
+	noffset = min(block->offset + icount, (int)prog->bf_len);
+
+	fprintf(out, "\tblock%u [shape=ellipse, id=\"block-%u\" label=\"BLOCK%u\\n", block->id, block->id, block->id);
+	for (i = block->offset; i < noffset; i++) {
+		fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i));
+	}
+	fprintf(out, "\" tooltip=\"");
+	for (i = 0; i < BPF_MEMWORDS; i++)
+		if (block->val[i] != VAL_UNKNOWN)
+			fprintf(out, "val[%d]=%d ", i, block->val[i]);
+	fprintf(out, "val[A]=%d ", block->val[A_ATOM]);
+	fprintf(out, "val[X]=%d", block->val[X_ATOM]);
+	fprintf(out, "\"");
+	if (JT(block) == NULL)
+		fprintf(out, ", peripheries=2");
+	fprintf(out, "];\n");
+
+	dot_dump_node(ic, JT(block), prog, out);
+	dot_dump_node(ic, JF(block), prog, out);
+}
+
+static void
+dot_dump_edge(struct icode *ic, struct block *block, FILE *out)
+{
+	if (block == NULL || isMarked(ic, block))
+		return;
+	Mark(ic, block);
+
+	if (JT(block)) {
+		fprintf(out, "\t\"block%u\":se -> \"block%u\":n [label=\"T\"]; \n",
+				block->id, JT(block)->id);
+		fprintf(out, "\t\"block%u\":sw -> \"block%u\":n [label=\"F\"]; \n",
+			   block->id, JF(block)->id);
+	}
+	dot_dump_edge(ic, JT(block), out);
+	dot_dump_edge(ic, JF(block), out);
+}
+
+/* Output the block CFG using graphviz/DOT language
+ * In the CFG, block's code, value index for each registers at EXIT,
+ * and the jump relationship is show.
+ *
+ * example DOT for BPF `ip src host 1.1.1.1' is:
+    digraph BPF {
+    	block0 [shape=ellipse, id="block-0" label="BLOCK0\n\n(000) ldh      [12]\n(001) jeq      #0x800           jt 2	jf 5" tooltip="val[A]=0 val[X]=0"];
+    	block1 [shape=ellipse, id="block-1" label="BLOCK1\n\n(002) ld       [26]\n(003) jeq      #0x1010101       jt 4	jf 5" tooltip="val[A]=0 val[X]=0"];
+    	block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret      #68" tooltip="val[A]=0 val[X]=0", peripheries=2];
+    	block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret      #0" tooltip="val[A]=0 val[X]=0", peripheries=2];
+    	"block0":se -> "block1":n [label="T"];
+    	"block0":sw -> "block3":n [label="F"];
+    	"block1":se -> "block2":n [label="T"];
+    	"block1":sw -> "block3":n [label="F"];
+    }
+ *
+ *  After install graphviz on https://www.graphviz.org/, save it as bpf.dot
+ *  and run `dot -Tpng -O bpf.dot' to draw the graph.
+ */
+static int
+dot_dump(struct icode *ic, char *errbuf)
+{
+	struct bpf_program f;
+	FILE *out = stdout;
+
+	memset(bids, 0, sizeof bids);
+	f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
+	if (f.bf_insns == NULL)
+		return -1;
+
+	fprintf(out, "digraph BPF {\n");
+	unMarkAll(ic);
+	dot_dump_node(ic, ic->root, &f, out);
+	unMarkAll(ic);
+	dot_dump_edge(ic, ic->root, out);
+	fprintf(out, "}\n");
+
+	free((char *)f.bf_insns);
+	return 0;
+}
+
+static int
+plain_dump(struct icode *ic, char *errbuf)
+{
+	struct bpf_program f;
+
+	memset(bids, 0, sizeof bids);
+	f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
+	if (f.bf_insns == NULL)
+		return -1;
+	bpf_dump(&f, 1);
+	putchar('\n');
+	free((char *)f.bf_insns);
+	return 0;
+}
+
+static void
+opt_dump(opt_state_t *opt_state, struct icode *ic)
+{
+	int status;
+	char errbuf[PCAP_ERRBUF_SIZE];
+
+	/*
+	 * If the CFG, in DOT format, is requested, output it rather than
+	 * the code that would be generated from that graph.
+	 */
+	if (pcap_print_dot_graph)
+		status = dot_dump(ic, errbuf);
+	else
+		status = plain_dump(ic, errbuf);
+	if (status == -1)
+		opt_error(opt_state, "opt_dump: icode_to_fcode failed: %s", errbuf);
+}
+#endif
diff --git a/optimize.h b/optimize.h
new file mode 100644
index 0000000..56b31f4
--- /dev/null
+++ b/optimize.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Some stuff for use when debugging the optimizer.
+ */
+#ifdef BDEBUG
+#define NBIDS	1000
+extern int bids[NBIDS];
+#endif
diff --git a/pcap-common.c b/pcap-common.c
new file mode 100644
index 0000000..51d0666
--- /dev/null
+++ b/pcap-common.c
@@ -0,0 +1,1676 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-common.c - common code for pcap and pcapng files
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include "pcap-int.h"
+#include "extract.h"
+#include "pcap/sll.h"
+#include "pcap/usb.h"
+#include "pcap/nflog.h"
+#include "pcap/can_socketcan.h"
+
+#include "pcap-common.h"
+
+/*
+ * We don't write DLT_* values to capture files, because they're not the
+ * same on all platforms.
+ *
+ * Unfortunately, the various flavors of BSD have not always used the same
+ * numerical values for the same data types, and various patches to
+ * libpcap for non-BSD OSes have added their own DLT_* codes for link
+ * layer encapsulation types seen on those OSes, and those codes have had,
+ * in some cases, values that were also used, on other platforms, for other
+ * link layer encapsulation types.
+ *
+ * This means that capture files of a type whose numerical DLT_* code
+ * means different things on different BSDs, or with different versions
+ * of libpcap, can't always be read on systems other than those like
+ * the one running on the machine on which the capture was made.
+ *
+ * Instead, we define here a set of LINKTYPE_* codes, and map DLT_* codes
+ * to LINKTYPE_* codes when writing a savefile header, and map LINKTYPE_*
+ * codes to DLT_* codes when reading a savefile header.
+ *
+ * For those DLT_* codes that have, as far as we know, the same values on
+ * all platforms (DLT_NULL through DLT_FDDI), we define LINKTYPE_xxx as
+ * DLT_xxx; that way, captures of those types can still be read by
+ * versions of libpcap that map LINKTYPE_* values to DLT_* values, and
+ * captures of those types written by versions of libpcap that map DLT_
+ * values to LINKTYPE_ values can still be read by older versions
+ * of libpcap.
+ *
+ * The other LINKTYPE_* codes are given values starting at 100, in the
+ * hopes that no DLT_* code will be given one of those values.
+ *
+ * In order to ensure that a given LINKTYPE_* code's value will refer to
+ * the same encapsulation type on all platforms, you should not allocate
+ * a new LINKTYPE_* value without consulting
+ * "tcpdump-workers@lists.tcpdump.org".  The tcpdump developers will
+ * allocate a value for you, and will not subsequently allocate it to
+ * anybody else; that value will be added to the "pcap.h" in the
+ * tcpdump.org Git repository, so that a future libpcap release will
+ * include it.
+ *
+ * You should, if possible, also contribute patches to libpcap and tcpdump
+ * to handle the new encapsulation type, so that they can also be checked
+ * into the tcpdump.org Git repository and so that they will appear in
+ * future libpcap and tcpdump releases.
+ *
+ * Do *NOT* assume that any values after the largest value in this file
+ * are available; you might not have the most up-to-date version of this
+ * file, and new values after that one might have been assigned.  Also,
+ * do *NOT* use any values below 100 - those might already have been
+ * taken by one (or more!) organizations.
+ *
+ * Any platform that defines additional DLT_* codes should:
+ *
+ *	request a LINKTYPE_* code and value from tcpdump.org,
+ *	as per the above;
+ *
+ *	add, in their version of libpcap, an entry to map
+ *	those DLT_* codes to the corresponding LINKTYPE_*
+ *	code;
+ *
+ *	redefine, in their "net/bpf.h", any DLT_* values
+ *	that collide with the values used by their additional
+ *	DLT_* codes, to remove those collisions (but without
+ *	making them collide with any of the LINKTYPE_*
+ *	values equal to 50 or above; they should also avoid
+ *	defining DLT_* values that collide with those
+ *	LINKTYPE_* values, either).
+ */
+#define LINKTYPE_NULL		DLT_NULL
+#define LINKTYPE_ETHERNET	DLT_EN10MB	/* also for 100Mb and up */
+#define LINKTYPE_EXP_ETHERNET	DLT_EN3MB	/* 3Mb experimental Ethernet */
+#define LINKTYPE_AX25		DLT_AX25
+#define LINKTYPE_PRONET		DLT_PRONET
+#define LINKTYPE_CHAOS		DLT_CHAOS
+#define LINKTYPE_IEEE802_5	DLT_IEEE802	/* DLT_IEEE802 is used for 802.5 Token Ring */
+#define LINKTYPE_ARCNET_BSD	DLT_ARCNET	/* BSD-style headers */
+#define LINKTYPE_SLIP		DLT_SLIP
+#define LINKTYPE_PPP		DLT_PPP
+#define LINKTYPE_FDDI		DLT_FDDI
+
+/*
+ * LINKTYPE_PPP is for use when there might, or might not, be an RFC 1662
+ * PPP in HDLC-like framing header (with 0xff 0x03 before the PPP protocol
+ * field) at the beginning of the packet.
+ *
+ * This is for use when there is always such a header; the address field
+ * might be 0xff, for regular PPP, or it might be an address field for Cisco
+ * point-to-point with HDLC framing as per section 4.3.1 of RFC 1547 ("Cisco
+ * HDLC").  This is, for example, what you get with NetBSD's DLT_PPP_SERIAL.
+ *
+ * We give it the same value as NetBSD's DLT_PPP_SERIAL, in the hopes that
+ * nobody else will choose a DLT_ value of 50, and so that DLT_PPP_SERIAL
+ * captures will be written out with a link type that NetBSD's tcpdump
+ * can read.
+ */
+#define LINKTYPE_PPP_HDLC	50		/* PPP in HDLC-like framing */
+
+#define LINKTYPE_PPP_ETHER	51		/* NetBSD PPP-over-Ethernet */
+
+#define LINKTYPE_SYMANTEC_FIREWALL 99		/* Symantec Enterprise Firewall */
+
+/*
+ * These correspond to DLT_s that have different values on different
+ * platforms; we map between these values in capture files and
+ * the DLT_ values as returned by pcap_datalink() and passed to
+ * pcap_open_dead().
+ */
+#define LINKTYPE_ATM_RFC1483	100		/* LLC/SNAP-encapsulated ATM */
+#define LINKTYPE_RAW		101		/* raw IP */
+#define LINKTYPE_SLIP_BSDOS	102		/* BSD/OS SLIP BPF header */
+#define LINKTYPE_PPP_BSDOS	103		/* BSD/OS PPP BPF header */
+
+/*
+ * Values starting with 104 are used for newly-assigned link-layer
+ * header type values; for those link-layer header types, the DLT_
+ * value returned by pcap_datalink() and passed to pcap_open_dead(),
+ * and the LINKTYPE_ value that appears in capture files, are the
+ * same.
+ *
+ * LINKTYPE_MATCHING_MIN is the lowest such value; LINKTYPE_MATCHING_MAX
+ * is the highest such value.
+ */
+#define LINKTYPE_MATCHING_MIN	104		/* lowest value in the "matching" range */
+
+#define LINKTYPE_C_HDLC		104		/* Cisco HDLC */
+#define LINKTYPE_IEEE802_11	105		/* IEEE 802.11 (wireless) */
+#define LINKTYPE_ATM_CLIP	106		/* Linux Classical IP over ATM */
+#define LINKTYPE_FRELAY		107		/* Frame Relay */
+#define LINKTYPE_LOOP		108		/* OpenBSD loopback */
+#define LINKTYPE_ENC		109		/* OpenBSD IPSEC enc */
+
+/*
+ * These three types are reserved for future use.
+ */
+#define LINKTYPE_LANE8023	110		/* ATM LANE + 802.3 */
+#define LINKTYPE_HIPPI		111		/* NetBSD HIPPI */
+#define LINKTYPE_HDLC		112		/* NetBSD HDLC framing */
+
+#define LINKTYPE_LINUX_SLL	113		/* Linux cooked socket capture */
+#define LINKTYPE_LTALK		114		/* Apple LocalTalk hardware */
+#define LINKTYPE_ECONET		115		/* Acorn Econet */
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define LINKTYPE_IPFILTER	116
+
+#define LINKTYPE_PFLOG		117		/* OpenBSD DLT_PFLOG */
+#define LINKTYPE_CISCO_IOS	118		/* For Cisco-internal use */
+#define LINKTYPE_IEEE802_11_PRISM 119		/* 802.11 plus Prism II monitor mode radio metadata header */
+#define LINKTYPE_IEEE802_11_AIRONET 120		/* 802.11 plus FreeBSD Aironet driver radio metadata header */
+
+/*
+ * Reserved for Siemens HiPath HDLC.
+ */
+#define LINKTYPE_HHDLC		121
+
+#define LINKTYPE_IP_OVER_FC	122		/* RFC 2625 IP-over-Fibre Channel */
+#define LINKTYPE_SUNATM		123		/* Solaris+SunATM */
+
+/*
+ * Reserved as per request from Kent Dahlgren <kent@praesum.com>
+ * for private use.
+ */
+#define LINKTYPE_RIO		124		/* RapidIO */
+#define LINKTYPE_PCI_EXP	125		/* PCI Express */
+#define LINKTYPE_AURORA		126		/* Xilinx Aurora link layer */
+
+#define LINKTYPE_IEEE802_11_RADIOTAP 127	/* 802.11 plus radiotap radio metadata header */
+
+/*
+ * Reserved for the TZSP encapsulation, as per request from
+ * Chris Waters <chris.waters@networkchemistry.com>
+ * TZSP is a generic encapsulation for any other link type,
+ * which includes a means to include meta-information
+ * with the packet, e.g. signal strength and channel
+ * for 802.11 packets.
+ */
+#define LINKTYPE_TZSP		128		/* Tazmen Sniffer Protocol */
+
+#define LINKTYPE_ARCNET_LINUX	129		/* Linux-style headers */
+
+/*
+ * Juniper-private data link types, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The corresponding
+ * DLT_s are used for passing on chassis-internal
+ * metainformation such as QOS profiles, etc..
+ */
+#define LINKTYPE_JUNIPER_MLPPP  130
+#define LINKTYPE_JUNIPER_MLFR   131
+#define LINKTYPE_JUNIPER_ES     132
+#define LINKTYPE_JUNIPER_GGSN   133
+#define LINKTYPE_JUNIPER_MFR    134
+#define LINKTYPE_JUNIPER_ATM2   135
+#define LINKTYPE_JUNIPER_SERVICES 136
+#define LINKTYPE_JUNIPER_ATM1   137
+
+#define LINKTYPE_APPLE_IP_OVER_IEEE1394 138	/* Apple IP-over-IEEE 1394 cooked header */
+
+#define LINKTYPE_MTP2_WITH_PHDR	139
+#define LINKTYPE_MTP2		140
+#define LINKTYPE_MTP3		141
+#define LINKTYPE_SCCP		142
+
+#define LINKTYPE_DOCSIS		143		/* DOCSIS MAC frames */
+
+#define LINKTYPE_LINUX_IRDA	144		/* Linux-IrDA */
+
+/*
+ * Reserved for IBM SP switch and IBM Next Federation switch.
+ */
+#define LINKTYPE_IBM_SP		145
+#define LINKTYPE_IBM_SN		146
+
+/*
+ * Reserved for private use.  If you have some link-layer header type
+ * that you want to use within your organization, with the capture files
+ * using that link-layer header type not ever be sent outside your
+ * organization, you can use these values.
+ *
+ * No libpcap release will use these for any purpose, nor will any
+ * tcpdump release use them, either.
+ *
+ * Do *NOT* use these in capture files that you expect anybody not using
+ * your private versions of capture-file-reading tools to read; in
+ * particular, do *NOT* use them in products, otherwise you may find that
+ * people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ * read capture files from your firewall/intrusion detection/traffic
+ * monitoring/etc. appliance, or whatever product uses that LINKTYPE_ value,
+ * and you may also find that the developers of those applications will
+ * not accept patches to let them read those files.
+ *
+ * Also, do not use them if somebody might send you a capture using them
+ * for *their* private type and tools using them for *your* private type
+ * would have to read them.
+ *
+ * Instead, in those cases, ask "tcpdump-workers@lists.tcpdump.org" for a
+ * new DLT_ and LINKTYPE_ value, as per the comment in pcap/bpf.h, and use
+ * the type you're given.
+ */
+#define LINKTYPE_USER0		147
+#define LINKTYPE_USER1		148
+#define LINKTYPE_USER2		149
+#define LINKTYPE_USER3		150
+#define LINKTYPE_USER4		151
+#define LINKTYPE_USER5		152
+#define LINKTYPE_USER6		153
+#define LINKTYPE_USER7		154
+#define LINKTYPE_USER8		155
+#define LINKTYPE_USER9		156
+#define LINKTYPE_USER10		157
+#define LINKTYPE_USER11		158
+#define LINKTYPE_USER12		159
+#define LINKTYPE_USER13		160
+#define LINKTYPE_USER14		161
+#define LINKTYPE_USER15		162
+
+/*
+ * For future use with 802.11 captures - defined by AbsoluteValue
+ * Systems to store a number of bits of link-layer information
+ * including radio information:
+ *
+ *	http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ */
+#define LINKTYPE_IEEE802_11_AVS	163	/* 802.11 plus AVS radio metadata header */
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The corresponding
+ * DLT_s are used for passing on chassis-internal
+ * metainformation such as QOS profiles, etc..
+ */
+#define LINKTYPE_JUNIPER_MONITOR 164
+
+/*
+ * BACnet MS/TP frames.
+ */
+#define LINKTYPE_BACNET_MS_TP	165
+
+/*
+ * Another PPP variant as per request from Karsten Keil <kkeil@suse.de>.
+ *
+ * This is used in some OSes to allow a kernel socket filter to distinguish
+ * between incoming and outgoing packets, on a socket intended to
+ * supply pppd with outgoing packets so it can do dial-on-demand and
+ * hangup-on-lack-of-demand; incoming packets are filtered out so they
+ * don't cause pppd to hold the connection up (you don't want random
+ * input packets such as port scans, packets from old lost connections,
+ * etc. to force the connection to stay up).
+ *
+ * The first byte of the PPP header (0xff03) is modified to accommodate
+ * the direction - 0x00 = IN, 0x01 = OUT.
+ */
+#define LINKTYPE_PPP_PPPD	166
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, cookies, etc..
+ */
+#define LINKTYPE_JUNIPER_PPPOE     167
+#define LINKTYPE_JUNIPER_PPPOE_ATM 168
+
+#define LINKTYPE_GPRS_LLC	169		/* GPRS LLC */
+#define LINKTYPE_GPF_T		170		/* GPF-T (ITU-T G.7041/Y.1303) */
+#define LINKTYPE_GPF_F		171		/* GPF-F (ITU-T G.7041/Y.1303) */
+
+/*
+ * Requested by Oolan Zimmer <oz@gcom.com> for use in Gcom's T1/E1 line
+ * monitoring equipment.
+ */
+#define LINKTYPE_GCOM_T1E1	172
+#define LINKTYPE_GCOM_SERIAL	173
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The DLT_ is used
+ * for internal communication to Physical Interface Cards (PIC)
+ */
+#define LINKTYPE_JUNIPER_PIC_PEER    174
+
+/*
+ * Link types requested by Gregor Maier <gregor@endace.com> of Endace
+ * Measurement Systems.  They add an ERF header (see
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * the link-layer header.
+ */
+#define LINKTYPE_ERF_ETH	175	/* Ethernet */
+#define LINKTYPE_ERF_POS	176	/* Packet-over-SONET */
+
+/*
+ * Requested by Daniele Orlandi <daniele@orlandi.com> for raw LAPD
+ * for vISDN (http://www.orlandi.com/visdn/).  Its link-layer header
+ * includes additional information before the LAPD header, so it's
+ * not necessarily a generic LAPD header.
+ */
+#define LINKTYPE_LINUX_LAPD	177
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The Link Types are used for prepending meta-information
+ * like interface index, interface name
+ * before standard Ethernet, PPP, Frelay & C-HDLC Frames
+ */
+#define LINKTYPE_JUNIPER_ETHER  178
+#define LINKTYPE_JUNIPER_PPP    179
+#define LINKTYPE_JUNIPER_FRELAY 180
+#define LINKTYPE_JUNIPER_CHDLC  181
+
+/*
+ * Multi Link Frame Relay (FRF.16)
+ */
+#define LINKTYPE_MFR            182
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * voice Adapter Card (PIC)
+ */
+#define LINKTYPE_JUNIPER_VP     183
+
+/*
+ * Arinc 429 frames.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Every frame contains a 32bit A429 label.
+ * More documentation on Arinc 429 can be found at
+ * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf
+ */
+#define LINKTYPE_A429           184
+
+/*
+ * Arinc 653 Interpartition Communication messages.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Please refer to the A653-1 standard for more information.
+ */
+#define LINKTYPE_A653_ICM       185
+
+/*
+ * This used to be "USB packets, beginning with a USB setup header;
+ * requested by Paolo Abeni <paolo.abeni@email.it>."
+ *
+ * However, that header didn't work all that well - it left out some
+ * useful information - and was abandoned in favor of the DLT_USB_LINUX
+ * header.
+ *
+ * This is now used by FreeBSD for its BPF taps for USB; that has its
+ * own headers.  So it is written, so it is done.
+ */
+#define LINKTYPE_USB_FREEBSD	186
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4); requested by
+ * Paolo Abeni.
+ */
+#define LINKTYPE_BLUETOOTH_HCI_H4	187
+
+/*
+ * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz
+ * <cruz_petagay@bah.com>.
+ */
+#define LINKTYPE_IEEE802_16_MAC_CPS	188
+
+/*
+ * USB packets, beginning with a Linux USB header; requested by
+ * Paolo Abeni <paolo.abeni@email.it>.
+ */
+#define LINKTYPE_USB_LINUX		189
+
+/*
+ * Controller Area Network (CAN) v. 2.0B packets.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Used to dump CAN packets coming from a CAN Vector board.
+ * More documentation on the CAN v2.0B frames can be found at
+ * http://www.can-cia.org/downloads/?269
+ */
+#define LINKTYPE_CAN20B         190
+
+/*
+ * IEEE 802.15.4, with address fields padded, as is done by Linux
+ * drivers; requested by Juergen Schimmer.
+ */
+#define LINKTYPE_IEEE802_15_4_LINUX	191
+
+/*
+ * Per Packet Information encapsulated packets.
+ * LINKTYPE_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ */
+#define LINKTYPE_PPI			192
+
+/*
+ * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header;
+ * requested by Charles Clancy.
+ */
+#define LINKTYPE_IEEE802_16_MAC_CPS_RADIO	193
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * integrated service module (ISM).
+ */
+#define LINKTYPE_JUNIPER_ISM    194
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), and with the FCS at the end of the frame; requested by
+ * Mikko Saarnivala <mikko.saarnivala@sensinode.com>.
+ *
+ * This should only be used if the FCS is present at the end of the
+ * frame; if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be
+ * used.
+ */
+#define LINKTYPE_IEEE802_15_4_WITHFCS	195
+
+/*
+ * Various link-layer types, with a pseudo-header, for SITA
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ */
+#define LINKTYPE_SITA		196
+
+/*
+ * Various link-layer types, with a pseudo-header, for Endace DAG cards;
+ * encapsulates Endace ERF records.  Requested by Stephen Donnelly
+ * <stephen@endace.com>.
+ */
+#define LINKTYPE_ERF		197
+
+/*
+ * Special header prepended to Ethernet packets when capturing from a
+ * u10 Networks board.  Requested by Phil Mulholland
+ * <phil@u10networks.com>.
+ */
+#define LINKTYPE_RAIF1		198
+
+/*
+ * IPMB packet for IPMI, beginning with a 2-byte header, followed by
+ * the I2C slave address, followed by the netFn and LUN, etc..
+ * Requested by Chanthy Toeung <chanthy.toeung@ca.kontron.com>.
+ *
+ * XXX - its DLT_ value used to be called DLT_IPMB, back when we got the
+ * impression from the email thread requesting it that the packet
+ * had no extra 2-byte header.  We've renamed it; if anybody used
+ * DLT_IPMB and assumed no 2-byte header, this will cause the compile
+ * to fail, at which point we'll have to figure out what to do about
+ * the two header types using the same DLT_/LINKTYPE_ value.  If that
+ * doesn't happen, we'll assume nobody used it and that the redefinition
+ * is safe.
+ */
+#define LINKTYPE_IPMB_KONTRON	199
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for capturing data on a secure tunnel interface.
+ */
+#define LINKTYPE_JUNIPER_ST     200
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4), with pseudo-header
+ * that includes direction information; requested by Paolo Abeni.
+ */
+#define LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR	201
+
+/*
+ * AX.25 packet with a 1-byte KISS header; see
+ *
+ *	http://www.ax25.net/kiss.htm
+ *
+ * as per Richard Stearn <richard@rns-stearn.demon.co.uk>.
+ */
+#define LINKTYPE_AX25_KISS	202
+
+/*
+ * LAPD packets from an ISDN channel, starting with the address field,
+ * with no pseudo-header.
+ * Requested by Varuna De Silva <varunax@gmail.com>.
+ */
+#define LINKTYPE_LAPD		203
+
+/*
+ * PPP, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host", non-zero (any non-zero value) means "sent by
+ * this host" - as per Will Barker <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_PPP_WITH_DIR	204	/* Don't confuse with LINKTYPE_PPP_PPPD */
+
+/*
+ * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host", non-zero (any non-zero value) means
+ * "sent by this host" - as per Will Barker <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_C_HDLC_WITH_DIR 205	/* Cisco HDLC */
+
+/*
+ * Frame Relay, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host" (DCE -> DTE), non-zero (any non-zero
+ * value) means "sent by this host" (DTE -> DCE) - as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_FRELAY_WITH_DIR 206	/* Frame Relay */
+
+/*
+ * LAPB, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host" (DCE -> DTE), non-zero (any non-zero value)
+ * means "sent by this host" (DTE -> DCE)- as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_LAPB_WITH_DIR	207	/* LAPB */
+
+/*
+ * 208 is reserved for an as-yet-unspecified proprietary link-layer
+ * type, as requested by Will Barker.
+ */
+
+/*
+ * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman
+ * <avn@pigeonpoint.com>.
+ */
+#define LINKTYPE_IPMB_LINUX	209
+
+/*
+ * FlexRay automotive bus - http://www.flexray.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_FLEXRAY	210
+
+/*
+ * Media Oriented Systems Transport (MOST) bus for multimedia
+ * transport - https://www.mostcooperation.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_MOST		211
+
+/*
+ * Local Interconnect Network (LIN) bus for vehicle networks -
+ * http://www.lin-subbus.org/ - as requested by Hannes Kaelber
+ * <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_LIN		212
+
+/*
+ * X2E-private data link type used for serial line capture,
+ * as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_X2E_SERIAL	213
+
+/*
+ * X2E-private data link type used for the Xoraya data logger
+ * family, as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_X2E_XORAYA	214
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), but with the PHY-level data for non-ASK PHYs (4 octets
+ * of 0 as preamble, one octet of SFD, one octet of frame length+
+ * reserved bit, and then the MAC-layer data, starting with the
+ * frame control field).
+ *
+ * Requested by Max Filippov <jcmvbkbc@gmail.com>.
+ */
+#define LINKTYPE_IEEE802_15_4_NONASK_PHY	215
+
+/*
+ * David Gibson <david@gibson.dropbear.id.au> requested this for
+ * captures from the Linux kernel /dev/input/eventN devices. This
+ * is used to communicate keystrokes and mouse movements from the
+ * Linux kernel to display systems, such as Xorg.
+ */
+#define LINKTYPE_LINUX_EVDEV	216
+
+/*
+ * GSM Um and Abis interfaces, preceded by a "gsmtap" header.
+ *
+ * Requested by Harald Welte <laforge@gnumonks.org>.
+ */
+#define LINKTYPE_GSMTAP_UM	217
+#define LINKTYPE_GSMTAP_ABIS	218
+
+/*
+ * MPLS, with an MPLS label as the link-layer header.
+ * Requested by Michele Marchetto <michele@openbsd.org> on behalf
+ * of OpenBSD.
+ */
+#define LINKTYPE_MPLS		219
+
+/*
+ * USB packets, beginning with a Linux USB header, with the USB header
+ * padded to 64 bytes; required for memory-mapped access.
+ */
+#define LINKTYPE_USB_LINUX_MMAPPED		220
+
+/*
+ * DECT packets, with a pseudo-header; requested by
+ * Matthias Wenzel <tcpdump@mazzoo.de>.
+ */
+#define LINKTYPE_DECT		221
+
+/*
+ * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" <eric.lidwa-1@nasa.gov>
+ * Date: Mon, 11 May 2009 11:18:30 -0500
+ *
+ * DLT_AOS. We need it for AOS Space Data Link Protocol.
+ *   I have already written dissectors for but need an OK from
+ *   legal before I can submit a patch.
+ *
+ */
+#define LINKTYPE_AOS		222
+
+/*
+ * Wireless HART (Highway Addressable Remote Transducer)
+ * From the HART Communication Foundation
+ * IES/PAS 62591
+ *
+ * Requested by Sam Roberts <vieuxtech@gmail.com>.
+ */
+#define LINKTYPE_WIHART		223
+
+/*
+ * Fibre Channel FC-2 frames, beginning with a Frame_Header.
+ * Requested by Kahou Lei <kahou82@gmail.com>.
+ */
+#define LINKTYPE_FC_2		224
+
+/*
+ * Fibre Channel FC-2 frames, beginning with an encoding of the
+ * SOF, and ending with an encoding of the EOF.
+ *
+ * The encodings represent the frame delimiters as 4-byte sequences
+ * representing the corresponding ordered sets, with K28.5
+ * represented as 0xBC, and the D symbols as the corresponding
+ * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2,
+ * is represented as 0xBC 0xB5 0x55 0x55.
+ *
+ * Requested by Kahou Lei <kahou82@gmail.com>.
+ */
+#define LINKTYPE_FC_2_WITH_FRAME_DELIMS		225
+
+/*
+ * Solaris ipnet pseudo-header; requested by Darren Reed <Darren.Reed@Sun.COM>.
+ *
+ * The pseudo-header starts with a one-byte version number; for version 2,
+ * the pseudo-header is:
+ *
+ * struct dl_ipnetinfo {
+ *     uint8_t   dli_version;
+ *     uint8_t   dli_family;
+ *     uint16_t  dli_htype;
+ *     uint32_t  dli_pktlen;
+ *     uint32_t  dli_ifindex;
+ *     uint32_t  dli_grifindex;
+ *     uint32_t  dli_zsrc;
+ *     uint32_t  dli_zdst;
+ * };
+ *
+ * dli_version is 2 for the current version of the pseudo-header.
+ *
+ * dli_family is a Solaris address family value, so it's 2 for IPv4
+ * and 26 for IPv6.
+ *
+ * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing
+ * packets, and 2 for packets arriving from another zone on the same
+ * machine.
+ *
+ * dli_pktlen is the length of the packet data following the pseudo-header
+ * (so the captured length minus dli_pktlen is the length of the
+ * pseudo-header, assuming the entire pseudo-header was captured).
+ *
+ * dli_ifindex is the interface index of the interface on which the
+ * packet arrived.
+ *
+ * dli_grifindex is the group interface index number (for IPMP interfaces).
+ *
+ * dli_zsrc is the zone identifier for the source of the packet.
+ *
+ * dli_zdst is the zone identifier for the destination of the packet.
+ *
+ * A zone number of 0 is the global zone; a zone number of 0xffffffff
+ * means that the packet arrived from another host on the network, not
+ * from another zone on the same machine.
+ *
+ * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates
+ * which of those it is.
+ */
+#define LINKTYPE_IPNET		226
+
+/*
+ * CAN (Controller Area Network) frames, with a pseudo-header as supplied
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in big-endian byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
+ *
+ * Requested by Felix Obenhuber <felix@obenhuber.de>.
+ */
+#define LINKTYPE_CAN_SOCKETCAN	227
+
+/*
+ * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies
+ * whether it's v4 or v6.  Requested by Darren Reed <Darren.Reed@Sun.COM>.
+ */
+#define LINKTYPE_IPV4		228
+#define LINKTYPE_IPV6		229
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), and with no FCS at the end of the frame; requested by
+ * Jon Smirl <jonsmirl@gmail.com>.
+ */
+#define LINKTYPE_IEEE802_15_4_NOFCS		230
+
+/*
+ * Raw D-Bus:
+ *
+ *	https://www.freedesktop.org/wiki/Software/dbus
+ *
+ * messages:
+ *
+ *	https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ *
+ * starting with the endianness flag, followed by the message type, etc.,
+ * but without the authentication handshake before the message sequence:
+ *
+ *	https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ *
+ * Requested by Martin Vidner <martin@vidner.net>.
+ */
+#define LINKTYPE_DBUS		231
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define LINKTYPE_JUNIPER_VS			232
+#define LINKTYPE_JUNIPER_SRX_E2E		233
+#define LINKTYPE_JUNIPER_FIBRECHANNEL		234
+
+/*
+ * DVB-CI (DVB Common Interface for communication between a PC Card
+ * module and a DVB receiver).  See
+ *
+ *	https://www.kaiser.cx/pcap-dvbci.html
+ *
+ * for the specification.
+ *
+ * Requested by Martin Kaiser <martin@kaiser.cx>.
+ */
+#define LINKTYPE_DVB_CI		235
+
+/*
+ * Variant of 3GPP TS 27.010 multiplexing protocol.  Requested
+ * by Hans-Christoph Schemmel <hans-christoph.schemmel@cinterion.com>.
+ */
+#define LINKTYPE_MUX27010	236
+
+/*
+ * STANAG 5066 D_PDUs.  Requested by M. Baris Demiray
+ * <barisdemiray@gmail.com>.
+ */
+#define LINKTYPE_STANAG_5066_D_PDU		237
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define LINKTYPE_JUNIPER_ATM_CEMIC		238
+
+/*
+ * NetFilter LOG messages
+ * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets)
+ *
+ * Requested by Jakub Zawadzki <darkjames-ws@darkjames.pl>
+ */
+#define LINKTYPE_NFLOG		239
+
+/*
+ * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type
+ * for Ethernet packets with a 4-byte pseudo-header and always
+ * with the payload including the FCS, as supplied by their
+ * netANALYZER hardware and software.
+ *
+ * Requested by Holger P. Frommer <HPfrommer@hilscher.com>
+ */
+#define LINKTYPE_NETANALYZER	240
+
+/*
+ * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type
+ * for Ethernet packets with a 4-byte pseudo-header and FCS and
+ * 1 byte of SFD, as supplied by their netANALYZER hardware and
+ * software.
+ *
+ * Requested by Holger P. Frommer <HPfrommer@hilscher.com>
+ */
+#define LINKTYPE_NETANALYZER_TRANSPARENT	241
+
+/*
+ * IP-over-InfiniBand, as specified by RFC 4391.
+ *
+ * Requested by Petr Sumbera <petr.sumbera@oracle.com>.
+ */
+#define LINKTYPE_IPOIB		242
+
+/*
+ * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0).
+ *
+ * Requested by Guy Martin <gmsoft@tuxicoman.be>.
+ */
+#define LINKTYPE_MPEG_2_TS	243
+
+/*
+ * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as
+ * used by their ng40 protocol tester.
+ *
+ * Requested by Jens Grimmer <jens.grimmer@ng4t.com>.
+ */
+#define LINKTYPE_NG40		244
+
+/*
+ * Pseudo-header giving adapter number and flags, followed by an NFC
+ * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU,
+ * as specified by NFC Forum Logical Link Control Protocol Technical
+ * Specification LLCP 1.1.
+ *
+ * Requested by Mike Wakerly <mikey@google.com>.
+ */
+#define LINKTYPE_NFC_LLCP	245
+
+/*
+ * pfsync output; DLT_PFSYNC is 18, which collides with DLT_CIP in
+ * SuSE 6.3, on OpenBSD, NetBSD, DragonFly BSD, and macOS, and
+ * is 121, which collides with DLT_HHDLC, in FreeBSD.  We pick a
+ * shiny new link-layer header type value that doesn't collide with
+ * anything, in the hopes that future pfsync savefiles, if any,
+ * won't require special hacks to distinguish from other savefiles.
+ *
+ */
+#define LINKTYPE_PFSYNC		246
+
+/*
+ * Raw InfiniBand packets, starting with the Local Routing Header.
+ *
+ * Requested by Oren Kladnitsky <orenk@mellanox.com>.
+ */
+#define LINKTYPE_INFINIBAND	247
+
+/*
+ * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6).
+ *
+ * Requested by Michael Tuexen <Michael.Tuexen@lurchi.franken.de>.
+ */
+#define LINKTYPE_SCTP		248
+
+/*
+ * USB packets, beginning with a USBPcap header.
+ *
+ * Requested by Tomasz Mon <desowin@gmail.com>
+ */
+#define LINKTYPE_USBPCAP	249
+
+/*
+ * Schweitzer Engineering Laboratories "RTAC" product serial-line
+ * packets.
+ *
+ * Requested by Chris Bontje <chris_bontje@selinc.com>.
+ */
+#define LINKTYPE_RTAC_SERIAL		250
+
+/*
+ * Bluetooth Low Energy air interface link-layer packets.
+ *
+ * Requested by Mike Kershaw <dragorn@kismetwireless.net>.
+ */
+#define LINKTYPE_BLUETOOTH_LE_LL	251
+
+/*
+ * Link-layer header type for upper-protocol layer PDU saves from wireshark.
+ *
+ * the actual contents are determined by two TAGs stored with each
+ * packet:
+ *   EXP_PDU_TAG_LINKTYPE          the link type (LINKTYPE_ value) of the
+ *				   original packet.
+ *
+ *   EXP_PDU_TAG_PROTO_NAME        the name of the wireshark dissector
+ * 				   that can make sense of the data stored.
+ */
+#define LINKTYPE_WIRESHARK_UPPER_PDU	252
+
+/*
+ * Link-layer header type for the netlink protocol (nlmon devices).
+ */
+#define LINKTYPE_NETLINK		253
+
+/*
+ * Bluetooth Linux Monitor headers for the BlueZ stack.
+ */
+#define LINKTYPE_BLUETOOTH_LINUX_MONITOR	254
+
+/*
+ * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as
+ * captured by Ubertooth.
+ */
+#define LINKTYPE_BLUETOOTH_BREDR_BB	255
+
+/*
+ * Bluetooth Low Energy link layer packets, as captured by Ubertooth.
+ */
+#define LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR	256
+
+/*
+ * PROFIBUS data link layer.
+ */
+#define LINKTYPE_PROFIBUS_DL		257
+
+/*
+ * Apple's DLT_PKTAP headers.
+ *
+ * Sadly, the folks at Apple either had no clue that the DLT_USERn values
+ * are for internal use within an organization and partners only, and
+ * didn't know that the right way to get a link-layer header type is to
+ * ask tcpdump.org for one, or knew and didn't care, so they just
+ * used DLT_USER2, which causes problems for everything except for
+ * their version of tcpdump.
+ *
+ * So I'll just give them one; hopefully this will show up in a
+ * libpcap release in time for them to get this into 10.10 Big Sur
+ * or whatever Mavericks' successor is called.  LINKTYPE_PKTAP
+ * will be 258 *even on macOS*; that is *intentional*, so that
+ * PKTAP files look the same on *all* OSes (different OSes can have
+ * different numerical values for a given DLT_, but *MUST NOT* have
+ * different values for what goes in a file, as files can be moved
+ * between OSes!).
+ */
+#define LINKTYPE_PKTAP		258
+
+/*
+ * Ethernet packets preceded by a header giving the last 6 octets
+ * of the preamble specified by 802.3-2012 Clause 65, section
+ * 65.1.3.2 "Transmit".
+ */
+#define LINKTYPE_EPON		259
+
+/*
+ * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format"
+ * in the PICMG HPM.2 specification.
+ */
+#define LINKTYPE_IPMI_HPM_2	260
+
+/*
+ * per  Joshua Wright <jwright@hasborg.com>, formats for Zwave captures.
+ */
+#define LINKTYPE_ZWAVE_R1_R2	261
+#define LINKTYPE_ZWAVE_R3	262
+
+/*
+ * per Steve Karg <skarg@users.sourceforge.net>, formats for Wattstopper
+ * Digital Lighting Management room bus serial protocol captures.
+ */
+#define LINKTYPE_WATTSTOPPER_DLM 263
+
+/*
+ * ISO 14443 contactless smart card messages.
+ */
+#define LINKTYPE_ISO_14443      264
+
+/*
+ * Radio data system (RDS) groups.  IEC 62106.
+ * Per Jonathan Brucker <jonathan.brucke@gmail.com>.
+ */
+#define LINKTYPE_RDS		265
+
+/*
+ * USB packets, beginning with a Darwin (macOS, etc.) header.
+ */
+#define LINKTYPE_USB_DARWIN	266
+
+/*
+ * OpenBSD DLT_OPENFLOW.
+ */
+#define LINKTYPE_OPENFLOW	267
+
+/*
+ * SDLC frames containing SNA PDUs.
+ */
+#define LINKTYPE_SDLC		268
+
+/*
+ * per "Selvig, Bjorn" <b.selvig@ti.com> used for
+ * TI protocol sniffer.
+ */
+#define LINKTYPE_TI_LLN_SNIFFER	269
+
+/*
+ * per: Erik de Jong <erikdejong at gmail.com> for
+ *   https://github.com/eriknl/LoRaTap/releases/tag/v0.1
+ */
+#define LINKTYPE_LORATAP        270
+
+/*
+ * per: Stefanha at gmail.com for
+ *   https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h
+ * for: https://qemu-project.org/Features/VirtioVsock
+ */
+#define LINKTYPE_VSOCK          271
+
+/*
+ * Nordic Semiconductor Bluetooth LE sniffer.
+ */
+#define LINKTYPE_NORDIC_BLE	272
+
+/*
+ * Excentis DOCSIS 3.1 RF sniffer (XRA-31)
+ *   per: bruno.verstuyft at excentis.com
+ *        https://www.xra31.com/xra-header
+ */
+#define LINKTYPE_DOCSIS31_XRA31	273
+
+/*
+ * mPackets, as specified by IEEE 802.3br Figure 99-4, starting
+ * with the preamble and always ending with a CRC field.
+ */
+#define LINKTYPE_ETHERNET_MPACKET	274
+
+/*
+ * DisplayPort AUX channel monitoring data as specified by VESA
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
+ *    per dirk.eibach at gdsys.cc
+ */
+#define LINKTYPE_DISPLAYPORT_AUX	275
+
+/*
+ * Linux cooked sockets v2.
+ */
+#define LINKTYPE_LINUX_SLL2	276
+
+/*
+ * Sercos Monitor, per Manuel Jacob <manuel.jacob at steinbeis-stg.de>
+ */
+#define LINKTYPE_SERCOS_MONITOR 277
+
+/*
+ * OpenVizsla http://openvizsla.org is open source USB analyzer hardware.
+ * It consists of FPGA with attached USB phy and FTDI chip for streaming
+ * the data to the host PC.
+ *
+ * Current OpenVizsla data encapsulation format is described here:
+ * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description
+ *
+ */
+#define LINKTYPE_OPENVIZSLA     278
+
+/*
+ * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced
+ * by a PCIe Card for interfacing high speed automotive interfaces.
+ *
+ * The specification for this frame format can be found at:
+ *   https://www.elektrobit.com/ebhscr
+ *
+ * for Guenter.Ebermann at elektrobit.com
+ *
+ */
+#define LINKTYPE_EBHSCR	        279
+
+/*
+ * The https://fd.io vpp graph dispatch tracer produces pcap trace files
+ * in the format documented here:
+ * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing
+ */
+#define LINKTYPE_VPP_DISPATCH	280
+
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define LINKTYPE_DSA_TAG_BRCM	281
+#define LINKTYPE_DSA_TAG_BRCM_PREPEND	282
+
+/*
+ * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload
+ * exactly as it appears in the spec (no padding, no nothing), and FCS if
+ * specified by FCS Type TLV;  requested by James Ko <jck@exegin.com>.
+ * Specification at https://github.com/jkcko/ieee802.15.4-tap
+ */
+#define LINKTYPE_IEEE802_15_4_TAP       283
+
+/*
+ * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format.
+ */
+#define LINKTYPE_DSA_TAG_DSA	284
+#define LINKTYPE_DSA_TAG_EDSA	285
+
+/*
+ * Payload of lawful intercept packets using the ELEE protocol;
+ * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii
+ */
+#define LINKTYPE_ELEE		286
+
+/*
+ * Serial frames transmitted between a host and a Z-Wave chip.
+ */
+#define LINKTYPE_Z_WAVE_SERIAL	287
+
+/*
+ * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable.
+ */
+#define LINKTYPE_USB_2_0	288
+
+/*
+ * ATSC Link-Layer Protocol (A/330) packets.
+ */
+#define LINKTYPE_ATSC_ALP	289
+
+#define LINKTYPE_MATCHING_MAX	289		/* highest value in the "matching" range */
+
+/*
+ * The DLT_ and LINKTYPE_ values in the "matching" range should be the
+ * same, so DLT_MATCHING_MAX and LINKTYPE_MATCHING_MAX should be the
+ * same.
+ */
+#if LINKTYPE_MATCHING_MAX != DLT_MATCHING_MAX
+#error The LINKTYPE_ matching range does not match the DLT_ matching range
+#endif
+
+static struct linktype_map {
+	int	dlt;
+	int	linktype;
+} map[] = {
+	/*
+	 * These DLT_* codes have LINKTYPE_* codes with values identical
+	 * to the values of the corresponding DLT_* code.
+	 */
+	{ DLT_NULL,		LINKTYPE_NULL },
+	{ DLT_EN10MB,		LINKTYPE_ETHERNET },
+	{ DLT_EN3MB,		LINKTYPE_EXP_ETHERNET },
+	{ DLT_AX25,		LINKTYPE_AX25 },
+	{ DLT_PRONET,		LINKTYPE_PRONET },
+	{ DLT_CHAOS,		LINKTYPE_CHAOS },
+	{ DLT_IEEE802,		LINKTYPE_IEEE802_5 },
+	{ DLT_ARCNET,		LINKTYPE_ARCNET_BSD },
+	{ DLT_SLIP,		LINKTYPE_SLIP },
+	{ DLT_PPP,		LINKTYPE_PPP },
+	{ DLT_FDDI,		LINKTYPE_FDDI },
+	{ DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL },
+
+	/*
+	 * These DLT_* codes have different values on different
+	 * platforms; we map them to LINKTYPE_* codes that
+	 * have values that should never be equal to any DLT_*
+	 * code.
+	 */
+#ifdef DLT_FR
+	/* BSD/OS Frame Relay */
+	{ DLT_FR,		LINKTYPE_FRELAY },
+#endif
+
+	{ DLT_ATM_RFC1483, 	LINKTYPE_ATM_RFC1483 },
+	{ DLT_RAW,		LINKTYPE_RAW },
+	{ DLT_SLIP_BSDOS,	LINKTYPE_SLIP_BSDOS },
+	{ DLT_PPP_BSDOS,	LINKTYPE_PPP_BSDOS },
+
+	/* BSD/OS Cisco HDLC */
+	{ DLT_C_HDLC,		LINKTYPE_C_HDLC },
+
+	/*
+	 * These DLT_* codes are not on all platforms, but, so far,
+	 * there don't appear to be any platforms that define
+	 * other codes with those values; we map them to
+	 * different LINKTYPE_* values anyway, just in case.
+	 */
+
+	/* Linux ATM Classical IP */
+	{ DLT_ATM_CLIP,		LINKTYPE_ATM_CLIP },
+
+	/* NetBSD sync/async serial PPP (or Cisco HDLC) */
+	{ DLT_PPP_SERIAL,	LINKTYPE_PPP_HDLC },
+
+	/* NetBSD PPP over Ethernet */
+	{ DLT_PPP_ETHER,	LINKTYPE_PPP_ETHER },
+
+	/*
+	 * All LINKTYPE_ values between LINKTYPE_MATCHING_MIN
+	 * and LINKTYPE_MATCHING_MAX are mapped to identical
+	 * DLT_ values.
+	 */
+
+	{ -1,			-1 }
+};
+
+int
+dlt_to_linktype(int dlt)
+{
+	int i;
+
+	/*
+	 * DLTs that, on some platforms, have values in the matching range
+	 * but that *don't* have the same value as the corresponding
+	 * LINKTYPE because, for some reason, not all OSes have the
+	 * same value for that DLT (note that the DLT's value might be
+	 * outside the matching range on some of those OSes).
+	 */
+	if (dlt == DLT_PFSYNC)
+		return (LINKTYPE_PFSYNC);
+	if (dlt == DLT_PKTAP)
+		return (LINKTYPE_PKTAP);
+
+	/*
+	 * For all other values in the matching range, the DLT
+	 * value is the same as the LINKTYPE value.
+	 */
+	if (dlt >= DLT_MATCHING_MIN && dlt <= DLT_MATCHING_MAX)
+		return (dlt);
+
+	/*
+	 * Map the values outside that range.
+	 */
+	for (i = 0; map[i].dlt != -1; i++) {
+		if (map[i].dlt == dlt)
+			return (map[i].linktype);
+	}
+
+	/*
+	 * If we don't have a mapping for this DLT, return an
+	 * error; that means that this is a value with no corresponding
+	 * LINKTYPE, and we need to assign one.
+	 */
+	return (-1);
+}
+
+int
+linktype_to_dlt(int linktype)
+{
+	int i;
+
+	/*
+	 * LINKTYPEs in the matching range that *don't*
+	 * have the same value as the corresponding DLTs
+	 * because, for some reason, not all OSes have the
+	 * same value for that DLT.
+	 */
+	if (linktype == LINKTYPE_PFSYNC)
+		return (DLT_PFSYNC);
+	if (linktype == LINKTYPE_PKTAP)
+		return (DLT_PKTAP);
+
+	/*
+	 * For all other values in the matching range, except for
+	 * LINKTYPE_ATM_CLIP, the LINKTYPE value is the same as
+	 * the DLT value.
+	 *
+	 * LINKTYPE_ATM_CLIP is a special case.  DLT_ATM_CLIP is
+	 * not on all platforms, but, so far, there don't appear
+	 * to be any platforms that define it as anything other
+	 * than 19; we define LINKTYPE_ATM_CLIP as something
+	 * other than 19, just in case.  That value is in the
+	 * matching range, so we have to check for it.
+	 */
+	if (linktype >= LINKTYPE_MATCHING_MIN &&
+	    linktype <= LINKTYPE_MATCHING_MAX &&
+	    linktype != LINKTYPE_ATM_CLIP)
+		return (linktype);
+
+	/*
+	 * Map the values outside that range.
+	 */
+	for (i = 0; map[i].linktype != -1; i++) {
+		if (map[i].linktype == linktype)
+			return (map[i].dlt);
+	}
+
+	/*
+	 * If we don't have an entry for this LINKTYPE, return
+	 * the link type value; it may be a DLT from an newer
+	 * version of libpcap.
+	 */
+	return linktype;
+}
+
+/*
+ * Return the maximum snapshot length for a given DLT_ value.
+ *
+ * For most link-layer types, we use MAXIMUM_SNAPLEN.
+ *
+ * For DLT_DBUS, the maximum is 128MiB, as per
+ *
+ *    https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ *
+ * For DLT_EBHSCR, the maximum is 8MiB, as per
+ *
+ *    https://www.elektrobit.com/ebhscr
+ *
+ * For DLT_USBPCAP, the maximum is 1MiB, as per
+ *
+ *    https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=15985
+ */
+u_int
+max_snaplen_for_dlt(int dlt)
+{
+	switch (dlt) {
+
+	case DLT_DBUS:
+		return 128*1024*1024;
+
+	case DLT_EBHSCR:
+		return 8*1024*1024;
+
+	case DLT_USBPCAP:
+		return 1024*1024;
+
+	default:
+		return MAXIMUM_SNAPLEN;
+	}
+}
+
+/*
+ * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or
+ * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload,
+ * with the CAN ID being in host byte order.
+ *
+ * When reading a DLT_LINUX_SLL capture file, we need to check for those
+ * packets and convert the CAN ID from the byte order of the host that
+ * wrote the file to this host's byte order.
+ */
+static void
+swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+	u_int caplen = hdr->caplen;
+	u_int length = hdr->len;
+	struct sll_header *shdr = (struct sll_header *)buf;
+	uint16_t protocol;
+	pcap_can_socketcan_hdr *chdr;
+
+	if (caplen < (u_int) sizeof(struct sll_header) ||
+	    length < (u_int) sizeof(struct sll_header)) {
+		/* Not enough data to have the protocol field */
+		return;
+	}
+
+	protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
+	if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
+		return;
+
+	/*
+	 * SocketCAN packet; fix up the packet's header.
+	 */
+	chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header));
+	if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) ||
+	    length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) {
+		/* Not enough data to have the CAN ID */
+		return;
+	}
+	chdr->can_id = SWAPLONG(chdr->can_id);
+}
+
+/*
+ * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host
+ * byte order when capturing (it's supplied directly from a
+ * memory-mapped buffer shared by the kernel).
+ *
+ * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED capture file,
+ * we need to convert it from the byte order of the host that wrote
+ * the file to this host's byte order.
+ */
+static void
+swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
+    int header_len_64_bytes)
+{
+	pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf;
+	bpf_u_int32 offset = 0;
+
+	/*
+	 * "offset" is the offset *past* the field we're swapping;
+	 * we skip the field *before* checking to make sure
+	 * the captured data length includes the entire field.
+	 */
+
+	/*
+	 * The URB id is a totally opaque value; do we really need to
+	 * convert it to the reading host's byte order???
+	 */
+	offset += 8;			/* skip past id */
+	if (hdr->caplen < offset)
+		return;
+	uhdr->id = SWAPLL(uhdr->id);
+
+	offset += 4;			/* skip past various 1-byte fields */
+
+	offset += 2;			/* skip past bus_id */
+	if (hdr->caplen < offset)
+		return;
+	uhdr->bus_id = SWAPSHORT(uhdr->bus_id);
+
+	offset += 2;			/* skip past various 1-byte fields */
+
+	offset += 8;			/* skip past ts_sec */
+	if (hdr->caplen < offset)
+		return;
+	uhdr->ts_sec = SWAPLL(uhdr->ts_sec);
+
+	offset += 4;			/* skip past ts_usec */
+	if (hdr->caplen < offset)
+		return;
+	uhdr->ts_usec = SWAPLONG(uhdr->ts_usec);
+
+	offset += 4;			/* skip past status */
+	if (hdr->caplen < offset)
+		return;
+	uhdr->status = SWAPLONG(uhdr->status);
+
+	offset += 4;			/* skip past urb_len */
+	if (hdr->caplen < offset)
+		return;
+	uhdr->urb_len = SWAPLONG(uhdr->urb_len);
+
+	offset += 4;			/* skip past data_len */
+	if (hdr->caplen < offset)
+		return;
+	uhdr->data_len = SWAPLONG(uhdr->data_len);
+
+	if (uhdr->transfer_type == URB_ISOCHRONOUS) {
+		offset += 4;			/* skip past s.iso.error_count */
+		if (hdr->caplen < offset)
+			return;
+		uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count);
+
+		offset += 4;			/* skip past s.iso.numdesc */
+		if (hdr->caplen < offset)
+			return;
+		uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc);
+	} else
+		offset += 8;			/* skip USB setup header */
+
+	/*
+	 * With the old header, there are no isochronous descriptors
+	 * after the header.
+	 *
+	 * With the new header, the actual number of descriptors in
+	 * the header is not s.iso.numdesc, it's ndesc - only the
+	 * first N descriptors, for some value of N, are put into
+	 * the header, and ndesc is set to the actual number copied.
+	 * In addition, if s.iso.numdesc is negative, no descriptors
+	 * are captured, and ndesc is set to 0.
+	 */
+	if (header_len_64_bytes) {
+		/*
+		 * This is either the "version 1" header, with
+		 * 16 bytes of additional fields at the end, or
+		 * a "version 0" header from a memory-mapped
+		 * capture, with 16 bytes of zeroed-out padding
+		 * at the end.  Byte swap them as if this were
+		 * a "version 1" header.
+		 */
+		offset += 4;			/* skip past interval */
+		if (hdr->caplen < offset)
+			return;
+		uhdr->interval = SWAPLONG(uhdr->interval);
+
+		offset += 4;			/* skip past start_frame */
+		if (hdr->caplen < offset)
+			return;
+		uhdr->start_frame = SWAPLONG(uhdr->start_frame);
+
+		offset += 4;			/* skip past xfer_flags */
+		if (hdr->caplen < offset)
+			return;
+		uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags);
+
+		offset += 4;			/* skip past ndesc */
+		if (hdr->caplen < offset)
+			return;
+		uhdr->ndesc = SWAPLONG(uhdr->ndesc);
+
+		if (uhdr->transfer_type == URB_ISOCHRONOUS) {
+			/* swap the values in struct linux_usb_isodesc */
+			usb_isodesc *pisodesc;
+			uint32_t i;
+
+			pisodesc = (usb_isodesc *)(void *)(buf+offset);
+			for (i = 0; i < uhdr->ndesc; i++) {
+				offset += 4;		/* skip past status */
+				if (hdr->caplen < offset)
+					return;
+				pisodesc->status = SWAPLONG(pisodesc->status);
+
+				offset += 4;		/* skip past offset */
+				if (hdr->caplen < offset)
+					return;
+				pisodesc->offset = SWAPLONG(pisodesc->offset);
+
+				offset += 4;		/* skip past len */
+				if (hdr->caplen < offset)
+					return;
+				pisodesc->len = SWAPLONG(pisodesc->len);
+
+				offset += 4;		/* skip past padding */
+
+				pisodesc++;
+			}
+		}
+	}
+}
+
+/*
+ * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order
+ * data.  They begin with a fixed-length header with big-endian fields,
+ * followed by a set of TLVs, where the type and length are in host
+ * byte order but the values are either big-endian or are a raw byte
+ * sequence that's the same regardless of the host's byte order.
+ *
+ * When reading a DLT_NFLOG capture file, we need to convert the type
+ * and length values from the byte order of the host that wrote the
+ * file to the byte order of this host.
+ */
+static void
+swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+	u_char *p = buf;
+	nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf;
+	nflog_tlv_t *tlv;
+	u_int caplen = hdr->caplen;
+	u_int length = hdr->len;
+	uint16_t size;
+
+	if (caplen < (u_int) sizeof(nflog_hdr_t) ||
+	    length < (u_int) sizeof(nflog_hdr_t)) {
+		/* Not enough data to have any TLVs. */
+		return;
+	}
+
+	if (nfhdr->nflog_version != 0) {
+		/* Unknown NFLOG version */
+		return;
+	}
+
+	length -= sizeof(nflog_hdr_t);
+	caplen -= sizeof(nflog_hdr_t);
+	p += sizeof(nflog_hdr_t);
+
+	while (caplen >= sizeof(nflog_tlv_t)) {
+		tlv = (nflog_tlv_t *) p;
+
+		/* Swap the type and length. */
+		tlv->tlv_type = SWAPSHORT(tlv->tlv_type);
+		tlv->tlv_length = SWAPSHORT(tlv->tlv_length);
+
+		/* Get the length of the TLV. */
+		size = tlv->tlv_length;
+		if (size % 4 != 0)
+			size += 4 - size % 4;
+
+		/* Is the TLV's length less than the minimum? */
+		if (size < sizeof(nflog_tlv_t)) {
+			/* Yes. Give up now. */
+			return;
+		}
+
+		/* Do we have enough data for the full TLV? */
+		if (caplen < size || length < size) {
+			/* No. */
+			return;
+		}
+
+		/* Skip over the TLV. */
+		length -= size;
+		caplen -= size;
+		p += size;
+	}
+}
+
+void
+swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
+{
+	/*
+	 * Convert pseudo-headers from the byte order of
+	 * the host on which the file was saved to our
+	 * byte order, as necessary.
+	 */
+	switch (linktype) {
+
+	case DLT_LINUX_SLL:
+		swap_linux_sll_header(hdr, data);
+		break;
+
+	case DLT_USB_LINUX:
+		swap_linux_usb_header(hdr, data, 0);
+		break;
+
+	case DLT_USB_LINUX_MMAPPED:
+		swap_linux_usb_header(hdr, data, 1);
+		break;
+
+	case DLT_NFLOG:
+		swap_nflog_header(hdr, data);
+		break;
+	}
+}
diff --git a/pcap-common.h b/pcap-common.h
new file mode 100644
index 0000000..8795a82
--- /dev/null
+++ b/pcap-common.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-common.h - common code for pcap and pcapng files
+ */
+
+/*
+ * We use the "receiver-makes-right" approach to byte order,
+ * because time is at a premium when we are writing the file.
+ * In other words, the pcap_file_header and pcap_pkthdr,
+ * records are written in host byte order.
+ * Note that the bytes of packet data are written out in the order in
+ * which they were received, so multi-byte fields in packets are not
+ * written in host byte order, they're written in whatever order the
+ * sending machine put them in.
+ *
+ * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
+ * machine (if the file was written in little-end order).
+ */
+#define	SWAPLONG(y) \
+    (((((u_int)(y))&0xff)<<24) | \
+     ((((u_int)(y))&0xff00)<<8) | \
+     ((((u_int)(y))&0xff0000)>>8) | \
+     ((((u_int)(y))>>24)&0xff))
+#define	SWAPSHORT(y) \
+     ((u_short)(((((u_int)(y))&0xff)<<8) | \
+                ((((u_int)(y))&0xff00)>>8)))
+
+extern int dlt_to_linktype(int dlt);
+
+extern int linktype_to_dlt(int linktype);
+
+extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr,
+    u_char *data);
+
+extern u_int max_snaplen_for_dlt(int dlt);
diff --git a/pcap-int.h b/pcap-int.h
new file mode 100644
index 0000000..dc18d50
--- /dev/null
+++ b/pcap-int.h
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef pcap_int_h
+#define	pcap_int_h
+
+#include <stddef.h>
+
+#include <signal.h>
+
+#include <pcap/pcap.h>
+
+#ifdef MSDOS
+  #include <fcntl.h>
+  #include <io.h>
+#endif
+
+#include "varattrs.h"
+#include "fmtutils.h"
+
+#include <stdarg.h>
+
+#include "portability.h"
+
+/*
+ * Version string.
+ * Uses PACKAGE_VERSION from config.h.
+ */
+#define PCAP_VERSION_STRING "libpcap version " PACKAGE_VERSION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * If pcap_new_api is set, we disable pcap_lookupdev(), because:
+ *
+ *    it's not thread-safe, and is marked as deprecated, on all
+ *    platforms;
+ *
+ *    on Windows, it may return UTF-16LE strings, which the program
+ *    might then pass to pcap_create() (or to pcap_open_live(), which
+ *    then passes them to pcap_create()), requiring pcap_create() to
+ *    check for UTF-16LE strings using a hack, and that hack 1)
+ *    *cannot* be 100% reliable and 2) runs the risk of going past the
+ *    end of the string.
+ *
+ * We keep it around in legacy mode for compatibility.
+ *
+ * We also disable the aforementioned hack in pcap_create().
+ */
+extern int pcap_new_api;
+
+/*
+ * If pcap_utf_8_mode is set, on Windows we treat strings as UTF-8.
+ *
+ * On UN*Xes, we assume all strings are and should be in UTF-8, regardless
+ * of the setting of this flag.
+ */
+extern int pcap_utf_8_mode;
+
+/*
+ * Swap byte ordering of unsigned long long timestamp on a big endian
+ * machine.
+ */
+#define SWAPLL(ull)  ((ull & 0xff00000000000000ULL) >> 56) | \
+                      ((ull & 0x00ff000000000000ULL) >> 40) | \
+                      ((ull & 0x0000ff0000000000ULL) >> 24) | \
+                      ((ull & 0x000000ff00000000ULL) >> 8)  | \
+                      ((ull & 0x00000000ff000000ULL) << 8)  | \
+                      ((ull & 0x0000000000ff0000ULL) << 24) | \
+                      ((ull & 0x000000000000ff00ULL) << 40) | \
+                      ((ull & 0x00000000000000ffULL) << 56)
+
+/*
+ * Maximum snapshot length.
+ *
+ * Somewhat arbitrary, but chosen to be:
+ *
+ *    1) big enough for maximum-size Linux loopback packets (65549)
+ *       and some USB packets captured with USBPcap:
+ *
+ *           https://desowin.org/usbpcap/
+ *
+ *       (> 131072, < 262144)
+ *
+ * and
+ *
+ *    2) small enough not to cause attempts to allocate huge amounts of
+ *       memory; some applications might use the snapshot length in a
+ *       savefile header to control the size of the buffer they allocate,
+ *       so a size of, say, 2^31-1 might not work well.  (libpcap uses it
+ *       as a hint, but doesn't start out allocating a buffer bigger than
+ *       2 KiB, and grows the buffer as necessary, but not beyond the
+ *       per-linktype maximum snapshot length.  Other code might naively
+ *       use it; we want to avoid writing a too-large snapshot length,
+ *       in order not to cause that code problems.)
+ *
+ * We don't enforce this in pcap_set_snaplen(), but we use it internally.
+ */
+#define MAXIMUM_SNAPLEN		262144
+
+/*
+ * Locale-independent macros for testing character types.
+ * These can be passed any integral value, without worrying about, for
+ * example, sign-extending char values, unlike the C macros.
+ */
+#define PCAP_ISDIGIT(c) \
+	((c) >= '0' && (c) <= '9')
+#define PCAP_ISXDIGIT(c) \
+	(((c) >= '0' && (c) <= '9') || \
+	 ((c) >= 'A' && (c) <= 'F') || \
+	 ((c) >= 'a' && (c) <= 'f'))
+
+struct pcap_opt {
+	char	*device;
+	int	timeout;	/* timeout for buffering */
+	u_int	buffer_size;
+	int	promisc;
+	int	rfmon;		/* monitor mode */
+	int	immediate;	/* immediate mode - deliver packets as soon as they arrive */
+	int	nonblock;	/* non-blocking mode - don't wait for packets to be delivered, return "no packets available" */
+	int	tstamp_type;
+	int	tstamp_precision;
+
+	/*
+	 * Platform-dependent options.
+	 */
+#ifdef __linux__
+	int	protocol;	/* protocol to use when creating PF_PACKET socket */
+#endif
+#ifdef _WIN32
+	int	nocapture_local;/* disable NPF loopback */
+#endif
+};
+
+typedef int	(*activate_op_t)(pcap_t *);
+typedef int	(*can_set_rfmon_op_t)(pcap_t *);
+typedef int	(*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *);
+typedef int	(*next_packet_op_t)(pcap_t *, struct pcap_pkthdr *, u_char **);
+typedef int	(*inject_op_t)(pcap_t *, const void *, int);
+typedef void	(*save_current_filter_op_t)(pcap_t *, const char *);
+typedef int	(*setfilter_op_t)(pcap_t *, struct bpf_program *);
+typedef int	(*setdirection_op_t)(pcap_t *, pcap_direction_t);
+typedef int	(*set_datalink_op_t)(pcap_t *, int);
+typedef int	(*getnonblock_op_t)(pcap_t *);
+typedef int	(*setnonblock_op_t)(pcap_t *, int);
+typedef int	(*stats_op_t)(pcap_t *, struct pcap_stat *);
+typedef void	(*breakloop_op_t)(pcap_t *);
+#ifdef _WIN32
+typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *);
+typedef int	(*setbuff_op_t)(pcap_t *, int);
+typedef int	(*setmode_op_t)(pcap_t *, int);
+typedef int	(*setmintocopy_op_t)(pcap_t *, int);
+typedef HANDLE	(*getevent_op_t)(pcap_t *);
+typedef int	(*oid_get_request_op_t)(pcap_t *, bpf_u_int32, void *, size_t *);
+typedef int	(*oid_set_request_op_t)(pcap_t *, bpf_u_int32, const void *, size_t *);
+typedef u_int	(*sendqueue_transmit_op_t)(pcap_t *, pcap_send_queue *, int);
+typedef int	(*setuserbuffer_op_t)(pcap_t *, int);
+typedef int	(*live_dump_op_t)(pcap_t *, char *, int, int);
+typedef int	(*live_dump_ended_op_t)(pcap_t *, int);
+typedef PAirpcapHandle	(*get_airpcap_handle_op_t)(pcap_t *);
+#endif
+typedef void	(*cleanup_op_t)(pcap_t *);
+
+/*
+ * We put all the stuff used in the read code path at the beginning,
+ * to try to keep it together in the same cache line or lines.
+ */
+struct pcap {
+	/*
+	 * Method to call to read packets on a live capture.
+	 */
+	read_op_t read_op;
+
+	/*
+	 * Method to call to read the next packet from a savefile.
+	 */
+	next_packet_op_t next_packet_op;
+
+#ifdef _WIN32
+	HANDLE handle;
+#else
+	int fd;
+#endif /* _WIN32 */
+
+	/*
+	 * Read buffer.
+	 */
+	u_int bufsize;
+	void *buffer;
+	u_char *bp;
+	int cc;
+
+	sig_atomic_t break_loop; /* flag set to force break from packet-reading loop */
+
+	void *priv;		/* private data for methods */
+
+#ifdef ENABLE_REMOTE
+	struct pcap_samp rmt_samp;	/* parameters related to the sampling process. */
+#endif
+
+	int swapped;
+	FILE *rfile;		/* null if live capture, non-null if savefile */
+	u_int fddipad;
+	struct pcap *next;	/* list of open pcaps that need stuff cleared on close */
+
+	/*
+	 * File version number; meaningful only for a savefile, but we
+	 * keep it here so that apps that (mistakenly) ask for the
+	 * version numbers will get the same zero values that they
+	 * always did.
+	 */
+	int version_major;
+	int version_minor;
+
+	int snapshot;
+	int linktype;		/* Network linktype */
+	int linktype_ext;	/* Extended information stored in the linktype field of a file */
+	int offset;		/* offset for proper alignment */
+	int activated;		/* true if the capture is really started */
+	int oldstyle;		/* if we're opening with pcap_open_live() */
+
+	struct pcap_opt opt;
+
+	/*
+	 * Place holder for pcap_next().
+	 */
+	u_char *pkt;
+
+#ifdef _WIN32
+	struct pcap_stat stat;	/* used for pcap_stats_ex() */
+#endif
+
+	/* We're accepting only packets in this direction/these directions. */
+	pcap_direction_t direction;
+
+	/*
+	 * Flags to affect BPF code generation.
+	 */
+	int bpf_codegen_flags;
+
+#if !defined(_WIN32) && !defined(MSDOS)
+	int selectable_fd;	/* FD on which select()/poll()/epoll_wait()/kevent()/etc. can be done */
+
+	/*
+	 * In case there either is no selectable FD, or there is but
+	 * it doesn't necessarily work (e.g., if it doesn't get notified
+	 * if the packet capture timeout expires before the buffer
+	 * fills up), this points to a timeout that should be used
+	 * in select()/poll()/epoll_wait()/kevent() call.  The pcap_t should
+	 * be put into non-blocking mode, and, if the timeout expires on
+	 * the call, an attempt should be made to read packets from all
+	 * pcap_t's with a required timeout, and the code must be
+	 * prepared not to see any packets from the attempt.
+	 */
+	const struct timeval *required_select_timeout;
+#endif
+
+	/*
+	 * Placeholder for filter code if bpf not in kernel.
+	 */
+	struct bpf_program fcode;
+
+	char errbuf[PCAP_ERRBUF_SIZE + 1];
+#ifdef _WIN32
+	char acp_errbuf[PCAP_ERRBUF_SIZE + 1];	/* buffer for local code page error strings */
+#endif
+	int dlt_count;
+	u_int *dlt_list;
+	int tstamp_type_count;
+	u_int *tstamp_type_list;
+	int tstamp_precision_count;
+	u_int *tstamp_precision_list;
+
+	struct pcap_pkthdr pcap_header;	/* This is needed for the pcap_next_ex() to work */
+
+	/*
+	 * More methods.
+	 */
+	activate_op_t activate_op;
+	can_set_rfmon_op_t can_set_rfmon_op;
+	inject_op_t inject_op;
+	save_current_filter_op_t save_current_filter_op;
+	setfilter_op_t setfilter_op;
+	setdirection_op_t setdirection_op;
+	set_datalink_op_t set_datalink_op;
+	getnonblock_op_t getnonblock_op;
+	setnonblock_op_t setnonblock_op;
+	stats_op_t stats_op;
+	breakloop_op_t breakloop_op;
+
+	/*
+	 * Routine to use as callback for pcap_next()/pcap_next_ex().
+	 */
+	pcap_handler oneshot_callback;
+
+#ifdef _WIN32
+	/*
+	 * These are, at least currently, specific to the Win32 NPF
+	 * driver.
+	 */
+	stats_ex_op_t stats_ex_op;
+	setbuff_op_t setbuff_op;
+	setmode_op_t setmode_op;
+	setmintocopy_op_t setmintocopy_op;
+	getevent_op_t getevent_op;
+	oid_get_request_op_t oid_get_request_op;
+	oid_set_request_op_t oid_set_request_op;
+	sendqueue_transmit_op_t sendqueue_transmit_op;
+	setuserbuffer_op_t setuserbuffer_op;
+	live_dump_op_t live_dump_op;
+	live_dump_ended_op_t live_dump_ended_op;
+	get_airpcap_handle_op_t get_airpcap_handle_op;
+#endif
+	cleanup_op_t cleanup_op;
+};
+
+/*
+ * BPF code generation flags.
+ */
+#define BPF_SPECIAL_VLAN_HANDLING	0x00000001	/* special VLAN handling for Linux */
+
+/*
+ * This is a timeval as stored in a savefile.
+ * It has to use the same types everywhere, independent of the actual
+ * `struct timeval'; `struct timeval' has 32-bit tv_sec values on some
+ * platforms and 64-bit tv_sec values on other platforms, and writing
+ * out native `struct timeval' values would mean files could only be
+ * read on systems with the same tv_sec size as the system on which
+ * the file was written.
+ */
+
+struct pcap_timeval {
+    bpf_int32 tv_sec;		/* seconds */
+    bpf_int32 tv_usec;		/* microseconds */
+};
+
+/*
+ * This is a `pcap_pkthdr' as actually stored in a savefile.
+ *
+ * Do not change the format of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure),
+ * and do not make the time stamp anything other than seconds and
+ * microseconds (e.g., seconds and nanoseconds).  Instead:
+ *
+ *	introduce a new structure for the new format;
+ *
+ *	send mail to "tcpdump-workers@lists.tcpdump.org", requesting
+ *	a new magic number for your new capture file format, and, when
+ *	you get the new magic number, put it in "savefile.c";
+ *
+ *	use that magic number for save files with the changed record
+ *	header;
+ *
+ *	make the code in "savefile.c" capable of reading files with
+ *	the old record header as well as files with the new record header
+ *	(using the magic number to determine the header format).
+ *
+ * Then supply the changes by forking the branch at
+ *
+ *	https://github.com/the-tcpdump-group/libpcap/tree/master
+ *
+ * and issuing a pull request, so that future versions of libpcap and
+ * programs that use it (such as tcpdump) will be able to read your new
+ * capture file format.
+ */
+
+struct pcap_sf_pkthdr {
+    struct pcap_timeval ts;	/* time stamp */
+    bpf_u_int32 caplen;		/* length of portion present */
+    bpf_u_int32 len;		/* length of this packet (off wire) */
+};
+
+/*
+ * How a `pcap_pkthdr' is actually stored in savefiles written
+ * by some patched versions of libpcap (e.g. the ones in Red
+ * Hat Linux 6.1 and 6.2).
+ *
+ * Do not change the format of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure).
+ * Instead, introduce a new structure, as per the above.
+ */
+
+struct pcap_sf_patched_pkthdr {
+    struct pcap_timeval ts;	/* time stamp */
+    bpf_u_int32 caplen;		/* length of portion present */
+    bpf_u_int32 len;		/* length of this packet (off wire) */
+    int		index;
+    unsigned short protocol;
+    unsigned char pkt_type;
+};
+
+/*
+ * User data structure for the one-shot callback used for pcap_next()
+ * and pcap_next_ex().
+ */
+struct oneshot_userdata {
+	struct pcap_pkthdr *hdr;
+	const u_char **pkt;
+	pcap_t *pd;
+};
+
+#ifndef min
+#define min(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+int	pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
+
+/*
+ * Does the packet count argument to a module's read routine say
+ * "supply packets until you run out of packets"?
+ */
+#define PACKET_COUNT_IS_UNLIMITED(count)	((count) <= 0)
+
+/*
+ * Routines that most pcap implementations can use for non-blocking mode.
+ */
+#if !defined(_WIN32) && !defined(MSDOS)
+int	pcap_getnonblock_fd(pcap_t *);
+int	pcap_setnonblock_fd(pcap_t *p, int);
+#endif
+
+/*
+ * Internal interfaces for "pcap_create()".
+ *
+ * "pcap_create_interface()" is the routine to do a pcap_create on
+ * a regular network interface.  There are multiple implementations
+ * of this, one for each platform type (Linux, BPF, DLPI, etc.),
+ * with the one used chosen by the configure script.
+ *
+ * "pcap_create_common()" allocates and fills in a pcap_t, for use
+ * by pcap_create routines.
+ */
+pcap_t	*pcap_create_interface(const char *, char *);
+
+/*
+ * This wrapper takes an error buffer pointer and a type to use for the
+ * private data, and calls pcap_create_common(), passing it the error
+ * buffer pointer, the size fo the private data type, in bytes, and the
+ * offset of the private data from the beginning of the structure, in
+ * bytes.
+ */
+#define PCAP_CREATE_COMMON(ebuf, type) \
+	pcap_create_common(ebuf, \
+	    sizeof (struct { pcap_t __common; type __private; }), \
+	    offsetof (struct { pcap_t __common; type __private; }, __private))
+pcap_t	*pcap_create_common(char *, size_t, size_t);
+int	pcap_do_addexit(pcap_t *);
+void	pcap_add_to_pcaps_to_close(pcap_t *);
+void	pcap_remove_from_pcaps_to_close(pcap_t *);
+void	pcap_cleanup_live_common(pcap_t *);
+int	pcap_check_activated(pcap_t *);
+void	pcap_breakloop_common(pcap_t *);
+
+/*
+ * Internal interfaces for "pcap_findalldevs()".
+ *
+ * A pcap_if_list_t * is a reference to a list of devices.
+ *
+ * A get_if_flags_func is a platform-dependent function called to get
+ * additional interface flags.
+ *
+ * "pcap_platform_finddevs()" is the platform-dependent routine to
+ * find local network interfaces.
+ *
+ * "pcap_findalldevs_interfaces()" is a helper to find those interfaces
+ * using the "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.).
+ *
+ * "add_dev()" adds an entry to a pcap_if_list_t.
+ *
+ * "find_dev()" tries to find a device, by name, in a pcap_if_list_t.
+ *
+ * "find_or_add_dev()" checks whether a device is already in a pcap_if_list_t
+ * and, if not, adds an entry for it.
+ */
+struct pcap_if_list;
+typedef struct pcap_if_list pcap_if_list_t;
+typedef int (*get_if_flags_func)(const char *, bpf_u_int32 *, char *);
+int	pcap_platform_finddevs(pcap_if_list_t *, char *);
+#if !defined(_WIN32) && !defined(MSDOS)
+int	pcap_findalldevs_interfaces(pcap_if_list_t *, char *,
+	    int (*)(const char *), get_if_flags_func);
+#endif
+pcap_if_t *find_or_add_dev(pcap_if_list_t *, const char *, bpf_u_int32,
+	    get_if_flags_func, const char *, char *);
+pcap_if_t *find_dev(pcap_if_list_t *, const char *);
+pcap_if_t *add_dev(pcap_if_list_t *, const char *, bpf_u_int32, const char *,
+	    char *);
+int	add_addr_to_dev(pcap_if_t *, struct sockaddr *, size_t,
+	    struct sockaddr *, size_t, struct sockaddr *, size_t,
+	    struct sockaddr *dstaddr, size_t, char *errbuf);
+#ifndef _WIN32
+pcap_if_t *find_or_add_if(pcap_if_list_t *, const char *, bpf_u_int32,
+	    get_if_flags_func, char *);
+int	add_addr_to_if(pcap_if_list_t *, const char *, bpf_u_int32,
+	    get_if_flags_func,
+	    struct sockaddr *, size_t, struct sockaddr *, size_t,
+	    struct sockaddr *, size_t, struct sockaddr *, size_t, char *);
+#endif
+
+/*
+ * Internal interfaces for "pcap_open_offline()" and other savefile
+ * I/O routines.
+ *
+ * "pcap_open_offline_common()" allocates and fills in a pcap_t, for use
+ * by pcap_open_offline routines.
+ *
+ * "pcap_adjust_snapshot()" adjusts the snapshot to be non-zero and
+ * fit within an int.
+ *
+ * "sf_cleanup()" closes the file handle associated with a pcap_t, if
+ * appropriate, and frees all data common to all modules for handling
+ * savefile types.
+ *
+ * "charset_fopen()", in UTF-8 mode on Windows, does an fopen() that
+ * treats the pathname as being in UTF-8, rather than the local
+ * code page, on Windows.
+ */
+
+/*
+ * This wrapper takes an error buffer pointer and a type to use for the
+ * private data, and calls pcap_create_common(), passing it the error
+ * buffer pointer, the size fo the private data type, in bytes, and the
+ * offset of the private data from the beginning of the structure, in
+ * bytes.
+ */
+#define PCAP_OPEN_OFFLINE_COMMON(ebuf, type) \
+	pcap_open_offline_common(ebuf, \
+	    sizeof (struct { pcap_t __common; type __private; }), \
+	    offsetof (struct { pcap_t __common; type __private; }, __private))
+pcap_t	*pcap_open_offline_common(char *ebuf, size_t total_size,
+    size_t private_data);
+bpf_u_int32 pcap_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen);
+void	sf_cleanup(pcap_t *p);
+#ifdef _WIN32
+FILE	*charset_fopen(const char *path, const char *mode);
+#else
+/*
+ * On other OSes, just use Boring Old fopen().
+ */
+#define charset_fopen(path, mode)	fopen((path), (mode))
+#endif
+
+/*
+ * Internal interfaces for loading code at run time.
+ */
+#ifdef _WIN32
+#define pcap_code_handle_t	HMODULE
+#define pcap_funcptr_t		FARPROC
+
+pcap_code_handle_t	pcap_load_code(const char *);
+pcap_funcptr_t		pcap_find_function(pcap_code_handle_t, const char *);
+#endif
+
+/*
+ * Internal interfaces for doing user-mode filtering of packets and
+ * validating filter programs.
+ */
+/*
+ * Auxiliary data, for use when interpreting a filter intended for the
+ * Linux kernel when the kernel rejects the filter (requiring us to
+ * run it in userland).  It contains VLAN tag information.
+ */
+struct pcap_bpf_aux_data {
+	u_short vlan_tag_present;
+	u_short vlan_tag;
+};
+
+/*
+ * Filtering routine that takes the auxiliary data as an additional
+ * argument.
+ */
+u_int	pcap_filter_with_aux_data(const struct bpf_insn *,
+    const u_char *, u_int, u_int, const struct pcap_bpf_aux_data *);
+
+/*
+ * Filtering routine that doesn't.
+ */
+u_int	pcap_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+
+/*
+ * Routine to validate a BPF program.
+ */
+int	pcap_validate_filter(const struct bpf_insn *, int);
+
+/*
+ * Internal interfaces for both "pcap_create()" and routines that
+ * open savefiles.
+ *
+ * "pcap_oneshot()" is the standard one-shot callback for "pcap_next()"
+ * and "pcap_next_ex()".
+ */
+void	pcap_oneshot(u_char *, const struct pcap_pkthdr *, const u_char *);
+
+int	install_bpf_program(pcap_t *, struct bpf_program *);
+
+int	pcap_strcasecmp(const char *, const char *);
+
+/*
+ * Internal interfaces for pcap_createsrcstr and pcap_parsesrcstr with
+ * the additional bit of information regarding SSL support (rpcap:// vs.
+ * rpcaps://).
+ */
+int	pcap_createsrcstr_ex(char *, int, const char *, const char *,
+    const char *, unsigned char, char *);
+int	pcap_parsesrcstr_ex(const char *, int *, char *, char *,
+    char *, unsigned char *, char *);
+
+#ifdef YYDEBUG
+extern int pcap_debug;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pcap-namedb.h b/pcap-namedb.h
new file mode 100644
index 0000000..d5908c9
--- /dev/null
+++ b/pcap-namedb.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1994, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * For backwards compatibility.
+ *
+ * Note to OS vendors: do NOT get rid of this file!  Some applications
+ * might expect to be able to include <pcap-namedb.h>.
+ */
+#include <pcap/namedb.h>
diff --git a/pcap-null.c b/pcap-null.c
new file mode 100644
index 0000000..2ae27bf
--- /dev/null
+++ b/pcap-null.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "pcap-int.h"
+
+static char nosup[] = "live packet capture not supported on this system";
+
+pcap_t *
+pcap_create_interface(const char *device _U_, char *ebuf)
+{
+	(void)pcap_strlcpy(ebuf, nosup, PCAP_ERRBUF_SIZE);
+	return (NULL);
+}
+
+int
+pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf _U_)
+{
+	/*
+	 * There are no interfaces on which we can capture.
+	 */
+	return (0);
+}
+
+#ifdef _WIN32
+int
+pcap_lookupnet(const char *device _U_, bpf_u_int32 *netp _U_,
+    bpf_u_int32 *maskp _U_, char *errbuf)
+{
+	(void)pcap_strlcpy(errbuf, nosup, PCAP_ERRBUF_SIZE);
+	return (-1);
+}
+#endif
+
+/*
+ * Libpcap version string.
+ */
+const char *
+pcap_lib_version(void)
+{
+	return (PCAP_VERSION_STRING);
+}
diff --git a/pcap-types.h b/pcap-types.h
new file mode 100644
index 0000000..7d0fe81
--- /dev/null
+++ b/pcap-types.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef pcap_types_h
+#define pcap_types_h
+
+/*
+ * Get u_int defined, by hook or by crook.
+ */
+#ifdef _WIN32
+  /*
+   * This defines u_int.
+   */
+  #include <winsock2.h>
+#else /* _WIN32 */
+  /*
+   * This defines u_int, among other types.
+   */
+  #include <sys/types.h>
+#endif
+
+#endif /* pcap_types_h */
diff --git a/pcap.c b/pcap.c
new file mode 100644
index 0000000..ed8570a
--- /dev/null
+++ b/pcap.c
@@ -0,0 +1,4434 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#ifndef MSDOS
+#include <sys/file.h>
+#endif
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+
+struct mbuf;		/* Squelch compiler warnings on some platforms for */
+struct rtentry;		/* declarations in <net/if.h> */
+#include <net/if.h>
+#include <netinet/in.h>
+#endif /* _WIN32 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__)
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "diag-control.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef MSDOS
+#include "pcap-dos.h"
+#endif
+
+#include "pcap-int.h"
+
+#include "optimize.h"
+
+#ifdef HAVE_DAG_API
+#include "pcap-dag.h"
+#endif /* HAVE_DAG_API */
+
+#ifdef HAVE_SEPTEL_API
+#include "pcap-septel.h"
+#endif /* HAVE_SEPTEL_API */
+
+#ifdef HAVE_SNF_API
+#include "pcap-snf.h"
+#endif /* HAVE_SNF_API */
+
+#ifdef HAVE_TC_API
+#include "pcap-tc.h"
+#endif /* HAVE_TC_API */
+
+#ifdef PCAP_SUPPORT_LINUX_USBMON
+#include "pcap-usb-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_BT
+#include "pcap-bt-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_BT_MONITOR
+#include "pcap-bt-monitor-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_NETFILTER
+#include "pcap-netfilter-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_NETMAP
+#include "pcap-netmap.h"
+#endif
+
+#ifdef PCAP_SUPPORT_DBUS
+#include "pcap-dbus.h"
+#endif
+
+#ifdef PCAP_SUPPORT_RDMASNIFF
+#include "pcap-rdmasniff.h"
+#endif
+
+#ifdef PCAP_SUPPORT_DPDK
+#include "pcap-dpdk.h"
+#endif
+
+#ifdef HAVE_AIRPCAP_API
+#include "pcap-airpcap.h"
+#endif
+
+#ifdef _WIN32
+/*
+ * DllMain(), required when built as a Windows DLL.
+ *
+ * To quote the WSAStartup() documentation:
+ *
+ *   The WSAStartup function typically leads to protocol-specific helper
+ *   DLLs being loaded. As a result, the WSAStartup function should not
+ *   be called from the DllMain function in a application DLL. This can
+ *   potentially cause deadlocks.
+ *
+ * and the WSACleanup() documentation:
+ *
+ *   The WSACleanup function typically leads to protocol-specific helper
+ *   DLLs being unloaded. As a result, the WSACleanup function should not
+ *   be called from the DllMain function in a application DLL. This can
+ *   potentially cause deadlocks.
+ *
+ * So we don't initialize Winsock here.  pcap_init() should be called
+ * to initialize pcap on both UN*X and Windows; it will initialize
+ * Winsock on Windows.  (It will also be initialized as needed if
+ * pcap_init() hasn't been called.)
+ */
+BOOL WINAPI DllMain(
+  HANDLE hinstDLL _U_,
+  DWORD dwReason _U_,
+  LPVOID lpvReserved _U_
+)
+{
+	return (TRUE);
+}
+
+/*
+ * Start Winsock.
+ * Internal routine.
+ */
+static int
+internal_wsockinit(char *errbuf)
+{
+	WORD wVersionRequested;
+	WSADATA wsaData;
+	static int err = -1;
+	static int done = 0;
+	int status;
+
+	if (done)
+		return (err);
+
+	/*
+	 * Versions of Windows that don't support Winsock 2.2 are
+	 * too old for us.
+	 */
+	wVersionRequested = MAKEWORD(2, 2);
+	status = WSAStartup(wVersionRequested, &wsaData);
+	done = 1;
+	if (status != 0) {
+		if (errbuf != NULL) {
+			pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE,
+			    status, "WSAStartup() failed");
+		}
+		return (err);
+	}
+	atexit ((void(*)(void))WSACleanup);
+	err = 0;
+	return (err);
+}
+
+/*
+ * Exported in case some applications using WinPcap/Npcap called it,
+ * even though it wasn't exported.
+ */
+int
+wsockinit(void)
+{
+	return (internal_wsockinit(NULL));
+}
+
+/*
+ * This is the exported function; new programs should call this.
+ * *Newer* programs should call pcap_init().
+ */
+int
+pcap_wsockinit(void)
+{
+	return (internal_wsockinit(NULL));
+}
+#endif /* _WIN32 */
+
+/*
+ * Do whatever initialization is needed for libpcap.
+ *
+ * The argument specifies whether we use the local code page or UTF-8
+ * for strings; on UN*X, we just assume UTF-8 in places where the encoding
+ * would matter, whereas, on Windows, we use the local code page for
+ * PCAP_CHAR_ENC_LOCAL and UTF-8 for PCAP_CHAR_ENC_UTF_8.
+ *
+ * On Windows, we also disable the hack in pcap_create() to deal with
+ * being handed UTF-16 strings, because if the user calls this they're
+ * explicitly declaring that they will either be passing local code
+ * page strings or UTF-8 strings, so we don't need to allow UTF-16LE
+ * strings to be passed.  For good measure, on Windows *and* UN*X,
+ * we disable pcap_lookupdev(), to prevent anybody from even
+ * *trying* to pass the result of pcap_lookupdev() - which might be
+ * UTF-16LE on Windows, for ugly compatibility reasons - to pcap_create()
+ * or pcap_open_live() or pcap_open().
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int pcap_new_api;		/* pcap_lookupdev() always fails */
+int pcap_utf_8_mode;		/* Strings should be in UTF-8. */
+
+int
+pcap_init(unsigned int opts, char *errbuf)
+{
+	static int initialized;
+
+	/*
+	 * Don't allow multiple calls that set different modes; that
+	 * may mean a library is initializing pcap in one mode and
+	 * a program using that library, or another library used by
+	 * that program, is initializing it in another mode.
+	 */
+	switch (opts) {
+
+	case PCAP_CHAR_ENC_LOCAL:
+		/* Leave "UTF-8 mode" off. */
+		if (initialized) {
+			if (pcap_utf_8_mode) {
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "Multiple pcap_init calls with different character encodings");
+				return (-1);
+			}
+		}
+		break;
+
+	case PCAP_CHAR_ENC_UTF_8:
+		/* Turn on "UTF-8 mode". */
+		if (initialized) {
+			if (!pcap_utf_8_mode) {
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "Multiple pcap_init calls with different character encodings");
+				return (-1);
+			}
+		}
+		pcap_utf_8_mode = 1;
+		break;
+
+	default:
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown options specified");
+		return (-1);
+	}
+
+	/*
+	 * Turn the appropriate mode on for error messages; those routines
+	 * are also used in rpcapd, which has no access to pcap's internal
+	 * UTF-8 mode flag, so we have to call a routine to set its
+	 * UTF-8 mode flag.
+	 */
+	pcap_fmt_set_encoding(opts);
+
+	if (initialized) {
+		/*
+		 * Nothing more to do; for example, on Windows, we've
+		 * already initialized Winsock.
+		 */
+		return (0);
+	}
+
+#ifdef _WIN32
+	/*
+	 * Now set up Winsock.
+	 */
+	if (internal_wsockinit(errbuf) == -1) {
+		/* Failed. */
+		return (-1);
+	}
+#endif
+
+	/*
+	 * We're done.
+	 */
+	initialized = 1;
+	pcap_new_api = 1;
+	return (0);
+}
+
+/*
+ * String containing the library version.
+ * Not explicitly exported via a header file - the right API to use
+ * is pcap_lib_version() - but some programs included it, so we
+ * provide it.
+ *
+ * We declare it here, right before defining it, to squelch any
+ * warnings we might get from compilers about the lack of a
+ * declaration.
+ */
+PCAP_API char pcap_version[];
+PCAP_API_DEF char pcap_version[] = PACKAGE_VERSION;
+
+static void
+pcap_set_not_initialized_message(pcap_t *pcap)
+{
+	if (pcap->activated) {
+		/* A module probably forgot to set the function pointer */
+		(void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+		    "This operation isn't properly handled by that device");
+		return;
+	}
+	/* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
+	(void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+	    "This handle hasn't been activated yet");
+}
+
+static int
+pcap_read_not_initialized(pcap_t *pcap, int cnt _U_, pcap_handler callback _U_,
+    u_char *user _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, int size _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setfilter_not_initialized(pcap_t *pcap, struct bpf_program *fp _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setdirection_not_initialized(pcap_t *pcap, pcap_direction_t d _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_set_datalink_not_initialized(pcap_t *pcap, int dlt _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_getnonblock_not_initialized(pcap_t *pcap)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+#ifdef _WIN32
+static struct pcap_stat *
+pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (NULL);
+}
+
+static int
+pcap_setbuff_not_initialized(pcap_t *pcap, int dim _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmode_not_initialized(pcap_t *pcap, int mode _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmintocopy_not_initialized(pcap_t *pcap, int size _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	/* this means 'not initialized' */
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static HANDLE
+pcap_getevent_not_initialized(pcap_t *pcap)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (INVALID_HANDLE_VALUE);
+}
+
+static int
+pcap_oid_get_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+    void *data _U_, size_t *lenp _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+    const void *data _U_, size_t *lenp _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static u_int
+pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_,
+    int sync _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (0);
+}
+
+static int
+pcap_setuserbuffer_not_initialized(pcap_t *pcap, int size _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_not_initialized(pcap_t *pcap, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_ended_not_initialized(pcap_t *pcap, int sync _U_)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static PAirpcapHandle
+pcap_get_airpcap_handle_not_initialized(pcap_t *pcap)
+{
+	pcap_set_not_initialized_message(pcap);
+	return (NULL);
+}
+#endif
+
+/*
+ * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't,
+ * a PCAP_ERROR value on an error.
+ */
+int
+pcap_can_set_rfmon(pcap_t *p)
+{
+	return (p->can_set_rfmon_op(p));
+}
+
+/*
+ * For systems where rfmon mode is never supported.
+ */
+static int
+pcap_cant_set_rfmon(pcap_t *p _U_)
+{
+	return (0);
+}
+
+/*
+ * Sets *tstamp_typesp to point to an array 1 or more supported time stamp
+ * types; the return value is the number of supported time stamp types.
+ * The list should be freed by a call to pcap_free_tstamp_types() when
+ * you're done with it.
+ *
+ * A return value of 0 means "you don't get a choice of time stamp type",
+ * in which case *tstamp_typesp is set to null.
+ *
+ * PCAP_ERROR is returned on error.
+ */
+int
+pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp)
+{
+	if (p->tstamp_type_count == 0) {
+		/*
+		 * We don't support multiple time stamp types.
+		 * That means the only type we support is PCAP_TSTAMP_HOST;
+		 * set up a list containing only that type.
+		 */
+		*tstamp_typesp = (int*)malloc(sizeof(**tstamp_typesp));
+		if (*tstamp_typesp == NULL) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+			    errno, "malloc");
+			return (PCAP_ERROR);
+		}
+		**tstamp_typesp = PCAP_TSTAMP_HOST;
+		return (1);
+	} else {
+		*tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp),
+		    p->tstamp_type_count);
+		if (*tstamp_typesp == NULL) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+			    errno, "malloc");
+			return (PCAP_ERROR);
+		}
+		(void)memcpy(*tstamp_typesp, p->tstamp_type_list,
+		    sizeof(**tstamp_typesp) * p->tstamp_type_count);
+		return (p->tstamp_type_count);
+	}
+}
+
+/*
+ * In Windows, you might have a library built with one version of the
+ * C runtime library and an application built with another version of
+ * the C runtime library, which means that the library might use one
+ * version of malloc() and free() and the application might use another
+ * version of malloc() and free().  If so, that means something
+ * allocated by the library cannot be freed by the application, so we
+ * need to have a pcap_free_tstamp_types() routine to free up the list
+ * allocated by pcap_list_tstamp_types(), even though it's just a wrapper
+ * around free().
+ */
+void
+pcap_free_tstamp_types(int *tstamp_type_list)
+{
+	free(tstamp_type_list);
+}
+
+/*
+ * Default one-shot callback; overridden for capture types where the
+ * packet data cannot be guaranteed to be available after the callback
+ * returns, so that a copy must be made.
+ */
+void
+pcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt)
+{
+	struct oneshot_userdata *sp = (struct oneshot_userdata *)user;
+
+	*sp->hdr = *h;
+	*sp->pkt = pkt;
+}
+
+const u_char *
+pcap_next(pcap_t *p, struct pcap_pkthdr *h)
+{
+	struct oneshot_userdata s;
+	const u_char *pkt;
+
+	s.hdr = h;
+	s.pkt = &pkt;
+	s.pd = p;
+	if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0)
+		return (0);
+	return (pkt);
+}
+
+int
+pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
+    const u_char **pkt_data)
+{
+	struct oneshot_userdata s;
+
+	s.hdr = &p->pcap_header;
+	s.pkt = pkt_data;
+	s.pd = p;
+
+	/* Saves a pointer to the packet headers */
+	*pkt_header= &p->pcap_header;
+
+	if (p->rfile != NULL) {
+		int status;
+
+		/* We are on an offline capture */
+		status = pcap_offline_read(p, 1, p->oneshot_callback,
+		    (u_char *)&s);
+
+		/*
+		 * Return codes for pcap_offline_read() are:
+		 *   -  0: EOF
+		 *   - -1: error
+		 *   - >1: OK
+		 * The first one ('0') conflicts with the return code of
+		 * 0 from pcap_read() meaning "no packets arrived before
+		 * the timeout expired", so we map it to -2 so you can
+		 * distinguish between an EOF from a savefile and a
+		 * "no packets arrived before the timeout expired, try
+		 * again" from a live capture.
+		 */
+		if (status == 0)
+			return (-2);
+		else
+			return (status);
+	}
+
+	/*
+	 * Return codes for pcap_read() are:
+	 *   -  0: timeout
+	 *   - -1: error
+	 *   - -2: loop was broken out of with pcap_breakloop()
+	 *   - >1: OK
+	 * The first one ('0') conflicts with the return code of 0 from
+	 * pcap_offline_read() meaning "end of file".
+	*/
+	return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s));
+}
+
+/*
+ * Implementation of a pcap_if_list_t.
+ */
+struct pcap_if_list {
+	pcap_if_t *beginning;
+};
+
+static struct capture_source_type {
+	int (*findalldevs_op)(pcap_if_list_t *, char *);
+	pcap_t *(*create_op)(const char *, char *, int *);
+} capture_source_types[] = {
+#ifdef HAVE_DAG_API
+	{ dag_findalldevs, dag_create },
+#endif
+#ifdef HAVE_SEPTEL_API
+	{ septel_findalldevs, septel_create },
+#endif
+#ifdef HAVE_SNF_API
+	{ snf_findalldevs, snf_create },
+#endif
+#ifdef HAVE_TC_API
+	{ TcFindAllDevs, TcCreate },
+#endif
+#ifdef PCAP_SUPPORT_BT
+	{ bt_findalldevs, bt_create },
+#endif
+#ifdef PCAP_SUPPORT_BT_MONITOR
+	{ bt_monitor_findalldevs, bt_monitor_create },
+#endif
+#ifdef PCAP_SUPPORT_LINUX_USBMON
+	{ usb_findalldevs, usb_create },
+#endif
+#ifdef PCAP_SUPPORT_NETFILTER
+	{ netfilter_findalldevs, netfilter_create },
+#endif
+#ifdef PCAP_SUPPORT_NETMAP
+	{ pcap_netmap_findalldevs, pcap_netmap_create },
+#endif
+#ifdef PCAP_SUPPORT_DBUS
+	{ dbus_findalldevs, dbus_create },
+#endif
+#ifdef PCAP_SUPPORT_RDMASNIFF
+	{ rdmasniff_findalldevs, rdmasniff_create },
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+	{ pcap_dpdk_findalldevs, pcap_dpdk_create },
+#endif
+#ifdef HAVE_AIRPCAP_API
+	{ airpcap_findalldevs, airpcap_create },
+#endif
+	{ NULL, NULL }
+};
+
+/*
+ * Get a list of all capture sources that are up and that we can open.
+ * Returns -1 on error, 0 otherwise.
+ * The list, as returned through "alldevsp", may be null if no interfaces
+ * were up and could be opened.
+ */
+int
+pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
+{
+	size_t i;
+	pcap_if_list_t devlist;
+
+	/*
+	 * Find all the local network interfaces on which we
+	 * can capture.
+	 */
+	devlist.beginning = NULL;
+	if (pcap_platform_finddevs(&devlist, errbuf) == -1) {
+		/*
+		 * Failed - free all of the entries we were given
+		 * before we failed.
+		 */
+		if (devlist.beginning != NULL)
+			pcap_freealldevs(devlist.beginning);
+		*alldevsp = NULL;
+		return (-1);
+	}
+
+	/*
+	 * Ask each of the non-local-network-interface capture
+	 * source types what interfaces they have.
+	 */
+	for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) {
+		if (capture_source_types[i].findalldevs_op(&devlist, errbuf) == -1) {
+			/*
+			 * We had an error; free the list we've been
+			 * constructing.
+			 */
+			if (devlist.beginning != NULL)
+				pcap_freealldevs(devlist.beginning);
+			*alldevsp = NULL;
+			return (-1);
+		}
+	}
+
+	/*
+	 * Return the first entry of the list of all devices.
+	 */
+	*alldevsp = devlist.beginning;
+	return (0);
+}
+
+static struct sockaddr *
+dup_sockaddr(struct sockaddr *sa, size_t sa_length)
+{
+	struct sockaddr *newsa;
+
+	if ((newsa = malloc(sa_length)) == NULL)
+		return (NULL);
+	return (memcpy(newsa, sa, sa_length));
+}
+
+/*
+ * Construct a "figure of merit" for an interface, for use when sorting
+ * the list of interfaces, in which interfaces that are up are superior
+ * to interfaces that aren't up, interfaces that are up and running are
+ * superior to interfaces that are up but not running, and non-loopback
+ * interfaces that are up and running are superior to loopback interfaces,
+ * and interfaces with the same flags have a figure of merit that's higher
+ * the lower the instance number.
+ *
+ * The goal is to try to put the interfaces most likely to be useful for
+ * capture at the beginning of the list.
+ *
+ * The figure of merit, which is lower the "better" the interface is,
+ * has the uppermost bit set if the interface isn't running, the bit
+ * below that set if the interface isn't up, the bit below that
+ * set if the interface is a loopback interface, and the bit below
+ * that set if it's the "any" interface.
+ *
+ * Note: we don't sort by unit number because 1) not all interfaces have
+ * a unit number (systemd, for example, might assign interface names
+ * based on the interface's MAC address or on the physical location of
+ * the adapter's connector), and 2) if the name does end with a simple
+ * unit number, it's not a global property of the interface, it's only
+ * useful as a sort key for device names with the same prefix, so xyz0
+ * shouldn't necessarily sort before abc2.  This means that interfaces
+ * with the same figure of merit will be sorted by the order in which
+ * the mechanism from which we're getting the interfaces supplies them.
+ */
+static u_int
+get_figure_of_merit(pcap_if_t *dev)
+{
+	u_int n;
+
+	n = 0;
+	if (!(dev->flags & PCAP_IF_RUNNING))
+		n |= 0x80000000;
+	if (!(dev->flags & PCAP_IF_UP))
+		n |= 0x40000000;
+
+	/*
+	 * Give non-wireless interfaces that aren't disconnected a better
+	 * figure of merit than interfaces that are disconnected, as
+	 * "disconnected" should indicate that the interface isn't
+	 * plugged into a network and thus won't give you any traffic.
+	 *
+	 * For wireless interfaces, it means "associated with a network",
+	 * which we presume not to necessarily prevent capture, as you
+	 * might run the adapter in some flavor of monitor mode.
+	 */
+	if (!(dev->flags & PCAP_IF_WIRELESS) &&
+	    (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED)
+		n |= 0x20000000;
+
+	/*
+	 * Sort loopback devices after non-loopback devices, *except* for
+	 * disconnected devices.
+	 */
+	if (dev->flags & PCAP_IF_LOOPBACK)
+		n |= 0x10000000;
+
+	/*
+	 * Sort the "any" device before loopback and disconnected devices,
+	 * but after all other devices.
+	 */
+	if (strcmp(dev->name, "any") == 0)
+		n |= 0x08000000;
+
+	return (n);
+}
+
+#ifndef _WIN32
+/*
+ * Try to get a description for a given device.
+ * Returns a mallocated description if it could and NULL if it couldn't.
+ *
+ * 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?  FreeBSD
+ * and OpenBSD let 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
+ * a description in FreeBSD and OpenBSD, but if there is no such
+ * description available, it still might be nice to get some description
+ * string based on the device type or something such as that.
+ *
+ * In macOS, 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 and, in any case, I think HAL is being deprecated in
+ * favor of other stuff such as DeviceKit.  DeviceKit doesn't appear
+ * to have any obvious product information for devices, but maybe
+ * I haven't looked hard enough.
+ *
+ * Using the System Configuration framework, or HAL, or DeviceKit, or
+ * whatever, would require that libpcap applications be linked with
+ * the frameworks/libraries in question.  That shouldn't be a problem
+ * for programs linking with the shared version of libpcap (unless
+ * you're running on AIX - which I think is the only UN*X that doesn't
+ * support linking a shared library with other libraries on which it
+ * depends, and having an executable linked only with the first shared
+ * library automatically pick up the other libraries when started -
+ * and using HAL or whatever).  Programs linked with the static
+ * version of libpcap would have to use pcap-config with the --static
+ * flag in order to get the right linker flags in order to pick up
+ * the additional libraries/frameworks; those programs need that anyway
+ * for libpcap 1.1 and beyond on Linux, as, by default, it requires
+ * -lnl.
+ *
+ * Do any other UN*Xes, or desktop environments support getting a
+ * description?
+ */
+static char *
+#ifdef SIOCGIFDESCR
+get_if_description(const char *name)
+{
+	char *description = NULL;
+	int s;
+	struct ifreq ifrdesc;
+#ifndef IFDESCRSIZE
+	size_t descrlen = 64;
+#else
+	size_t descrlen = IFDESCRSIZE;
+#endif /* IFDESCRSIZE */
+
+	/*
+	 * Get the description for the interface.
+	 */
+	memset(&ifrdesc, 0, sizeof ifrdesc);
+	pcap_strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s >= 0) {
+#ifdef __FreeBSD__
+		/*
+		 * On FreeBSD, if the buffer isn't big enough for the
+		 * description, the ioctl succeeds, but the description
+		 * isn't copied, ifr_buffer.length is set to the description
+		 * length, and ifr_buffer.buffer is set to NULL.
+		 */
+		for (;;) {
+			free(description);
+			if ((description = malloc(descrlen)) != NULL) {
+				ifrdesc.ifr_buffer.buffer = description;
+				ifrdesc.ifr_buffer.length = descrlen;
+				if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) {
+					if (ifrdesc.ifr_buffer.buffer ==
+					    description)
+						break;
+					else
+						descrlen = ifrdesc.ifr_buffer.length;
+				} else {
+					/*
+					 * Failed to get interface description.
+					 */
+					free(description);
+					description = NULL;
+					break;
+				}
+			} else
+				break;
+		}
+#else /* __FreeBSD__ */
+		/*
+		 * The only other OS that currently supports
+		 * SIOCGIFDESCR is OpenBSD, and it has no way
+		 * to get the description length - it's clamped
+		 * to a maximum of IFDESCRSIZE.
+		 */
+		if ((description = malloc(descrlen)) != NULL) {
+			ifrdesc.ifr_data = (caddr_t)description;
+			if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) {
+				/*
+				 * Failed to get interface description.
+				 */
+				free(description);
+				description = NULL;
+			}
+		}
+#endif /* __FreeBSD__ */
+		close(s);
+		if (description != NULL && description[0] == '\0') {
+			/*
+			 * Description is empty, so discard it.
+			 */
+			free(description);
+			description = NULL;
+		}
+	}
+
+#ifdef __FreeBSD__
+	/*
+	 * For FreeBSD, if we didn't get a description, and this is
+	 * a device with a name of the form usbusN, label it as a USB
+	 * bus.
+	 */
+	if (description == NULL) {
+		if (strncmp(name, "usbus", 5) == 0) {
+			/*
+			 * OK, it begins with "usbus".
+			 */
+			long busnum;
+			char *p;
+
+			errno = 0;
+			busnum = strtol(name + 5, &p, 10);
+			if (errno == 0 && p != name + 5 && *p == '\0' &&
+			    busnum >= 0 && busnum <= INT_MAX) {
+				/*
+				 * OK, it's a valid number that's not
+				 * bigger than INT_MAX.  Construct
+				 * a description from it.
+				 * (If that fails, we don't worry about
+				 * it, we just return NULL.)
+				 */
+				if (pcap_asprintf(&description,
+				    "USB bus number %ld", busnum) == -1) {
+					/* Failed. */
+					description = NULL;
+				}
+			}
+		}
+	}
+#endif
+	return (description);
+#else /* SIOCGIFDESCR */
+get_if_description(const char *name _U_)
+{
+	return (NULL);
+#endif /* SIOCGIFDESCR */
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * If we find it, return a pointer to its entry.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * IFF_ flags and description, and, if that succeeds, return a pointer to
+ * the new entry, otherwise return NULL and set errbuf to an error message.
+ */
+pcap_if_t *
+find_or_add_if(pcap_if_list_t *devlistp, const char *name,
+    bpf_u_int32 if_flags, get_if_flags_func get_flags_func, char *errbuf)
+{
+	bpf_u_int32 pcap_flags;
+
+	/*
+	 * Convert IFF_ flags to pcap flags.
+	 */
+	pcap_flags = 0;
+#ifdef IFF_LOOPBACK
+	if (if_flags & IFF_LOOPBACK)
+		pcap_flags |= PCAP_IF_LOOPBACK;
+#else
+	/*
+	 * We don't have IFF_LOOPBACK, so look at the device name to
+	 * see if it looks like a loopback device.
+	 */
+	if (name[0] == 'l' && name[1] == 'o' &&
+	    (PCAP_ISDIGIT(name[2]) || name[2] == '\0'))
+		pcap_flags |= PCAP_IF_LOOPBACK;
+#endif
+#ifdef IFF_UP
+	if (if_flags & IFF_UP)
+		pcap_flags |= PCAP_IF_UP;
+#endif
+#ifdef IFF_RUNNING
+	if (if_flags & IFF_RUNNING)
+		pcap_flags |= PCAP_IF_RUNNING;
+#endif
+
+	/*
+	 * Attempt to find an entry for this device; if we don't find one,
+	 * attempt to add one.
+	 */
+	return (find_or_add_dev(devlistp, name, pcap_flags,
+	    get_flags_func, get_if_description(name), errbuf));
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * If we find it, then, if the specified address isn't null, add it to
+ * the list of addresses for the device and return 0.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * IFF_ flags and description, and, if that succeeds, add the specified
+ * address to its list of addresses if that address is non-null, and
+ * return 0, otherwise return -1 and set errbuf to an error message.
+ *
+ * (We can get called with a null address because we might get a list
+ * of interface name/address combinations from the underlying OS, with
+ * the address being absent in some cases, rather than a list of
+ * interfaces with each interface having a list of addresses, so this
+ * call may be the only call made to add to the list, and we want to
+ * add interfaces even if they have no addresses.)
+ */
+int
+add_addr_to_if(pcap_if_list_t *devlistp, const char *name,
+    bpf_u_int32 if_flags, get_if_flags_func get_flags_func,
+    struct sockaddr *addr, size_t addr_size,
+    struct sockaddr *netmask, size_t netmask_size,
+    struct sockaddr *broadaddr, size_t broadaddr_size,
+    struct sockaddr *dstaddr, size_t dstaddr_size,
+    char *errbuf)
+{
+	pcap_if_t *curdev;
+
+	/*
+	 * Check whether the device exists and, if not, add it.
+	 */
+	curdev = find_or_add_if(devlistp, name, if_flags, get_flags_func,
+	    errbuf);
+	if (curdev == NULL) {
+		/*
+		 * Error - give up.
+		 */
+		return (-1);
+	}
+
+	if (addr == NULL) {
+		/*
+		 * There's no address to add; this entry just meant
+		 * "here's a new interface".
+		 */
+		return (0);
+	}
+
+	/*
+	 * "curdev" is an entry for this interface, and we have an
+	 * address for it; add an entry for that address to the
+	 * interface's list of addresses.
+	 */
+	return (add_addr_to_dev(curdev, addr, addr_size, netmask,
+	    netmask_size, broadaddr, broadaddr_size, dstaddr,
+	    dstaddr_size, errbuf));
+}
+#endif /* _WIN32 */
+
+/*
+ * Add an entry to the list of addresses for an interface.
+ * "curdev" is the entry for that interface.
+ */
+int
+add_addr_to_dev(pcap_if_t *curdev,
+    struct sockaddr *addr, size_t addr_size,
+    struct sockaddr *netmask, size_t netmask_size,
+    struct sockaddr *broadaddr, size_t broadaddr_size,
+    struct sockaddr *dstaddr, size_t dstaddr_size,
+    char *errbuf)
+{
+	pcap_addr_t *curaddr, *prevaddr, *nextaddr;
+
+	/*
+	 * Allocate the new entry and fill it in.
+	 */
+	curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t));
+	if (curaddr == NULL) {
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		return (-1);
+	}
+
+	curaddr->next = NULL;
+	if (addr != NULL && addr_size != 0) {
+		curaddr->addr = (struct sockaddr *)dup_sockaddr(addr, addr_size);
+		if (curaddr->addr == NULL) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			free(curaddr);
+			return (-1);
+		}
+	} else
+		curaddr->addr = NULL;
+
+	if (netmask != NULL && netmask_size != 0) {
+		curaddr->netmask = (struct sockaddr *)dup_sockaddr(netmask, netmask_size);
+		if (curaddr->netmask == NULL) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			if (curaddr->addr != NULL)
+				free(curaddr->addr);
+			free(curaddr);
+			return (-1);
+		}
+	} else
+		curaddr->netmask = NULL;
+
+	if (broadaddr != NULL && broadaddr_size != 0) {
+		curaddr->broadaddr = (struct sockaddr *)dup_sockaddr(broadaddr, broadaddr_size);
+		if (curaddr->broadaddr == NULL) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			if (curaddr->netmask != NULL)
+				free(curaddr->netmask);
+			if (curaddr->addr != NULL)
+				free(curaddr->addr);
+			free(curaddr);
+			return (-1);
+		}
+	} else
+		curaddr->broadaddr = NULL;
+
+	if (dstaddr != NULL && dstaddr_size != 0) {
+		curaddr->dstaddr = (struct sockaddr *)dup_sockaddr(dstaddr, dstaddr_size);
+		if (curaddr->dstaddr == NULL) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			if (curaddr->broadaddr != NULL)
+				free(curaddr->broadaddr);
+			if (curaddr->netmask != NULL)
+				free(curaddr->netmask);
+			if (curaddr->addr != NULL)
+				free(curaddr->addr);
+			free(curaddr);
+			return (-1);
+		}
+	} else
+		curaddr->dstaddr = NULL;
+
+	/*
+	 * Find the end of the list of addresses.
+	 */
+	for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) {
+		nextaddr = prevaddr->next;
+		if (nextaddr == NULL) {
+			/*
+			 * This is the end of the list.
+			 */
+			break;
+		}
+	}
+
+	if (prevaddr == NULL) {
+		/*
+		 * The list was empty; this is the first member.
+		 */
+		curdev->addresses = curaddr;
+	} else {
+		/*
+		 * "prevaddr" is the last member of the list; append
+		 * this member to it.
+		 */
+		prevaddr->next = curaddr;
+	}
+
+	return (0);
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * If we find it, return 0 and set *curdev_ret to point to it.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * flags and description, and, if that succeeds, return 0, otherwise
+ * return -1 and set errbuf to an error message.
+ */
+pcap_if_t *
+find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
+    get_if_flags_func get_flags_func, const char *description, char *errbuf)
+{
+	pcap_if_t *curdev;
+
+	/*
+	 * Is there already an entry in the list for this device?
+	 */
+	curdev = find_dev(devlistp, name);
+	if (curdev != NULL) {
+		/*
+		 * Yes, return it.
+		 */
+		return (curdev);
+	}
+
+	/*
+	 * No, we didn't find it.
+	 */
+
+	/*
+	 * Try to get additional flags for the device.
+	 */
+	if ((*get_flags_func)(name, &flags, errbuf) == -1) {
+		/*
+		 * Failed.
+		 */
+		return (NULL);
+	}
+
+	/*
+	 * Now, try to add it to the list of devices.
+	 */
+	return (add_dev(devlistp, name, flags, description, errbuf));
+}
+
+/*
+ * Look for a given device in the specified list of devices, and return
+ * the entry for it if we find it or NULL if we don't.
+ */
+pcap_if_t *
+find_dev(pcap_if_list_t *devlistp, const char *name)
+{
+	pcap_if_t *curdev;
+
+	/*
+	 * Is there an entry in the list for this device?
+	 */
+	for (curdev = devlistp->beginning; curdev != NULL;
+	    curdev = curdev->next) {
+		if (strcmp(name, curdev->name) == 0) {
+			/*
+			 * We found it, so, yes, there is.  No need to
+			 * add it.  Provide the entry we found to our
+			 * caller.
+			 */
+			return (curdev);
+		}
+	}
+
+	/*
+	 * No.
+	 */
+	return (NULL);
+}
+
+/*
+ * Attempt to add an entry for a device, with the specified flags
+ * and description, and, if that succeeds, return 0 and return a pointer
+ * to the new entry, otherwise return NULL and set errbuf to an error
+ * message.
+ *
+ * If we weren't given a description, try to get one.
+ */
+pcap_if_t *
+add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
+    const char *description, char *errbuf)
+{
+	pcap_if_t *curdev, *prevdev, *nextdev;
+	u_int this_figure_of_merit, nextdev_figure_of_merit;
+
+	curdev = malloc(sizeof(pcap_if_t));
+	if (curdev == NULL) {
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		return (NULL);
+	}
+
+	/*
+	 * Fill in the entry.
+	 */
+	curdev->next = NULL;
+	curdev->name = strdup(name);
+	if (curdev->name == NULL) {
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		free(curdev);
+		return (NULL);
+	}
+	if (description == NULL) {
+		/*
+		 * We weren't handed a description for the interface.
+		 */
+		curdev->description = NULL;
+	} else {
+		/*
+		 * We were handed a description; make a copy.
+		 */
+		curdev->description = strdup(description);
+		if (curdev->description == NULL) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			free(curdev->name);
+			free(curdev);
+			return (NULL);
+		}
+	}
+	curdev->addresses = NULL;	/* list starts out as empty */
+	curdev->flags = flags;
+
+	/*
+	 * Add it to the list, in the appropriate location.
+	 * First, get the "figure of merit" for this interface.
+	 */
+	this_figure_of_merit = get_figure_of_merit(curdev);
+
+	/*
+	 * Now look for the last interface with an figure of merit
+	 * less than or equal to the new interface's figure of merit.
+	 *
+	 * We start with "prevdev" being NULL, meaning we're before
+	 * the first element in the list.
+	 */
+	prevdev = NULL;
+	for (;;) {
+		/*
+		 * Get the interface after this one.
+		 */
+		if (prevdev == NULL) {
+			/*
+			 * The next element is the first element.
+			 */
+			nextdev = devlistp->beginning;
+		} else
+			nextdev = prevdev->next;
+
+		/*
+		 * Are we at the end of the list?
+		 */
+		if (nextdev == NULL) {
+			/*
+			 * Yes - we have to put the new entry after "prevdev".
+			 */
+			break;
+		}
+
+		/*
+		 * Is the new interface's figure of merit less
+		 * than the next interface's figure of merit,
+		 * meaning that the new interface is better
+		 * than the next interface?
+		 */
+		nextdev_figure_of_merit = get_figure_of_merit(nextdev);
+		if (this_figure_of_merit < nextdev_figure_of_merit) {
+			/*
+			 * Yes - we should put the new entry
+			 * before "nextdev", i.e. after "prevdev".
+			 */
+			break;
+		}
+
+		prevdev = nextdev;
+	}
+
+	/*
+	 * Insert before "nextdev".
+	 */
+	curdev->next = nextdev;
+
+	/*
+	 * Insert after "prevdev" - unless "prevdev" is null,
+	 * in which case this is the first interface.
+	 */
+	if (prevdev == NULL) {
+		/*
+		 * This is the first interface.  Make it
+		 * the first element in the list of devices.
+		 */
+		devlistp->beginning = curdev;
+	} else
+		prevdev->next = curdev;
+	return (curdev);
+}
+
+/*
+ * Free a list of interfaces.
+ */
+void
+pcap_freealldevs(pcap_if_t *alldevs)
+{
+	pcap_if_t *curdev, *nextdev;
+	pcap_addr_t *curaddr, *nextaddr;
+
+	for (curdev = alldevs; curdev != NULL; curdev = nextdev) {
+		nextdev = curdev->next;
+
+		/*
+		 * Free all addresses.
+		 */
+		for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) {
+			nextaddr = curaddr->next;
+			if (curaddr->addr)
+				free(curaddr->addr);
+			if (curaddr->netmask)
+				free(curaddr->netmask);
+			if (curaddr->broadaddr)
+				free(curaddr->broadaddr);
+			if (curaddr->dstaddr)
+				free(curaddr->dstaddr);
+			free(curaddr);
+		}
+
+		/*
+		 * Free the name string.
+		 */
+		free(curdev->name);
+
+		/*
+		 * Free the description string, if any.
+		 */
+		if (curdev->description != NULL)
+			free(curdev->description);
+
+		/*
+		 * Free the interface.
+		 */
+		free(curdev);
+	}
+}
+
+/*
+ * pcap-npf.c has its own pcap_lookupdev(), for compatibility reasons, as
+ * it actually returns the names of all interfaces, with a NUL separator
+ * between them; some callers may depend on that.
+ *
+ * MS-DOS has its own pcap_lookupdev(), but that might be useful only
+ * as an optimization.
+ *
+ * In all other cases, we just use pcap_findalldevs() to get a list of
+ * devices, and pick from that list.
+ */
+#if !defined(HAVE_PACKET32) && !defined(MSDOS)
+/*
+ * Return the name of a network interface attached to the system, or NULL
+ * if none can be found.  The interface must be configured up; the
+ * lowest unit number is preferred; loopback is ignored.
+ */
+char *
+pcap_lookupdev(char *errbuf)
+{
+	pcap_if_t *alldevs;
+#ifdef _WIN32
+  /*
+   * Windows - use the same size as the old WinPcap 3.1 code.
+   * XXX - this is probably bigger than it needs to be.
+   */
+  #define IF_NAMESIZE 8192
+#else
+  /*
+   * UN*X - use the system's interface name size.
+   * XXX - that might not be large enough for capture devices
+   * that aren't regular network interfaces.
+   */
+  /* for old BSD systems, including bsdi3 */
+  #ifndef IF_NAMESIZE
+  #define IF_NAMESIZE IFNAMSIZ
+  #endif
+#endif
+	static char device[IF_NAMESIZE + 1];
+	char *ret;
+
+	/*
+	 * We disable this in "new API" mode, because 1) in WinPcap/Npcap,
+	 * it may return UTF-16 strings, for backwards-compatibility
+	 * reasons, and we're also disabling the hack to make that work,
+	 * for not-going-past-the-end-of-a-string reasons, and 2) we
+	 * want its behavior to be consistent.
+	 *
+	 * In addition, it's not thread-safe, so we've marked it as
+	 * deprecated.
+	 */
+	if (pcap_new_api) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()");
+		return (NULL);
+	}
+
+	if (pcap_findalldevs(&alldevs, errbuf) == -1)
+		return (NULL);
+
+	if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
+		/*
+		 * There are no devices on the list, or the first device
+		 * on the list is a loopback device, which means there
+		 * are no non-loopback devices on the list.  This means
+		 * we can't return any device.
+		 *
+		 * XXX - why not return a loopback device?  If we can't
+		 * capture on it, it won't be on the list, and if it's
+		 * on the list, there aren't any non-loopback devices,
+		 * so why not just supply it as the default device?
+		 */
+		(void)pcap_strlcpy(errbuf, "no suitable device found",
+		    PCAP_ERRBUF_SIZE);
+		ret = NULL;
+	} else {
+		/*
+		 * Return the name of the first device on the list.
+		 */
+		(void)pcap_strlcpy(device, alldevs->name, sizeof(device));
+		ret = device;
+	}
+
+	pcap_freealldevs(alldevs);
+	return (ret);
+}
+#endif /* !defined(HAVE_PACKET32) && !defined(MSDOS) */
+
+#if !defined(_WIN32) && !defined(MSDOS)
+/*
+ * We don't just fetch the entire list of devices, search for the
+ * particular device, and use its first IPv4 address, as that's too
+ * much work to get just one device's netmask.
+ *
+ * If we had an API to get attributes for a given device, we could
+ * use that.
+ */
+int
+pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
+    char *errbuf)
+{
+	register int fd;
+	register struct sockaddr_in *sin4;
+	struct ifreq ifr;
+
+	/*
+	 * The pseudo-device "any" listens on all interfaces and therefore
+	 * has the network address and -mask "0.0.0.0" therefore catching
+	 * all traffic. Using NULL for the interface is the same as "any".
+	 */
+	if (!device || strcmp(device, "any") == 0
+#ifdef HAVE_DAG_API
+	    || strstr(device, "dag") != NULL
+#endif
+#ifdef HAVE_SEPTEL_API
+	    || strstr(device, "septel") != NULL
+#endif
+#ifdef PCAP_SUPPORT_BT
+	    || strstr(device, "bluetooth") != NULL
+#endif
+#ifdef PCAP_SUPPORT_LINUX_USBMON
+	    || strstr(device, "usbmon") != NULL
+#endif
+#ifdef HAVE_SNF_API
+	    || strstr(device, "snf") != NULL
+#endif
+#ifdef PCAP_SUPPORT_NETMAP
+	    || strncmp(device, "netmap:", 7) == 0
+	    || strncmp(device, "vale", 4) == 0
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+	    || strncmp(device, "dpdk:", 5) == 0
+#endif
+	    ) {
+		*netp = *maskp = 0;
+		return 0;
+	}
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "socket");
+		return (-1);
+	}
+	memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+	/* XXX Work around Linux kernel bug */
+	ifr.ifr_addr.sa_family = AF_INET;
+#endif
+	(void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+	if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+		if (errno == EADDRNOTAVAIL) {
+			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: no IPv4 address assigned", device);
+		} else {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "SIOCGIFADDR: %s", device);
+		}
+		(void)close(fd);
+		return (-1);
+	}
+	sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
+	*netp = sin4->sin_addr.s_addr;
+	memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+	/* XXX Work around Linux kernel bug */
+	ifr.ifr_addr.sa_family = AF_INET;
+#endif
+	(void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+	if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "SIOCGIFNETMASK: %s", device);
+		(void)close(fd);
+		return (-1);
+	}
+	(void)close(fd);
+	*maskp = sin4->sin_addr.s_addr;
+	if (*maskp == 0) {
+		if (IN_CLASSA(*netp))
+			*maskp = IN_CLASSA_NET;
+		else if (IN_CLASSB(*netp))
+			*maskp = IN_CLASSB_NET;
+		else if (IN_CLASSC(*netp))
+			*maskp = IN_CLASSC_NET;
+		else {
+			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "inet class for 0x%x unknown", *netp);
+			return (-1);
+		}
+	}
+	*netp &= *maskp;
+	return (0);
+}
+#endif /* !defined(_WIN32) && !defined(MSDOS) */
+
+#ifdef ENABLE_REMOTE
+#include "pcap-rpcap.h"
+
+/*
+ * Extract a substring from a string.
+ */
+static char *
+get_substring(const char *p, size_t len, char *ebuf)
+{
+	char *token;
+
+	token = malloc(len + 1);
+	if (token == NULL) {
+		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		return (NULL);
+	}
+	memcpy(token, p, len);
+	token[len] = '\0';
+	return (token);
+}
+
+/*
+ * Parse a capture source that might be a URL.
+ *
+ * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp
+ * are set to NULL, *pathp is set to point to the source, and 0 is
+ * returned.
+ *
+ * If source is a URL, and the URL refers to a local device (a special
+ * case of rpcap:), *schemep, *userinfop, *hostp, and *portp are set
+ * to NULL, *pathp is set to point to the device name, and 0 is returned.
+ *
+ * If source is a URL, and it's not a special case that refers to a local
+ * device, and the parse succeeds:
+ *
+ *    *schemep is set to point to an allocated string containing the scheme;
+ *
+ *    if user information is present in the URL, *userinfop is set to point
+ *    to an allocated string containing the user information, otherwise
+ *    it's set to NULL;
+ *
+ *    if host information is present in the URL, *hostp is set to point
+ *    to an allocated string containing the host information, otherwise
+ *    it's set to NULL;
+ *
+ *    if a port number is present in the URL, *portp is set to point
+ *    to an allocated string containing the port number, otherwise
+ *    it's set to NULL;
+ *
+ *    *pathp is set to point to an allocated string containing the
+ *    path;
+ *
+ * and 0 is returned.
+ *
+ * If the parse fails, ebuf is set to an error string, and -1 is returned.
+ */
+static int
+pcap_parse_source(const char *source, char **schemep, char **userinfop,
+    char **hostp, char **portp, char **pathp, char *ebuf)
+{
+	char *colonp;
+	size_t scheme_len;
+	char *scheme;
+	const char *endp;
+	size_t authority_len;
+	char *authority;
+	char *parsep, *atsignp, *bracketp;
+	char *userinfo, *host, *port, *path;
+
+	/*
+	 * Start out returning nothing.
+	 */
+	*schemep = NULL;
+	*userinfop = NULL;
+	*hostp = NULL;
+	*portp = NULL;
+	*pathp = NULL;
+
+	/*
+	 * RFC 3986 says:
+	 *
+	 *   URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+	 *
+	 *   hier-part   = "//" authority path-abempty
+	 *               / path-absolute
+	 *               / path-rootless
+	 *               / path-empty
+	 *
+	 *   authority   = [ userinfo "@" ] host [ ":" port ]
+	 *
+	 *   userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
+         *
+         * Step 1: look for the ":" at the end of the scheme.
+	 * A colon in the source is *NOT* sufficient to indicate that
+	 * this is a URL, as interface names on some platforms might
+	 * include colons (e.g., I think some Solaris interfaces
+	 * might).
+	 */
+	colonp = strchr(source, ':');
+	if (colonp == NULL) {
+		/*
+		 * The source is the device to open.
+		 * Return a NULL pointer for the scheme, user information,
+		 * host, and port, and return the device as the path.
+		 */
+		*pathp = strdup(source);
+		if (*pathp == NULL) {
+			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			return (-1);
+		}
+		return (0);
+	}
+
+	/*
+	 * All schemes must have "//" after them, i.e. we only support
+	 * hier-part   = "//" authority path-abempty, not
+	 * hier-part   = path-absolute
+	 * hier-part   = path-rootless
+	 * hier-part   = path-empty
+	 *
+	 * We need that in order to distinguish between a local device
+	 * name that happens to contain a colon and a URI.
+	 */
+	if (strncmp(colonp + 1, "//", 2) != 0) {
+		/*
+		 * The source is the device to open.
+		 * Return a NULL pointer for the scheme, user information,
+		 * host, and port, and return the device as the path.
+		 */
+		*pathp = strdup(source);
+		if (*pathp == NULL) {
+			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			return (-1);
+		}
+		return (0);
+	}
+
+	/*
+	 * XXX - check whether the purported scheme could be a scheme?
+	 */
+
+	/*
+	 * OK, this looks like a URL.
+	 * Get the scheme.
+	 */
+	scheme_len = colonp - source;
+	scheme = malloc(scheme_len + 1);
+	if (scheme == NULL) {
+		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		return (-1);
+	}
+	memcpy(scheme, source, scheme_len);
+	scheme[scheme_len] = '\0';
+
+	/*
+	 * Treat file: specially - take everything after file:// as
+	 * the pathname.
+	 */
+	if (pcap_strcasecmp(scheme, "file") == 0) {
+		*pathp = strdup(colonp + 3);
+		if (*pathp == NULL) {
+			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			free(scheme);
+			return (-1);
+		}
+		*schemep = scheme;
+		return (0);
+	}
+
+	/*
+	 * The WinPcap documentation says you can specify a local
+	 * interface with "rpcap://{device}"; we special-case
+	 * that here.  If the scheme is "rpcap", and there are
+	 * no slashes past the "//", we just return the device.
+	 *
+	 * XXX - %-escaping?
+	 */
+	if ((pcap_strcasecmp(scheme, "rpcap") == 0 ||
+	    pcap_strcasecmp(scheme, "rpcaps") == 0) &&
+	    strchr(colonp + 3, '/') == NULL) {
+		/*
+		 * Local device.
+		 *
+		 * Return a NULL pointer for the scheme, user information,
+		 * host, and port, and return the device as the path.
+		 */
+		free(scheme);
+		*pathp = strdup(colonp + 3);
+		if (*pathp == NULL) {
+			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			return (-1);
+		}
+		return (0);
+	}
+
+	/*
+	 * OK, now start parsing the authority.
+	 * Get token, terminated with / or terminated at the end of
+	 * the string.
+	 */
+	authority_len = strcspn(colonp + 3, "/");
+	authority = get_substring(colonp + 3, authority_len, ebuf);
+	if (authority == NULL) {
+		/*
+		 * Error.
+		 */
+		free(scheme);
+		return (-1);
+	}
+	endp = colonp + 3 + authority_len;
+
+	/*
+	 * Now carve the authority field into its components.
+	 */
+	parsep = authority;
+
+	/*
+	 * Is there a userinfo field?
+	 */
+	atsignp = strchr(parsep, '@');
+	if (atsignp != NULL) {
+		/*
+		 * Yes.
+		 */
+		size_t userinfo_len;
+
+		userinfo_len = atsignp - parsep;
+		userinfo = get_substring(parsep, userinfo_len, ebuf);
+		if (userinfo == NULL) {
+			/*
+			 * Error.
+			 */
+			free(authority);
+			free(scheme);
+			return (-1);
+		}
+		parsep = atsignp + 1;
+	} else {
+		/*
+		 * No.
+		 */
+		userinfo = NULL;
+	}
+
+	/*
+	 * Is there a host field?
+	 */
+	if (*parsep == '\0') {
+		/*
+		 * No; there's no host field or port field.
+		 */
+		host = NULL;
+		port = NULL;
+	} else {
+		/*
+		 * Yes.
+		 */
+		size_t host_len;
+
+		/*
+		 * Is it an IP-literal?
+		 */
+		if (*parsep == '[') {
+			/*
+			 * Yes.
+			 * Treat verything up to the closing square
+			 * bracket as the IP-Literal; we don't worry
+			 * about whether it's a valid IPv6address or
+			 * IPvFuture (or an IPv4address, for that
+			 * matter, just in case we get handed a
+			 * URL with an IPv4 IP-Literal, of the sort
+			 * that pcap_createsrcstr() used to generate,
+			 * and that pcap_parsesrcstr(), in the original
+			 * WinPcap code, accepted).
+			 */
+			bracketp = strchr(parsep, ']');
+			if (bracketp == NULL) {
+				/*
+				 * There's no closing square bracket.
+				 */
+				snprintf(ebuf, PCAP_ERRBUF_SIZE,
+				    "IP-literal in URL doesn't end with ]");
+				free(userinfo);
+				free(authority);
+				free(scheme);
+				return (-1);
+			}
+			if (*(bracketp + 1) != '\0' &&
+			    *(bracketp + 1) != ':') {
+				/*
+				 * There's extra crud after the
+				 * closing square bracketn.
+				 */
+				snprintf(ebuf, PCAP_ERRBUF_SIZE,
+				    "Extra text after IP-literal in URL");
+				free(userinfo);
+				free(authority);
+				free(scheme);
+				return (-1);
+			}
+			host_len = (bracketp - 1) - parsep;
+			host = get_substring(parsep + 1, host_len, ebuf);
+			if (host == NULL) {
+				/*
+				 * Error.
+				 */
+				free(userinfo);
+				free(authority);
+				free(scheme);
+				return (-1);
+			}
+			parsep = bracketp + 1;
+		} else {
+			/*
+			 * No.
+			 * Treat everything up to a : or the end of
+			 * the string as the host.
+			 */
+			host_len = strcspn(parsep, ":");
+			host = get_substring(parsep, host_len, ebuf);
+			if (host == NULL) {
+				/*
+				 * Error.
+				 */
+				free(userinfo);
+				free(authority);
+				free(scheme);
+				return (-1);
+			}
+			parsep = parsep + host_len;
+		}
+
+		/*
+		 * Is there a port field?
+		 */
+		if (*parsep == ':') {
+			/*
+			 * Yes.  It's the rest of the authority field.
+			 */
+			size_t port_len;
+
+			parsep++;
+			port_len = strlen(parsep);
+			port = get_substring(parsep, port_len, ebuf);
+			if (port == NULL) {
+				/*
+				 * Error.
+				 */
+				free(host);
+				free(userinfo);
+				free(authority);
+				free(scheme);
+				return (-1);
+			}
+		} else {
+			/*
+			 * No.
+			 */
+			port = NULL;
+		}
+	}
+	free(authority);
+
+	/*
+	 * Everything else is the path.  Strip off the leading /.
+	 */
+	if (*endp == '\0')
+		path = strdup("");
+	else
+		path = strdup(endp + 1);
+	if (path == NULL) {
+		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		free(port);
+		free(host);
+		free(userinfo);
+		free(scheme);
+		return (-1);
+	}
+	*schemep = scheme;
+	*userinfop = userinfo;
+	*hostp = host;
+	*portp = port;
+	*pathp = path;
+	return (0);
+}
+
+int
+pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
+    const char *name, unsigned char uses_ssl, char *errbuf)
+{
+	switch (type) {
+
+	case PCAP_SRC_FILE:
+		pcap_strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
+		if (name != NULL && *name != '\0') {
+			pcap_strlcat(source, name, PCAP_BUF_SIZE);
+			return (0);
+		} else {
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "The file name cannot be NULL.");
+			return (-1);
+		}
+
+	case PCAP_SRC_IFREMOTE:
+		pcap_strlcpy(source,
+		    (uses_ssl ? "rpcaps://" : PCAP_SRC_IF_STRING),
+		    PCAP_BUF_SIZE);
+		if (host != NULL && *host != '\0') {
+			if (strchr(host, ':') != NULL) {
+				/*
+				 * The host name contains a colon, so it's
+				 * probably an IPv6 address, and needs to
+				 * be included in square brackets.
+				 */
+				pcap_strlcat(source, "[", PCAP_BUF_SIZE);
+				pcap_strlcat(source, host, PCAP_BUF_SIZE);
+				pcap_strlcat(source, "]", PCAP_BUF_SIZE);
+			} else
+				pcap_strlcat(source, host, PCAP_BUF_SIZE);
+
+			if (port != NULL && *port != '\0') {
+				pcap_strlcat(source, ":", PCAP_BUF_SIZE);
+				pcap_strlcat(source, port, PCAP_BUF_SIZE);
+			}
+
+			pcap_strlcat(source, "/", PCAP_BUF_SIZE);
+		} else {
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "The host name cannot be NULL.");
+			return (-1);
+		}
+
+		if (name != NULL && *name != '\0')
+			pcap_strlcat(source, name, PCAP_BUF_SIZE);
+
+		return (0);
+
+	case PCAP_SRC_IFLOCAL:
+		pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+
+		if (name != NULL && *name != '\0')
+			pcap_strlcat(source, name, PCAP_BUF_SIZE);
+
+		return (0);
+
+	default:
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "The interface type is not valid.");
+		return (-1);
+	}
+}
+
+
+int
+pcap_createsrcstr(char *source, int type, const char *host, const char *port,
+    const char *name, char *errbuf)
+{
+	return (pcap_createsrcstr_ex(source, type, host, port, name, 0, errbuf));
+}
+
+int
+pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port,
+    char *name, unsigned char *uses_ssl, char *errbuf)
+{
+	char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath;
+
+	/* Initialization stuff */
+	if (host)
+		*host = '\0';
+	if (port)
+		*port = '\0';
+	if (name)
+		*name = '\0';
+	if (uses_ssl)
+		*uses_ssl = 0;
+
+	/* Parse the source string */
+	if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
+	    &tmpport, &tmppath, errbuf) == -1) {
+		/*
+		 * Fail.
+		 */
+		return (-1);
+	}
+
+	if (scheme == NULL) {
+		/*
+		 * Local device.
+		 */
+		if (name && tmppath)
+			pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+		if (type)
+			*type = PCAP_SRC_IFLOCAL;
+		free(tmppath);
+		free(tmpport);
+		free(tmphost);
+		free(tmpuserinfo);
+		return (0);
+	}
+
+	int is_rpcap = 0;
+	if (strcmp(scheme, "rpcaps") == 0) {
+		is_rpcap = 1;
+		if (uses_ssl) *uses_ssl = 1;
+	} else if (strcmp(scheme, "rpcap") == 0) {
+		is_rpcap = 1;
+	}
+
+	if (is_rpcap) {
+		/*
+		 * rpcap[s]://
+		 *
+		 * pcap_parse_source() has already handled the case of
+		 * rpcap[s]://device
+		 */
+		if (host && tmphost) {
+			if (tmpuserinfo)
+				snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+				    tmpuserinfo, tmphost);
+			else
+				pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
+		}
+		if (port && tmpport)
+			pcap_strlcpy(port, tmpport, PCAP_BUF_SIZE);
+		if (name && tmppath)
+			pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+		if (type)
+			*type = PCAP_SRC_IFREMOTE;
+		free(tmppath);
+		free(tmpport);
+		free(tmphost);
+		free(tmpuserinfo);
+		free(scheme);
+		return (0);
+	}
+
+	if (strcmp(scheme, "file") == 0) {
+		/*
+		 * file://
+		 */
+		if (name && tmppath)
+			pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+		if (type)
+			*type = PCAP_SRC_FILE;
+		free(tmppath);
+		free(tmpport);
+		free(tmphost);
+		free(tmpuserinfo);
+		free(scheme);
+		return (0);
+	}
+
+	/*
+	 * Neither rpcap: nor file:; just treat the entire string
+	 * as a local device.
+	 */
+	if (name)
+		pcap_strlcpy(name, source, PCAP_BUF_SIZE);
+	if (type)
+		*type = PCAP_SRC_IFLOCAL;
+	free(tmppath);
+	free(tmpport);
+	free(tmphost);
+	free(tmpuserinfo);
+	free(scheme);
+	return (0);
+}
+
+int
+pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
+    char *name, char *errbuf)
+{
+	return (pcap_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf));
+}
+#endif
+
+pcap_t *
+pcap_create(const char *device, char *errbuf)
+{
+	size_t i;
+	int is_theirs;
+	pcap_t *p;
+	char *device_str;
+
+	/*
+	 * A null device name is equivalent to the "any" device -
+	 * which might not be supported on this platform, but
+	 * this means that you'll get a "not supported" error
+	 * rather than, say, a crash when we try to dereference
+	 * the null pointer.
+	 */
+	if (device == NULL)
+		device_str = strdup("any");
+	else {
+#ifdef _WIN32
+		/*
+		 * On Windows, for backwards compatibility reasons,
+		 * pcap_lookupdev() returns a pointer to a sequence of
+		 * pairs of UTF-16LE device names and local code page
+		 * description strings.
+		 *
+		 * This means that if a program uses pcap_lookupdev()
+		 * to get a default device, and hands that to an API
+		 * that opens devices, we'll get handed a UTF-16LE
+		 * string, not a string in the local code page.
+		 *
+		 * To work around that, we check whether the string
+		 * looks as if it might be a UTF-16LE string and, if
+		 * so, convert it back to the local code page's
+		 * extended ASCII.
+		 *
+		 * We disable that check in "new API" mode, because:
+		 *
+		 *   1) You *cannot* reliably detect whether a
+		 *   string is UTF-16LE or not; "a" could either
+		 *   be a one-character ASCII string or the first
+		 *   character of a UTF-16LE string.
+		 *
+		 *   2) Doing that test can run past the end of
+		 *   the string, if it's a 1-character ASCII
+		 *   string
+		 *
+		 * This particular version of this heuristic dates
+		 * back to WinPcap 4.1.1; PacketOpenAdapter() does
+		 * uses the same heuristic, with the exact same
+		 * vulnerability.
+		 *
+		 * That's why we disable this in "new API" mode.
+		 * We keep it around in legacy mode for backwards
+		 * compatibility.
+		 */
+		if (!pcap_new_api && device[0] != '\0' && device[1] == '\0') {
+			size_t length;
+
+			length = wcslen((wchar_t *)device);
+			device_str = (char *)malloc(length + 1);
+			if (device_str == NULL) {
+				pcap_fmt_errmsg_for_errno(errbuf,
+				    PCAP_ERRBUF_SIZE, errno,
+				    "malloc");
+				return (NULL);
+			}
+
+			snprintf(device_str, length + 1, "%ws",
+			    (const wchar_t *)device);
+		} else
+#endif
+			device_str = strdup(device);
+	}
+	if (device_str == NULL) {
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		return (NULL);
+	}
+
+	/*
+	 * Try each of the non-local-network-interface capture
+	 * source types until we find one that works for this
+	 * device or run out of types.
+	 */
+	for (i = 0; capture_source_types[i].create_op != NULL; i++) {
+		is_theirs = 0;
+		p = capture_source_types[i].create_op(device_str, errbuf,
+		    &is_theirs);
+		if (is_theirs) {
+			/*
+			 * The device name refers to a device of the
+			 * type in question; either it succeeded,
+			 * in which case p refers to a pcap_t to
+			 * later activate for the device, or it
+			 * failed, in which case p is null and we
+			 * should return that to report the failure
+			 * to create.
+			 */
+			if (p == NULL) {
+				/*
+				 * We assume the caller filled in errbuf.
+				 */
+				free(device_str);
+				return (NULL);
+			}
+			p->opt.device = device_str;
+			return (p);
+		}
+	}
+
+	/*
+	 * OK, try it as a regular network interface.
+	 */
+	p = pcap_create_interface(device_str, errbuf);
+	if (p == NULL) {
+		/*
+		 * We assume the caller filled in errbuf.
+		 */
+		free(device_str);
+		return (NULL);
+	}
+	p->opt.device = device_str;
+	return (p);
+}
+
+/*
+ * Set nonblocking mode on an unactivated pcap_t; this sets a flag
+ * checked by pcap_activate(), which sets the mode after calling
+ * the activate routine.
+ */
+static int
+pcap_setnonblock_unactivated(pcap_t *p, int nonblock)
+{
+	p->opt.nonblock = nonblock;
+	return (0);
+}
+
+static void
+initialize_ops(pcap_t *p)
+{
+	/*
+	 * Set operation pointers for operations that only work on
+	 * an activated pcap_t to point to a routine that returns
+	 * a "this isn't activated" error.
+	 */
+	p->read_op = pcap_read_not_initialized;
+	p->inject_op = pcap_inject_not_initialized;
+	p->setfilter_op = pcap_setfilter_not_initialized;
+	p->setdirection_op = pcap_setdirection_not_initialized;
+	p->set_datalink_op = pcap_set_datalink_not_initialized;
+	p->getnonblock_op = pcap_getnonblock_not_initialized;
+	p->stats_op = pcap_stats_not_initialized;
+#ifdef _WIN32
+	p->stats_ex_op = pcap_stats_ex_not_initialized;
+	p->setbuff_op = pcap_setbuff_not_initialized;
+	p->setmode_op = pcap_setmode_not_initialized;
+	p->setmintocopy_op = pcap_setmintocopy_not_initialized;
+	p->getevent_op = pcap_getevent_not_initialized;
+	p->oid_get_request_op = pcap_oid_get_request_not_initialized;
+	p->oid_set_request_op = pcap_oid_set_request_not_initialized;
+	p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized;
+	p->setuserbuffer_op = pcap_setuserbuffer_not_initialized;
+	p->live_dump_op = pcap_live_dump_not_initialized;
+	p->live_dump_ended_op = pcap_live_dump_ended_not_initialized;
+	p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized;
+#endif
+
+	/*
+	 * Default cleanup operation - implementations can override
+	 * this, but should call pcap_cleanup_live_common() after
+	 * doing their own additional cleanup.
+	 */
+	p->cleanup_op = pcap_cleanup_live_common;
+
+	/*
+	 * In most cases, the standard one-shot callback can
+	 * be used for pcap_next()/pcap_next_ex().
+	 */
+	p->oneshot_callback = pcap_oneshot;
+
+	/*
+	 * Default breakloop operation - implementations can override
+	 * this, but should call pcap_breakloop_common() before doing
+	 * their own logic.
+	 */
+	p->breakloop_op = pcap_breakloop_common;
+}
+
+static pcap_t *
+pcap_alloc_pcap_t(char *ebuf, size_t total_size, size_t private_offset)
+{
+	char *chunk;
+	pcap_t *p;
+
+	/*
+	 * total_size is the size of a structure containing a pcap_t
+	 * followed by a private structure.
+	 */
+	chunk = calloc(total_size, 1);
+	if (chunk == NULL) {
+		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		return (NULL);
+	}
+
+	/*
+	 * Get a pointer to the pcap_t at the beginning.
+	 */
+	p = (pcap_t *)chunk;
+
+#ifdef _WIN32
+	p->handle = INVALID_HANDLE_VALUE;	/* not opened yet */
+#else /* _WIN32 */
+	p->fd = -1;	/* not opened yet */
+#ifndef MSDOS
+	p->selectable_fd = -1;
+	p->required_select_timeout = NULL;
+#endif /* MSDOS */
+#endif /* _WIN32 */
+
+	/*
+	 * private_offset is the offset, in bytes, of the private
+	 * data from the beginning of the structure.
+	 *
+	 * Set the pointer to the private data; that's private_offset
+	 * bytes past the pcap_t.
+	 */
+	p->priv = (void *)(chunk + private_offset);
+
+	return (p);
+}
+
+pcap_t *
+pcap_create_common(char *ebuf, size_t total_size, size_t private_offset)
+{
+	pcap_t *p;
+
+	p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
+	if (p == NULL)
+		return (NULL);
+
+	/*
+	 * Default to "can't set rfmon mode"; if it's supported by
+	 * a platform, the create routine that called us can set
+	 * the op to its routine to check whether a particular
+	 * device supports it.
+	 */
+	p->can_set_rfmon_op = pcap_cant_set_rfmon;
+
+	/*
+	 * If pcap_setnonblock() is called on a not-yet-activated
+	 * pcap_t, default to setting a flag and turning
+	 * on non-blocking mode when activated.
+	 */
+	p->setnonblock_op = pcap_setnonblock_unactivated;
+
+	initialize_ops(p);
+
+	/* put in some defaults*/
+	p->snapshot = 0;		/* max packet size unspecified */
+	p->opt.timeout = 0;		/* no timeout specified */
+	p->opt.buffer_size = 0;		/* use the platform's default */
+	p->opt.promisc = 0;
+	p->opt.rfmon = 0;
+	p->opt.immediate = 0;
+	p->opt.tstamp_type = -1;	/* default to not setting time stamp type */
+	p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
+	/*
+	 * Platform-dependent options.
+	 */
+#ifdef __linux__
+	p->opt.protocol = 0;
+#endif
+#ifdef _WIN32
+	p->opt.nocapture_local = 0;
+#endif
+
+	/*
+	 * Start out with no BPF code generation flags set.
+	 */
+	p->bpf_codegen_flags = 0;
+
+	return (p);
+}
+
+int
+pcap_check_activated(pcap_t *p)
+{
+	if (p->activated) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
+			" operation on activated capture");
+		return (-1);
+	}
+	return (0);
+}
+
+int
+pcap_set_snaplen(pcap_t *p, int snaplen)
+{
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+	p->snapshot = snaplen;
+	return (0);
+}
+
+int
+pcap_set_promisc(pcap_t *p, int promisc)
+{
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+	p->opt.promisc = promisc;
+	return (0);
+}
+
+int
+pcap_set_rfmon(pcap_t *p, int rfmon)
+{
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+	p->opt.rfmon = rfmon;
+	return (0);
+}
+
+int
+pcap_set_timeout(pcap_t *p, int timeout_ms)
+{
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+	p->opt.timeout = timeout_ms;
+	return (0);
+}
+
+int
+pcap_set_tstamp_type(pcap_t *p, int tstamp_type)
+{
+	int i;
+
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+
+	/*
+	 * The argument should have been u_int, but that's too late
+	 * to change now - it's an API.
+	 */
+	if (tstamp_type < 0)
+		return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP);
+
+	/*
+	 * If p->tstamp_type_count is 0, we only support PCAP_TSTAMP_HOST;
+	 * the default time stamp type is PCAP_TSTAMP_HOST.
+	 */
+	if (p->tstamp_type_count == 0) {
+		if (tstamp_type == PCAP_TSTAMP_HOST) {
+			p->opt.tstamp_type = tstamp_type;
+			return (0);
+		}
+	} else {
+		/*
+		 * Check whether we claim to support this type of time stamp.
+		 */
+		for (i = 0; i < p->tstamp_type_count; i++) {
+			if (p->tstamp_type_list[i] == (u_int)tstamp_type) {
+				/*
+				 * Yes.
+				 */
+				p->opt.tstamp_type = tstamp_type;
+				return (0);
+			}
+		}
+	}
+
+	/*
+	 * We don't support this type of time stamp.
+	 */
+	return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP);
+}
+
+int
+pcap_set_immediate_mode(pcap_t *p, int immediate)
+{
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+	p->opt.immediate = immediate;
+	return (0);
+}
+
+int
+pcap_set_buffer_size(pcap_t *p, int buffer_size)
+{
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+	if (buffer_size <= 0) {
+		/*
+		 * Silently ignore invalid values.
+		 */
+		return (0);
+	}
+	p->opt.buffer_size = buffer_size;
+	return (0);
+}
+
+int
+pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision)
+{
+	int i;
+
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+
+	/*
+	 * The argument should have been u_int, but that's too late
+	 * to change now - it's an API.
+	 */
+	if (tstamp_precision < 0)
+		return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP);
+
+	/*
+	 * If p->tstamp_precision_count is 0, we only support setting
+	 * the time stamp precision to microsecond precision; every
+	 * pcap module *MUST* support microsecond precision, even if
+	 * it does so by converting the native precision to
+	 * microseconds.
+	 */
+	if (p->tstamp_precision_count == 0) {
+		if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO) {
+			p->opt.tstamp_precision = tstamp_precision;
+			return (0);
+		}
+	} else {
+		/*
+		 * Check whether we claim to support this precision of
+		 * time stamp.
+		 */
+		for (i = 0; i < p->tstamp_precision_count; i++) {
+			if (p->tstamp_precision_list[i] == (u_int)tstamp_precision) {
+				/*
+				 * Yes.
+				 */
+				p->opt.tstamp_precision = tstamp_precision;
+				return (0);
+			}
+		}
+	}
+
+	/*
+	 * We don't support this time stamp precision.
+	 */
+	return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP);
+}
+
+int
+pcap_get_tstamp_precision(pcap_t *p)
+{
+        return (p->opt.tstamp_precision);
+}
+
+int
+pcap_activate(pcap_t *p)
+{
+	int status;
+
+	/*
+	 * Catch attempts to re-activate an already-activated
+	 * pcap_t; this should, for example, catch code that
+	 * calls pcap_open_live() followed by pcap_activate(),
+	 * as some code that showed up in a Stack Exchange
+	 * question did.
+	 */
+	if (pcap_check_activated(p))
+		return (PCAP_ERROR_ACTIVATED);
+	status = p->activate_op(p);
+	if (status >= 0) {
+		/*
+		 * If somebody requested non-blocking mode before
+		 * calling pcap_activate(), turn it on now.
+		 */
+		if (p->opt.nonblock) {
+			status = p->setnonblock_op(p, 1);
+			if (status < 0) {
+				/*
+				 * Failed.  Undo everything done by
+				 * the activate operation.
+				 */
+				p->cleanup_op(p);
+				initialize_ops(p);
+				return (status);
+			}
+		}
+		p->activated = 1;
+	} else {
+		if (p->errbuf[0] == '\0') {
+			/*
+			 * No error message supplied by the activate routine;
+			 * for the benefit of programs that don't specially
+			 * handle errors other than PCAP_ERROR, return the
+			 * error message corresponding to the status.
+			 */
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
+			    pcap_statustostr(status));
+		}
+
+		/*
+		 * Undo any operation pointer setting, etc. done by
+		 * the activate operation.
+		 */
+		initialize_ops(p);
+	}
+	return (status);
+}
+
+pcap_t *
+pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf)
+{
+	pcap_t *p;
+	int status;
+#ifdef ENABLE_REMOTE
+	char host[PCAP_BUF_SIZE + 1];
+	char port[PCAP_BUF_SIZE + 1];
+	char name[PCAP_BUF_SIZE + 1];
+	int srctype;
+
+	/*
+	 * A null device name is equivalent to the "any" device -
+	 * which might not be supported on this platform, but
+	 * this means that you'll get a "not supported" error
+	 * rather than, say, a crash when we try to dereference
+	 * the null pointer.
+	 */
+	if (device == NULL)
+		device = "any";
+
+	/*
+	 * Retrofit - we have to make older applications compatible with
+	 * remote capture.
+	 * So we're calling pcap_open_remote() from here; this is a very
+	 * dirty hack.
+	 * Obviously, we cannot exploit all the new features; for instance,
+	 * we cannot send authentication, we cannot use a UDP data connection,
+	 * and so on.
+	 */
+	if (pcap_parsesrcstr(device, &srctype, host, port, name, errbuf))
+		return (NULL);
+
+	if (srctype == PCAP_SRC_IFREMOTE) {
+		/*
+		 * Although we already have host, port and iface, we prefer
+		 * to pass only 'device' to pcap_open_rpcap(), so that it has
+		 * to call pcap_parsesrcstr() again.
+		 * This is less optimized, but much clearer.
+		 */
+		return (pcap_open_rpcap(device, snaplen,
+		    promisc ? PCAP_OPENFLAG_PROMISCUOUS : 0, to_ms,
+		    NULL, errbuf));
+	}
+	if (srctype == PCAP_SRC_FILE) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
+		return (NULL);
+	}
+	if (srctype == PCAP_SRC_IFLOCAL) {
+		/*
+		 * If it starts with rpcap://, that refers to a local device
+		 * (no host part in the URL). Remove the rpcap://, and
+		 * fall through to the regular open path.
+		 */
+		if (strncmp(device, PCAP_SRC_IF_STRING, strlen(PCAP_SRC_IF_STRING)) == 0) {
+			size_t len = strlen(device) - strlen(PCAP_SRC_IF_STRING) + 1;
+
+			if (len > 0)
+				device += strlen(PCAP_SRC_IF_STRING);
+		}
+	}
+#endif	/* ENABLE_REMOTE */
+
+	p = pcap_create(device, errbuf);
+	if (p == NULL)
+		return (NULL);
+	status = pcap_set_snaplen(p, snaplen);
+	if (status < 0)
+		goto fail;
+	status = pcap_set_promisc(p, promisc);
+	if (status < 0)
+		goto fail;
+	status = pcap_set_timeout(p, to_ms);
+	if (status < 0)
+		goto fail;
+	/*
+	 * Mark this as opened with pcap_open_live(), so that, for
+	 * example, we show the full list of DLT_ values, rather
+	 * than just the ones that are compatible with capturing
+	 * when not in monitor mode.  That allows existing applications
+	 * to work the way they used to work, but allows new applications
+	 * that know about the new open API to, for example, find out the
+	 * DLT_ values that they can select without changing whether
+	 * the adapter is in monitor mode or not.
+	 */
+	p->oldstyle = 1;
+	status = pcap_activate(p);
+	if (status < 0)
+		goto fail;
+	return (p);
+fail:
+	if (status == PCAP_ERROR)
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
+		    PCAP_ERRBUF_SIZE - 3, p->errbuf);
+	else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
+	    status == PCAP_ERROR_PERM_DENIED ||
+	    status == PCAP_ERROR_PROMISC_PERM_DENIED)
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)", device,
+		    pcap_statustostr(status), PCAP_ERRBUF_SIZE - 6, p->errbuf);
+	else
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
+		    pcap_statustostr(status));
+	pcap_close(p);
+	return (NULL);
+}
+
+pcap_t *
+pcap_open_offline_common(char *ebuf, size_t total_size, size_t private_offset)
+{
+	pcap_t *p;
+
+	p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
+	if (p == NULL)
+		return (NULL);
+
+	p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
+
+	return (p);
+}
+
+int
+pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+	return (p->read_op(p, cnt, callback, user));
+}
+
+int
+pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+	register int n;
+
+	for (;;) {
+		if (p->rfile != NULL) {
+			/*
+			 * 0 means EOF, so don't loop if we get 0.
+			 */
+			n = pcap_offline_read(p, cnt, callback, user);
+		} else {
+			/*
+			 * XXX keep reading until we get something
+			 * (or an error occurs)
+			 */
+			do {
+				n = p->read_op(p, cnt, callback, user);
+			} while (n == 0);
+		}
+		if (n <= 0)
+			return (n);
+		if (!PACKET_COUNT_IS_UNLIMITED(cnt)) {
+			cnt -= n;
+			if (cnt <= 0)
+				return (0);
+		}
+	}
+}
+
+/*
+ * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate.
+ */
+void
+pcap_breakloop(pcap_t *p)
+{
+	p->breakloop_op(p);
+}
+
+int
+pcap_datalink(pcap_t *p)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	return (p->linktype);
+}
+
+int
+pcap_datalink_ext(pcap_t *p)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	return (p->linktype_ext);
+}
+
+int
+pcap_list_datalinks(pcap_t *p, int **dlt_buffer)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	if (p->dlt_count == 0) {
+		/*
+		 * We couldn't fetch the list of DLTs, which means
+		 * this platform doesn't support changing the
+		 * DLT for an interface.  Return a list of DLTs
+		 * containing only the DLT this device supports.
+		 */
+		*dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
+		if (*dlt_buffer == NULL) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+			    errno, "malloc");
+			return (PCAP_ERROR);
+		}
+		**dlt_buffer = p->linktype;
+		return (1);
+	} else {
+		*dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count);
+		if (*dlt_buffer == NULL) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+			    errno, "malloc");
+			return (PCAP_ERROR);
+		}
+		(void)memcpy(*dlt_buffer, p->dlt_list,
+		    sizeof(**dlt_buffer) * p->dlt_count);
+		return (p->dlt_count);
+	}
+}
+
+/*
+ * In Windows, you might have a library built with one version of the
+ * C runtime library and an application built with another version of
+ * the C runtime library, which means that the library might use one
+ * version of malloc() and free() and the application might use another
+ * version of malloc() and free().  If so, that means something
+ * allocated by the library cannot be freed by the application, so we
+ * need to have a pcap_free_datalinks() routine to free up the list
+ * allocated by pcap_list_datalinks(), even though it's just a wrapper
+ * around free().
+ */
+void
+pcap_free_datalinks(int *dlt_list)
+{
+	free(dlt_list);
+}
+
+int
+pcap_set_datalink(pcap_t *p, int dlt)
+{
+	int i;
+	const char *dlt_name;
+
+	if (dlt < 0)
+		goto unsupported;
+
+	if (p->dlt_count == 0 || p->set_datalink_op == NULL) {
+		/*
+		 * We couldn't fetch the list of DLTs, or we don't
+		 * have a "set datalink" operation, which means
+		 * this platform doesn't support changing the
+		 * DLT for an interface.  Check whether the new
+		 * DLT is the one this interface supports.
+		 */
+		if (p->linktype != dlt)
+			goto unsupported;
+
+		/*
+		 * It is, so there's nothing we need to do here.
+		 */
+		return (0);
+	}
+	for (i = 0; i < p->dlt_count; i++)
+		if (p->dlt_list[i] == (u_int)dlt)
+			break;
+	if (i >= p->dlt_count)
+		goto unsupported;
+	if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB &&
+	    dlt == DLT_DOCSIS) {
+		/*
+		 * This is presumably an Ethernet device, as the first
+		 * link-layer type it offers is DLT_EN10MB, and the only
+		 * other type it offers is DLT_DOCSIS.  That means that
+		 * we can't tell the driver to supply DOCSIS link-layer
+		 * headers - we're just pretending that's what we're
+		 * getting, as, presumably, we're capturing on a dedicated
+		 * link to a Cisco Cable Modem Termination System, and
+		 * it's putting raw DOCSIS frames on the wire inside low-level
+		 * Ethernet framing.
+		 */
+		p->linktype = dlt;
+		return (0);
+	}
+	if (p->set_datalink_op(p, dlt) == -1)
+		return (-1);
+	p->linktype = dlt;
+	return (0);
+
+unsupported:
+	dlt_name = pcap_datalink_val_to_name(dlt);
+	if (dlt_name != NULL) {
+		(void) snprintf(p->errbuf, sizeof(p->errbuf),
+		    "%s is not one of the DLTs supported by this device",
+		    dlt_name);
+	} else {
+		(void) snprintf(p->errbuf, sizeof(p->errbuf),
+		    "DLT %d is not one of the DLTs supported by this device",
+		    dlt);
+	}
+	return (-1);
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+	(u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003',
+	(u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007',
+	(u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013',
+	(u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017',
+	(u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023',
+	(u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027',
+	(u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033',
+	(u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037',
+	(u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043',
+	(u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047',
+	(u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053',
+	(u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057',
+	(u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063',
+	(u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067',
+	(u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073',
+	(u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077',
+	(u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143',
+	(u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
+	(u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
+	(u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
+	(u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
+	(u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
+	(u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133',
+	(u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137',
+	(u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143',
+	(u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
+	(u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
+	(u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
+	(u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
+	(u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
+	(u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173',
+	(u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177',
+	(u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203',
+	(u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207',
+	(u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213',
+	(u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217',
+	(u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223',
+	(u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227',
+	(u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233',
+	(u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237',
+	(u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243',
+	(u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247',
+	(u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253',
+	(u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257',
+	(u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263',
+	(u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267',
+	(u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273',
+	(u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277',
+	(u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343',
+	(u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
+	(u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
+	(u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
+	(u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
+	(u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
+	(u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333',
+	(u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337',
+	(u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343',
+	(u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
+	(u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
+	(u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
+	(u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
+	(u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
+	(u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373',
+	(u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377',
+};
+
+int
+pcap_strcasecmp(const char *s1, const char *s2)
+{
+	register const u_char	*cm = charmap,
+				*us1 = (const u_char *)s1,
+				*us2 = (const u_char *)s2;
+
+	while (cm[*us1] == cm[*us2++])
+		if (*us1++ == '\0')
+			return(0);
+	return (cm[*us1] - cm[*--us2]);
+}
+
+struct dlt_choice {
+	const char *name;
+	const char *description;
+	int	dlt;
+};
+
+#define DLT_CHOICE(code, description) { #code, description, DLT_ ## code }
+#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 }
+
+static struct dlt_choice dlt_choices[] = {
+	DLT_CHOICE(NULL, "BSD loopback"),
+	DLT_CHOICE(EN10MB, "Ethernet"),
+	DLT_CHOICE(IEEE802, "Token ring"),
+	DLT_CHOICE(ARCNET, "BSD ARCNET"),
+	DLT_CHOICE(SLIP, "SLIP"),
+	DLT_CHOICE(PPP, "PPP"),
+	DLT_CHOICE(FDDI, "FDDI"),
+	DLT_CHOICE(ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"),
+	DLT_CHOICE(RAW, "Raw IP"),
+	DLT_CHOICE(SLIP_BSDOS, "BSD/OS SLIP"),
+	DLT_CHOICE(PPP_BSDOS, "BSD/OS PPP"),
+	DLT_CHOICE(ATM_CLIP, "Linux Classical IP over ATM"),
+	DLT_CHOICE(PPP_SERIAL, "PPP over serial"),
+	DLT_CHOICE(PPP_ETHER, "PPPoE"),
+	DLT_CHOICE(SYMANTEC_FIREWALL, "Symantec Firewall"),
+	DLT_CHOICE(C_HDLC, "Cisco HDLC"),
+	DLT_CHOICE(IEEE802_11, "802.11"),
+	DLT_CHOICE(FRELAY, "Frame Relay"),
+	DLT_CHOICE(LOOP, "OpenBSD loopback"),
+	DLT_CHOICE(ENC, "OpenBSD encapsulated IP"),
+	DLT_CHOICE(LINUX_SLL, "Linux cooked v1"),
+	DLT_CHOICE(LTALK, "Localtalk"),
+	DLT_CHOICE(PFLOG, "OpenBSD pflog file"),
+	DLT_CHOICE(PFSYNC, "Packet filter state syncing"),
+	DLT_CHOICE(PRISM_HEADER, "802.11 plus Prism header"),
+	DLT_CHOICE(IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"),
+	DLT_CHOICE(SUNATM, "Sun raw ATM"),
+	DLT_CHOICE(IEEE802_11_RADIO, "802.11 plus radiotap header"),
+	DLT_CHOICE(ARCNET_LINUX, "Linux ARCNET"),
+	DLT_CHOICE(JUNIPER_MLPPP, "Juniper Multi-Link PPP"),
+	DLT_CHOICE(JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"),
+	DLT_CHOICE(JUNIPER_ES, "Juniper Encryption Services PIC"),
+	DLT_CHOICE(JUNIPER_GGSN, "Juniper GGSN PIC"),
+	DLT_CHOICE(JUNIPER_MFR, "Juniper FRF.16 Frame Relay"),
+	DLT_CHOICE(JUNIPER_ATM2, "Juniper ATM2 PIC"),
+	DLT_CHOICE(JUNIPER_SERVICES, "Juniper Advanced Services PIC"),
+	DLT_CHOICE(JUNIPER_ATM1, "Juniper ATM1 PIC"),
+	DLT_CHOICE(APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"),
+	DLT_CHOICE(MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"),
+	DLT_CHOICE(MTP2, "SS7 MTP2"),
+	DLT_CHOICE(MTP3, "SS7 MTP3"),
+	DLT_CHOICE(SCCP, "SS7 SCCP"),
+	DLT_CHOICE(DOCSIS, "DOCSIS"),
+	DLT_CHOICE(LINUX_IRDA, "Linux IrDA"),
+	DLT_CHOICE(IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"),
+	DLT_CHOICE(JUNIPER_MONITOR, "Juniper Passive Monitor PIC"),
+	DLT_CHOICE(BACNET_MS_TP, "BACnet MS/TP"),
+	DLT_CHOICE(PPP_PPPD, "PPP for pppd, with direction flag"),
+	DLT_CHOICE(JUNIPER_PPPOE, "Juniper PPPoE"),
+	DLT_CHOICE(JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"),
+	DLT_CHOICE(GPRS_LLC, "GPRS LLC"),
+	DLT_CHOICE(GPF_T, "GPF-T"),
+	DLT_CHOICE(GPF_F, "GPF-F"),
+	DLT_CHOICE(JUNIPER_PIC_PEER, "Juniper PIC Peer"),
+	DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"),
+	DLT_CHOICE(ERF_POS, "Packet-over-SONET with Endace ERF header"),
+	DLT_CHOICE(LINUX_LAPD, "Linux vISDN LAPD"),
+	DLT_CHOICE(JUNIPER_ETHER, "Juniper Ethernet"),
+	DLT_CHOICE(JUNIPER_PPP, "Juniper PPP"),
+	DLT_CHOICE(JUNIPER_FRELAY, "Juniper Frame Relay"),
+	DLT_CHOICE(JUNIPER_CHDLC, "Juniper C-HDLC"),
+	DLT_CHOICE(MFR, "FRF.16 Frame Relay"),
+	DLT_CHOICE(JUNIPER_VP, "Juniper Voice PIC"),
+	DLT_CHOICE(A429, "Arinc 429"),
+	DLT_CHOICE(A653_ICM, "Arinc 653 Interpartition Communication"),
+	DLT_CHOICE(USB_FREEBSD, "USB with FreeBSD header"),
+	DLT_CHOICE(BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"),
+	DLT_CHOICE(IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"),
+	DLT_CHOICE(USB_LINUX, "USB with Linux header"),
+	DLT_CHOICE(CAN20B, "Controller Area Network (CAN) v. 2.0B"),
+	DLT_CHOICE(IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"),
+	DLT_CHOICE(PPI, "Per-Packet Information"),
+	DLT_CHOICE(IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"),
+	DLT_CHOICE(JUNIPER_ISM, "Juniper Integrated Service Module"),
+	DLT_CHOICE(IEEE802_15_4, "IEEE 802.15.4 with FCS"),
+	DLT_CHOICE(SITA, "SITA pseudo-header"),
+	DLT_CHOICE(ERF, "Endace ERF header"),
+	DLT_CHOICE(RAIF1, "Ethernet with u10 Networks pseudo-header"),
+	DLT_CHOICE(IPMB_KONTRON, "IPMB with Kontron pseudo-header"),
+	DLT_CHOICE(JUNIPER_ST, "Juniper Secure Tunnel"),
+	DLT_CHOICE(BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"),
+	DLT_CHOICE(AX25_KISS, "AX.25 with KISS header"),
+	DLT_CHOICE(IPMB_LINUX, "IPMB with Linux/Pigeon Point pseudo-header"),
+	DLT_CHOICE(IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"),
+	DLT_CHOICE(MPLS, "MPLS with label as link-layer header"),
+	DLT_CHOICE(LINUX_EVDEV, "Linux evdev events"),
+	DLT_CHOICE(USB_LINUX_MMAPPED, "USB with padded Linux header"),
+	DLT_CHOICE(DECT, "DECT"),
+	DLT_CHOICE(AOS, "AOS Space Data Link protocol"),
+	DLT_CHOICE(WIHART, "Wireless HART"),
+	DLT_CHOICE(FC_2, "Fibre Channel FC-2"),
+	DLT_CHOICE(FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"),
+	DLT_CHOICE(IPNET, "Solaris ipnet"),
+	DLT_CHOICE(CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"),
+	DLT_CHOICE(IPV4, "Raw IPv4"),
+	DLT_CHOICE(IPV6, "Raw IPv6"),
+	DLT_CHOICE(IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"),
+	DLT_CHOICE(DBUS, "D-Bus"),
+	DLT_CHOICE(JUNIPER_VS, "Juniper Virtual Server"),
+	DLT_CHOICE(JUNIPER_SRX_E2E, "Juniper SRX E2E"),
+	DLT_CHOICE(JUNIPER_FIBRECHANNEL, "Juniper Fibre Channel"),
+	DLT_CHOICE(DVB_CI, "DVB-CI"),
+	DLT_CHOICE(MUX27010, "MUX27010"),
+	DLT_CHOICE(STANAG_5066_D_PDU, "STANAG 5066 D_PDUs"),
+	DLT_CHOICE(JUNIPER_ATM_CEMIC, "Juniper ATM CEMIC"),
+	DLT_CHOICE(NFLOG, "Linux netfilter log messages"),
+	DLT_CHOICE(NETANALYZER, "Ethernet with Hilscher netANALYZER pseudo-header"),
+	DLT_CHOICE(NETANALYZER_TRANSPARENT, "Ethernet with Hilscher netANALYZER pseudo-header and with preamble and SFD"),
+	DLT_CHOICE(IPOIB, "RFC 4391 IP-over-Infiniband"),
+	DLT_CHOICE(MPEG_2_TS, "MPEG-2 transport stream"),
+	DLT_CHOICE(NG40, "ng40 protocol tester Iub/Iur"),
+	DLT_CHOICE(NFC_LLCP, "NFC LLCP PDUs with pseudo-header"),
+	DLT_CHOICE(INFINIBAND, "InfiniBand"),
+	DLT_CHOICE(SCTP, "SCTP"),
+	DLT_CHOICE(USBPCAP, "USB with USBPcap header"),
+	DLT_CHOICE(RTAC_SERIAL, "Schweitzer Engineering Laboratories RTAC packets"),
+	DLT_CHOICE(BLUETOOTH_LE_LL, "Bluetooth Low Energy air interface"),
+	DLT_CHOICE(NETLINK, "Linux netlink"),
+	DLT_CHOICE(BLUETOOTH_LINUX_MONITOR, "Bluetooth Linux Monitor"),
+	DLT_CHOICE(BLUETOOTH_BREDR_BB, "Bluetooth Basic Rate/Enhanced Data Rate baseband packets"),
+	DLT_CHOICE(BLUETOOTH_LE_LL_WITH_PHDR, "Bluetooth Low Energy air interface with pseudo-header"),
+	DLT_CHOICE(PROFIBUS_DL, "PROFIBUS data link layer"),
+	DLT_CHOICE(PKTAP, "Apple DLT_PKTAP"),
+	DLT_CHOICE(EPON, "Ethernet with 802.3 Clause 65 EPON preamble"),
+	DLT_CHOICE(IPMI_HPM_2, "IPMI trace packets"),
+	DLT_CHOICE(ZWAVE_R1_R2, "Z-Wave RF profile R1 and R2 packets"),
+	DLT_CHOICE(ZWAVE_R3, "Z-Wave RF profile R3 packets"),
+	DLT_CHOICE(WATTSTOPPER_DLM, "WattStopper Digital Lighting Management (DLM) and Legrand Nitoo Open protocol"),
+	DLT_CHOICE(ISO_14443, "ISO 14443 messages"),
+	DLT_CHOICE(RDS, "IEC 62106 Radio Data System groups"),
+	DLT_CHOICE(USB_DARWIN, "USB with Darwin header"),
+	DLT_CHOICE(OPENFLOW, "OpenBSD DLT_OPENFLOW"),
+	DLT_CHOICE(SDLC, "IBM SDLC frames"),
+	DLT_CHOICE(TI_LLN_SNIFFER, "TI LLN sniffer frames"),
+	DLT_CHOICE(VSOCK, "Linux vsock"),
+	DLT_CHOICE(NORDIC_BLE, "Nordic Semiconductor Bluetooth LE sniffer frames"),
+	DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"),
+	DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"),
+	DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"),
+	DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"),
+	DLT_CHOICE(OPENVIZSLA, "OpenVizsla USB"),
+	DLT_CHOICE(EBHSCR, "Elektrobit High Speed Capture and Replay (EBHSCR)"),
+	DLT_CHOICE(VPP_DISPATCH, "VPP graph dispatch tracer"),
+	DLT_CHOICE(DSA_TAG_BRCM, "Broadcom tag"),
+	DLT_CHOICE(DSA_TAG_BRCM_PREPEND, "Broadcom tag (prepended)"),
+	DLT_CHOICE(IEEE802_15_4_TAP, "IEEE 802.15.4 with pseudo-header"),
+	DLT_CHOICE(DSA_TAG_DSA, "Marvell DSA"),
+	DLT_CHOICE(DSA_TAG_EDSA, "Marvell EDSA"),
+	DLT_CHOICE(ELEE, "ELEE lawful intercept packets"),
+	DLT_CHOICE(Z_WAVE_SERIAL, "Z-Wave serial frames between host and chip"),
+	DLT_CHOICE(USB_2_0, "USB 2.0/1.1/1.0 as transmitted over the cable"),
+	DLT_CHOICE(ATSC_ALP, "ATSC Link-Layer Protocol packets"),
+	DLT_CHOICE_SENTINEL
+};
+
+int
+pcap_datalink_name_to_val(const char *name)
+{
+	int i;
+
+	for (i = 0; dlt_choices[i].name != NULL; i++) {
+		if (pcap_strcasecmp(dlt_choices[i].name, name) == 0)
+			return (dlt_choices[i].dlt);
+	}
+	return (-1);
+}
+
+const char *
+pcap_datalink_val_to_name(int dlt)
+{
+	int i;
+
+	for (i = 0; dlt_choices[i].name != NULL; i++) {
+		if (dlt_choices[i].dlt == dlt)
+			return (dlt_choices[i].name);
+	}
+	return (NULL);
+}
+
+const char *
+pcap_datalink_val_to_description(int dlt)
+{
+	int i;
+
+	for (i = 0; dlt_choices[i].name != NULL; i++) {
+		if (dlt_choices[i].dlt == dlt)
+			return (dlt_choices[i].description);
+	}
+	return (NULL);
+}
+
+const char *
+pcap_datalink_val_to_description_or_dlt(int dlt)
+{
+        static char unkbuf[40];
+        const char *description;
+
+        description = pcap_datalink_val_to_description(dlt);
+        if (description != NULL) {
+                return description;
+        } else {
+                (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
+                return unkbuf;
+        }
+}
+
+struct tstamp_type_choice {
+	const char *name;
+	const char *description;
+	int	type;
+};
+
+static struct tstamp_type_choice tstamp_type_choices[] = {
+	{ "host", "Host", PCAP_TSTAMP_HOST },
+	{ "host_lowprec", "Host, low precision", PCAP_TSTAMP_HOST_LOWPREC },
+	{ "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC },
+	{ "adapter", "Adapter", PCAP_TSTAMP_ADAPTER },
+	{ "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED },
+	{ "host_hiprec_unsynced", "Host, high precision, not synced with system time", PCAP_TSTAMP_HOST_HIPREC_UNSYNCED },
+	{ NULL, NULL, 0 }
+};
+
+int
+pcap_tstamp_type_name_to_val(const char *name)
+{
+	int i;
+
+	for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+		if (pcap_strcasecmp(tstamp_type_choices[i].name, name) == 0)
+			return (tstamp_type_choices[i].type);
+	}
+	return (PCAP_ERROR);
+}
+
+const char *
+pcap_tstamp_type_val_to_name(int tstamp_type)
+{
+	int i;
+
+	for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+		if (tstamp_type_choices[i].type == tstamp_type)
+			return (tstamp_type_choices[i].name);
+	}
+	return (NULL);
+}
+
+const char *
+pcap_tstamp_type_val_to_description(int tstamp_type)
+{
+	int i;
+
+	for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+		if (tstamp_type_choices[i].type == tstamp_type)
+			return (tstamp_type_choices[i].description);
+	}
+	return (NULL);
+}
+
+int
+pcap_snapshot(pcap_t *p)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	return (p->snapshot);
+}
+
+int
+pcap_is_swapped(pcap_t *p)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	return (p->swapped);
+}
+
+int
+pcap_major_version(pcap_t *p)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	return (p->version_major);
+}
+
+int
+pcap_minor_version(pcap_t *p)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	return (p->version_minor);
+}
+
+int
+pcap_bufsize(pcap_t *p)
+{
+	if (!p->activated)
+		return (PCAP_ERROR_NOT_ACTIVATED);
+	return (p->bufsize);
+}
+
+FILE *
+pcap_file(pcap_t *p)
+{
+	return (p->rfile);
+}
+
+#ifdef _WIN32
+int
+pcap_fileno(pcap_t *p)
+{
+	if (p->handle != INVALID_HANDLE_VALUE) {
+		/*
+		 * This is a bogus and now-deprecated API; we
+		 * squelch the narrowing warning for the cast
+		 * from HANDLE to DWORD.  If Windows programmmers
+		 * need to get at the HANDLE for a pcap_t, *if*
+		 * there is one, they should request such a
+		 * routine (and be prepared for it to return
+		 * INVALID_HANDLE_VALUE).
+		 */
+DIAG_OFF_NARROWING
+		return ((int)(DWORD)p->handle);
+DIAG_ON_NARROWING
+	} else
+		return (PCAP_ERROR);
+}
+#else /* _WIN32 */
+int
+pcap_fileno(pcap_t *p)
+{
+	return (p->fd);
+}
+#endif /* _WIN32 */
+
+#if !defined(_WIN32) && !defined(MSDOS)
+int
+pcap_get_selectable_fd(pcap_t *p)
+{
+	return (p->selectable_fd);
+}
+
+const struct timeval *
+pcap_get_required_select_timeout(pcap_t *p)
+{
+	return (p->required_select_timeout);
+}
+#endif
+
+void
+pcap_perror(pcap_t *p, const char *prefix)
+{
+	fprintf(stderr, "%s: %s\n", prefix, p->errbuf);
+}
+
+char *
+pcap_geterr(pcap_t *p)
+{
+	return (p->errbuf);
+}
+
+int
+pcap_getnonblock(pcap_t *p, char *errbuf)
+{
+	int ret;
+
+	ret = p->getnonblock_op(p);
+	if (ret == -1) {
+		/*
+		 * The get nonblock operation sets p->errbuf; this
+		 * function *shouldn't* have had a separate errbuf
+		 * argument, as it didn't need one, but I goofed
+		 * when adding it.
+		 *
+		 * We copy the error message to errbuf, so callers
+		 * can find it in either place.
+		 */
+		pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+	}
+	return (ret);
+}
+
+/*
+ * Get the current non-blocking mode setting, under the assumption that
+ * it's just the standard POSIX non-blocking flag.
+ */
+#if !defined(_WIN32) && !defined(MSDOS)
+int
+pcap_getnonblock_fd(pcap_t *p)
+{
+	int fdflags;
+
+	fdflags = fcntl(p->fd, F_GETFL, 0);
+	if (fdflags == -1) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "F_GETFL");
+		return (-1);
+	}
+	if (fdflags & O_NONBLOCK)
+		return (1);
+	else
+		return (0);
+}
+#endif
+
+int
+pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
+{
+	int ret;
+
+	ret = p->setnonblock_op(p, nonblock);
+	if (ret == -1) {
+		/*
+		 * The set nonblock operation sets p->errbuf; this
+		 * function *shouldn't* have had a separate errbuf
+		 * argument, as it didn't need one, but I goofed
+		 * when adding it.
+		 *
+		 * We copy the error message to errbuf, so callers
+		 * can find it in either place.
+		 */
+		pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+	}
+	return (ret);
+}
+
+#if !defined(_WIN32) && !defined(MSDOS)
+/*
+ * Set non-blocking mode, under the assumption that it's just the
+ * standard POSIX non-blocking flag.  (This can be called by the
+ * per-platform non-blocking-mode routine if that routine also
+ * needs to do some additional work.)
+ */
+int
+pcap_setnonblock_fd(pcap_t *p, int nonblock)
+{
+	int fdflags;
+
+	fdflags = fcntl(p->fd, F_GETFL, 0);
+	if (fdflags == -1) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "F_GETFL");
+		return (-1);
+	}
+	if (nonblock)
+		fdflags |= O_NONBLOCK;
+	else
+		fdflags &= ~O_NONBLOCK;
+	if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "F_SETFL");
+		return (-1);
+	}
+	return (0);
+}
+#endif
+
+/*
+ * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values.
+ */
+const char *
+pcap_statustostr(int errnum)
+{
+	static char ebuf[15+10+1];
+
+	switch (errnum) {
+
+	case PCAP_WARNING:
+		return("Generic warning");
+
+	case PCAP_WARNING_TSTAMP_TYPE_NOTSUP:
+		return ("That type of time stamp is not supported by that device");
+
+	case PCAP_WARNING_PROMISC_NOTSUP:
+		return ("That device doesn't support promiscuous mode");
+
+	case PCAP_ERROR:
+		return("Generic error");
+
+	case PCAP_ERROR_BREAK:
+		return("Loop terminated by pcap_breakloop");
+
+	case PCAP_ERROR_NOT_ACTIVATED:
+		return("The pcap_t has not been activated");
+
+	case PCAP_ERROR_ACTIVATED:
+		return ("The setting can't be changed after the pcap_t is activated");
+
+	case PCAP_ERROR_NO_SUCH_DEVICE:
+		return ("No such device exists");
+
+	case PCAP_ERROR_RFMON_NOTSUP:
+		return ("That device doesn't support monitor mode");
+
+	case PCAP_ERROR_NOT_RFMON:
+		return ("That operation is supported only in monitor mode");
+
+	case PCAP_ERROR_PERM_DENIED:
+		return ("You don't have permission to capture on that device");
+
+	case PCAP_ERROR_IFACE_NOT_UP:
+		return ("That device is not up");
+
+	case PCAP_ERROR_CANTSET_TSTAMP_TYPE:
+		return ("That device doesn't support setting the time stamp type");
+
+	case PCAP_ERROR_PROMISC_PERM_DENIED:
+		return ("You don't have permission to capture in promiscuous mode on that device");
+
+	case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP:
+		return ("That device doesn't support that time stamp precision");
+	}
+	(void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
+	return(ebuf);
+}
+
+/*
+ * Not all systems have strerror().
+ */
+const char *
+pcap_strerror(int errnum)
+{
+#ifdef HAVE_STRERROR
+#ifdef _WIN32
+	static char errbuf[PCAP_ERRBUF_SIZE];
+	errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
+
+	if (err != 0) /* err = 0 if successful */
+		pcap_strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE);
+	return (errbuf);
+#else
+	return (strerror(errnum));
+#endif /* _WIN32 */
+#else
+	extern int sys_nerr;
+	extern const char *const sys_errlist[];
+	static char errbuf[PCAP_ERRBUF_SIZE];
+
+	if ((unsigned int)errnum < sys_nerr)
+		return ((char *)sys_errlist[errnum]);
+	(void)snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
+	return (errbuf);
+#endif
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+	return (p->setfilter_op(p, fp));
+}
+
+/*
+ * Set direction flag, which controls whether we accept only incoming
+ * packets, only outgoing packets, or both.
+ * Note that, depending on the platform, some or all direction arguments
+ * might not be supported.
+ */
+int
+pcap_setdirection(pcap_t *p, pcap_direction_t d)
+{
+	if (p->setdirection_op == NULL) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "Setting direction is not supported on this device");
+		return (-1);
+	} else {
+		switch (d) {
+
+		case PCAP_D_IN:
+		case PCAP_D_OUT:
+		case PCAP_D_INOUT:
+			/*
+			 * Valid direction.
+			 */
+			return (p->setdirection_op(p, d));
+
+		default:
+			/*
+			 * Invalid direction.
+			 */
+			snprintf(p->errbuf, sizeof(p->errbuf),
+			    "Invalid direction");
+			return (-1);
+		}
+	}
+}
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+	return (p->stats_op(p, ps));
+}
+
+#ifdef _WIN32
+struct pcap_stat *
+pcap_stats_ex(pcap_t *p, int *pcap_stat_size)
+{
+	return (p->stats_ex_op(p, pcap_stat_size));
+}
+
+int
+pcap_setbuff(pcap_t *p, int dim)
+{
+	return (p->setbuff_op(p, dim));
+}
+
+int
+pcap_setmode(pcap_t *p, int mode)
+{
+	return (p->setmode_op(p, mode));
+}
+
+int
+pcap_setmintocopy(pcap_t *p, int size)
+{
+	return (p->setmintocopy_op(p, size));
+}
+
+HANDLE
+pcap_getevent(pcap_t *p)
+{
+	return (p->getevent_op(p));
+}
+
+int
+pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp)
+{
+	return (p->oid_get_request_op(p, oid, data, lenp));
+}
+
+int
+pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp)
+{
+	return (p->oid_set_request_op(p, oid, data, lenp));
+}
+
+pcap_send_queue *
+pcap_sendqueue_alloc(u_int memsize)
+{
+	pcap_send_queue *tqueue;
+
+	/* Allocate the queue */
+	tqueue = (pcap_send_queue *)malloc(sizeof(pcap_send_queue));
+	if (tqueue == NULL){
+		return (NULL);
+	}
+
+	/* Allocate the buffer */
+	tqueue->buffer = (char *)malloc(memsize);
+	if (tqueue->buffer == NULL) {
+		free(tqueue);
+		return (NULL);
+	}
+
+	tqueue->maxlen = memsize;
+	tqueue->len = 0;
+
+	return (tqueue);
+}
+
+void
+pcap_sendqueue_destroy(pcap_send_queue *queue)
+{
+	free(queue->buffer);
+	free(queue);
+}
+
+int
+pcap_sendqueue_queue(pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)
+{
+	if (queue->len + sizeof(struct pcap_pkthdr) + pkt_header->caplen > queue->maxlen){
+		return (-1);
+	}
+
+	/* Copy the pcap_pkthdr header*/
+	memcpy(queue->buffer + queue->len, pkt_header, sizeof(struct pcap_pkthdr));
+	queue->len += sizeof(struct pcap_pkthdr);
+
+	/* copy the packet */
+	memcpy(queue->buffer + queue->len, pkt_data, pkt_header->caplen);
+	queue->len += pkt_header->caplen;
+
+	return (0);
+}
+
+u_int
+pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
+{
+	return (p->sendqueue_transmit_op(p, queue, sync));
+}
+
+int
+pcap_setuserbuffer(pcap_t *p, int size)
+{
+	return (p->setuserbuffer_op(p, size));
+}
+
+int
+pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
+{
+	return (p->live_dump_op(p, filename, maxsize, maxpacks));
+}
+
+int
+pcap_live_dump_ended(pcap_t *p, int sync)
+{
+	return (p->live_dump_ended_op(p, sync));
+}
+
+PAirpcapHandle
+pcap_get_airpcap_handle(pcap_t *p)
+{
+	PAirpcapHandle handle;
+
+	handle = p->get_airpcap_handle_op(p);
+	if (handle == NULL) {
+		(void)snprintf(p->errbuf, sizeof(p->errbuf),
+		    "This isn't an AirPcap device");
+	}
+	return (handle);
+}
+#endif
+
+/*
+ * On some platforms, we need to clean up promiscuous or monitor mode
+ * when we close a device - and we want that to happen even if the
+ * application just exits without explicitl closing devices.
+ * On those platforms, we need to register a "close all the pcaps"
+ * routine to be called when we exit, and need to maintain a list of
+ * pcaps that need to be closed to clean up modes.
+ *
+ * XXX - not thread-safe.
+ */
+
+/*
+ * List of pcaps on which we've done something that needs to be
+ * cleaned up.
+ * If there are any such pcaps, we arrange to call "pcap_close_all()"
+ * when we exit, and have it close all of them.
+ */
+static struct pcap *pcaps_to_close;
+
+/*
+ * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to
+ * be called on exit.
+ */
+static int did_atexit;
+
+static void
+pcap_close_all(void)
+{
+	struct pcap *handle;
+
+	while ((handle = pcaps_to_close) != NULL) {
+		pcap_close(handle);
+
+		/*
+		 * If a pcap module adds a pcap_t to the "close all"
+		 * list by calling pcap_add_to_pcaps_to_close(), it
+		 * must have a cleanup routine that removes it from the
+		 * list, by calling pcap_remove_from_pcaps_to_close(),
+		 * and must make that cleanup routine the cleanup_op
+		 * for the pcap_t.
+		 *
+		 * That means that, after pcap_close() - which calls
+		 * the cleanup_op for the pcap_t - the pcap_t must
+		 * have been removed from the list, so pcaps_to_close
+		 * must not be equal to handle.
+		 *
+		 * We check for that, and abort if handle is still
+		 * at the head of the list, to prevent infinite loops.
+		 */
+		if (pcaps_to_close == handle)
+			abort();
+	}
+}
+
+int
+pcap_do_addexit(pcap_t *p)
+{
+	/*
+	 * If we haven't already done so, arrange to have
+	 * "pcap_close_all()" called when we exit.
+	 */
+	if (!did_atexit) {
+		if (atexit(pcap_close_all) != 0) {
+			/*
+			 * "atexit()" failed; let our caller know.
+			 */
+			pcap_strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE);
+			return (0);
+		}
+		did_atexit = 1;
+	}
+	return (1);
+}
+
+void
+pcap_add_to_pcaps_to_close(pcap_t *p)
+{
+	p->next = pcaps_to_close;
+	pcaps_to_close = p;
+}
+
+void
+pcap_remove_from_pcaps_to_close(pcap_t *p)
+{
+	pcap_t *pc, *prevpc;
+
+	for (pc = pcaps_to_close, prevpc = NULL; pc != NULL;
+	    prevpc = pc, pc = pc->next) {
+		if (pc == p) {
+			/*
+			 * Found it.  Remove it from the list.
+			 */
+			if (prevpc == NULL) {
+				/*
+				 * It was at the head of the list.
+				 */
+				pcaps_to_close = pc->next;
+			} else {
+				/*
+				 * It was in the middle of the list.
+				 */
+				prevpc->next = pc->next;
+			}
+			break;
+		}
+	}
+}
+
+void
+pcap_breakloop_common(pcap_t *p)
+{
+	p->break_loop = 1;
+}
+
+
+void
+pcap_cleanup_live_common(pcap_t *p)
+{
+	if (p->buffer != NULL) {
+		free(p->buffer);
+		p->buffer = NULL;
+	}
+	if (p->dlt_list != NULL) {
+		free(p->dlt_list);
+		p->dlt_list = NULL;
+		p->dlt_count = 0;
+	}
+	if (p->tstamp_type_list != NULL) {
+		free(p->tstamp_type_list);
+		p->tstamp_type_list = NULL;
+		p->tstamp_type_count = 0;
+	}
+	if (p->tstamp_precision_list != NULL) {
+		free(p->tstamp_precision_list);
+		p->tstamp_precision_list = NULL;
+		p->tstamp_precision_count = 0;
+	}
+	pcap_freecode(&p->fcode);
+#if !defined(_WIN32) && !defined(MSDOS)
+	if (p->fd >= 0) {
+		close(p->fd);
+		p->fd = -1;
+	}
+	p->selectable_fd = -1;
+#endif
+}
+
+/*
+ * API compatible with WinPcap's "send a packet" routine - returns -1
+ * on error, 0 otherwise.
+ *
+ * XXX - what if we get a short write?
+ */
+int
+pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
+{
+	if (size <= 0) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "The number of bytes to be sent must be positive");
+		return (PCAP_ERROR);
+	}
+
+	if (p->inject_op(p, buf, size) == -1)
+		return (-1);
+	return (0);
+}
+
+/*
+ * API compatible with OpenBSD's "send a packet" routine - returns -1 on
+ * error, number of bytes written otherwise.
+ */
+int
+pcap_inject(pcap_t *p, const void *buf, size_t size)
+{
+	/*
+	 * We return the number of bytes written, so the number of
+	 * bytes to write must fit in an int.
+	 */
+	if (size > INT_MAX) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "More than %d bytes cannot be injected", INT_MAX);
+		return (PCAP_ERROR);
+	}
+
+	if (size == 0) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "The number of bytes to be injected must not be zero");
+		return (PCAP_ERROR);
+	}
+
+	return (p->inject_op(p, buf, (int)size));
+}
+
+void
+pcap_close(pcap_t *p)
+{
+	if (p->opt.device != NULL)
+		free(p->opt.device);
+	p->cleanup_op(p);
+	free(p);
+}
+
+/*
+ * Helpers for safely loding code at run time.
+ * Currently Windows-only.
+ */
+#ifdef _WIN32
+//
+// This wrapper around loadlibrary appends the system folder (usually
+// C:\Windows\System32) to the relative path of the DLL, so that the DLL
+// is always loaded from an absolute path (it's no longer possible to
+// load modules from the application folder).
+// This solves the DLL Hijacking issue discovered in August 2010:
+//
+// https://blog.rapid7.com/2010/08/23/exploiting-dll-hijacking-flaws/
+// https://blog.rapid7.com/2010/08/23/application-dll-load-hijacking/
+// (the purported Rapid7 blog post link in the first of those two links
+// is broken; the second of those links works.)
+//
+// If any links there are broken from all the content shuffling Rapid&
+// did, see archived versions of the posts at their original homes, at
+//
+// https://web.archive.org/web/20110122175058/http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
+// https://web.archive.org/web/20100828112111/http://blog.rapid7.com/?p=5325
+//
+pcap_code_handle_t
+pcap_load_code(const char *name)
+{
+	/*
+	 * XXX - should this work in UTF-16LE rather than in the local
+	 * ANSI code page?
+	 */
+	CHAR path[MAX_PATH];
+	CHAR fullFileName[MAX_PATH];
+	UINT res;
+	HMODULE hModule = NULL;
+
+	do
+	{
+		res = GetSystemDirectoryA(path, MAX_PATH);
+
+		if (res == 0) {
+			//
+			// some bad failure occurred;
+			//
+			break;
+		}
+
+		if (res > MAX_PATH) {
+			//
+			// the buffer was not big enough
+			//
+			SetLastError(ERROR_INSUFFICIENT_BUFFER);
+			break;
+		}
+
+		if (res + 1 + strlen(name) + 1 < MAX_PATH) {
+			memcpy(fullFileName, path, res * sizeof(TCHAR));
+			fullFileName[res] = '\\';
+			memcpy(&fullFileName[res + 1], name, (strlen(name) + 1) * sizeof(TCHAR));
+
+			hModule = LoadLibraryA(fullFileName);
+		} else
+			SetLastError(ERROR_INSUFFICIENT_BUFFER);
+
+	} while(FALSE);
+
+	return hModule;
+}
+
+pcap_funcptr_t
+pcap_find_function(pcap_code_handle_t code, const char *func)
+{
+	return (GetProcAddress(code, func));
+}
+#endif
+
+/*
+ * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw
+ * data for the packet, check whether the packet passes the filter.
+ * Returns the return value of the filter program, which will be zero if
+ * the packet doesn't pass and non-zero if the packet does pass.
+ */
+int
+pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
+    const u_char *pkt)
+{
+	const struct bpf_insn *fcode = fp->bf_insns;
+
+	if (fcode != NULL)
+		return (pcap_filter(fcode, pkt, h->len, h->caplen));
+	else
+		return (0);
+}
+
+static int
+pcap_can_set_rfmon_dead(pcap_t *p)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
+	return (PCAP_ERROR);
+}
+
+static int
+pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
+    u_char *user _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Packets aren't available from a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Packets can't be sent on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "A filter cannot be set on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The packet direction cannot be set on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_getnonblock_dead(pcap_t *p)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+	return (-1);
+}
+
+static int
+pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+	return (-1);
+}
+
+static int
+pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Statistics aren't available from a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+#ifdef _WIN32
+static struct pcap_stat *
+pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Statistics aren't available from a pcap_open_dead pcap_t");
+	return (NULL);
+}
+
+static int
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_setmode_dead(pcap_t *p, int mode _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "impossible to set mode on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static HANDLE
+pcap_getevent_dead(pcap_t *p)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "A pcap_open_dead pcap_t has no event handle");
+	return (INVALID_HANDLE_VALUE);
+}
+
+static int
+pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+    size_t *lenp _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "An OID get request cannot be performed on a pcap_open_dead pcap_t");
+	return (PCAP_ERROR);
+}
+
+static int
+pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+    size_t *lenp _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "An OID set request cannot be performed on a pcap_open_dead pcap_t");
+	return (PCAP_ERROR);
+}
+
+static u_int
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+    int sync _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Packets cannot be transmitted on a pcap_open_dead pcap_t");
+	return (0);
+}
+
+static int
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The user buffer cannot be set on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static int
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static PAirpcapHandle
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
+{
+	return (NULL);
+}
+#endif /* _WIN32 */
+
+static void
+pcap_cleanup_dead(pcap_t *p _U_)
+{
+	/* Nothing to do. */
+}
+
+pcap_t *
+pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
+{
+	pcap_t *p;
+
+	switch (precision) {
+
+	case PCAP_TSTAMP_PRECISION_MICRO:
+	case PCAP_TSTAMP_PRECISION_NANO:
+		break;
+
+	default:
+		/*
+		 * This doesn't really matter, but we don't have any way
+		 * to report particular errors, so the only failure we
+		 * should have is a memory allocation failure.  Just
+		 * pick microsecond precision.
+		 */
+		precision = PCAP_TSTAMP_PRECISION_MICRO;
+		break;
+	}
+	p = malloc(sizeof(*p));
+	if (p == NULL)
+		return NULL;
+	memset (p, 0, sizeof(*p));
+	p->snapshot = snaplen;
+	p->linktype = linktype;
+	p->opt.tstamp_precision = precision;
+	p->can_set_rfmon_op = pcap_can_set_rfmon_dead;
+	p->read_op = pcap_read_dead;
+	p->inject_op = pcap_inject_dead;
+	p->setfilter_op = pcap_setfilter_dead;
+	p->setdirection_op = pcap_setdirection_dead;
+	p->set_datalink_op = pcap_set_datalink_dead;
+	p->getnonblock_op = pcap_getnonblock_dead;
+	p->setnonblock_op = pcap_setnonblock_dead;
+	p->stats_op = pcap_stats_dead;
+#ifdef _WIN32
+	p->stats_ex_op = pcap_stats_ex_dead;
+	p->setbuff_op = pcap_setbuff_dead;
+	p->setmode_op = pcap_setmode_dead;
+	p->setmintocopy_op = pcap_setmintocopy_dead;
+	p->getevent_op = pcap_getevent_dead;
+	p->oid_get_request_op = pcap_oid_get_request_dead;
+	p->oid_set_request_op = pcap_oid_set_request_dead;
+	p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead;
+	p->setuserbuffer_op = pcap_setuserbuffer_dead;
+	p->live_dump_op = pcap_live_dump_dead;
+	p->live_dump_ended_op = pcap_live_dump_ended_dead;
+	p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead;
+#endif
+	p->cleanup_op = pcap_cleanup_dead;
+
+	/*
+	 * A "dead" pcap_t never requires special BPF code generation.
+	 */
+	p->bpf_codegen_flags = 0;
+
+	p->activated = 1;
+	return (p);
+}
+
+pcap_t *
+pcap_open_dead(int linktype, int snaplen)
+{
+	return (pcap_open_dead_with_tstamp_precision(linktype, snaplen,
+	    PCAP_TSTAMP_PRECISION_MICRO));
+}
+
+#ifdef YYDEBUG
+/*
+ * Set the internal "debug printout" flag for the filter expression parser.
+ * The code to print that stuff is present only if YYDEBUG is defined, so
+ * the flag, and the routine to set it, are defined only if YYDEBUG is
+ * defined.
+ *
+ * This is intended for libpcap developers, not for general use.
+ * If you want to set these in a program, you'll have to declare this
+ * routine yourself, with the appropriate DLL import attribute on Windows;
+ * it's not declared in any header file, and won't be declared in any
+ * header file provided by libpcap.
+ */
+PCAP_API void pcap_set_parser_debug(int value);
+
+PCAP_API_DEF void
+pcap_set_parser_debug(int value)
+{
+	pcap_debug = value;
+}
+#endif
diff --git a/pcap.h b/pcap.h
new file mode 100644
index 0000000..174e32d
--- /dev/null
+++ b/pcap.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * For backwards compatibility.
+ *
+ * Note to OS vendors: do NOT get rid of this file!  Many applications
+ * expect to be able to include <pcap.h>, and at least some of them
+ * go through contortions in their configure scripts to try to detect
+ * OSes that have "helpfully" moved pcap.h to <pcap/pcap.h> without
+ * leaving behind a <pcap.h> file.
+ */
+#include <pcap/pcap.h>
diff --git a/pcap/bpf.h b/pcap/bpf.h
new file mode 100644
index 0000000..54373af
--- /dev/null
+++ b/pcap/bpf.h
@@ -0,0 +1,292 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)bpf.h       7.1 (Berkeley) 5/7/91
+ */
+
+/*
+ * This is libpcap's cut-down version of bpf.h; it includes only
+ * the stuff needed for the code generator and the userland BPF
+ * interpreter, and the libpcap APIs for setting filters, etc..
+ *
+ * "pcap-bpf.c" will include the native OS version, as it deals with
+ * the OS's BPF implementation.
+ *
+ * At least two programs found by Google Code Search explicitly includes
+ * <pcap/bpf.h> (even though <pcap.h>/<pcap/pcap.h> includes it for you),
+ * so moving that stuff to <pcap/pcap.h> would break the build for some
+ * programs.
+ */
+
+/*
+ * If we've already included <net/bpf.h>, don't re-define this stuff.
+ * We assume BSD-style multiple-include protection in <net/bpf.h>,
+ * which is true of all but the oldest versions of FreeBSD and NetBSD,
+ * or Tru64 UNIX-style multiple-include protection (or, at least,
+ * Tru64 UNIX 5.x-style; I don't have earlier versions available to check),
+ * or AIX-style multiple-include protection (or, at least, AIX 5.x-style;
+ * I don't have earlier versions available to check), or QNX-style
+ * multiple-include protection (as per GitHub pull request #394).
+ *
+ * We trust that they will define structures and macros and types in
+ * a fashion that's source-compatible and binary-compatible with our
+ * definitions.
+ *
+ * We do not check for BPF_MAJOR_VERSION, as that's defined by
+ * <linux/filter.h>, which is directly or indirectly included in some
+ * programs that also include pcap.h, and <linux/filter.h> doesn't
+ * define stuff we need.  We *do* protect against <linux/filter.h>
+ * defining various macros for BPF code itself; <linux/filter.h> says
+ *
+ *	Try and keep these values and structures similar to BSD, especially
+ *	the BPF code definitions which need to match so you can share filters
+ *
+ * so we trust that it will define them in a fashion that's source-compatible
+ * and binary-compatible with our definitions.
+ *
+ * This also provides our own multiple-include protection.
+ */
+#if !defined(_NET_BPF_H_) && !defined(_NET_BPF_H_INCLUDED) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h)
+#define lib_pcap_bpf_h
+
+#include <pcap/funcattrs.h>
+
+#include <pcap/dlt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BSD style release date */
+#define BPF_RELEASE 199606
+
+#ifdef MSDOS /* must be 32-bit */
+typedef long          bpf_int32;
+typedef unsigned long bpf_u_int32;
+#else
+typedef	int bpf_int32;
+typedef	u_int bpf_u_int32;
+#endif
+
+/*
+ * Alignment macros.  BPF_WORDALIGN rounds up to the next
+ * even multiple of BPF_ALIGNMENT.
+ *
+ * Tcpdump's print-pflog.c uses this, so we define it here.
+ */
+#ifndef __NetBSD__
+#define BPF_ALIGNMENT sizeof(bpf_int32)
+#else
+#define BPF_ALIGNMENT sizeof(long)
+#endif
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+/*
+ * Structure for "pcap_compile()", "pcap_setfilter()", etc..
+ */
+struct bpf_program {
+	u_int bf_len;
+	struct bpf_insn *bf_insns;
+};
+
+/*
+ * The instruction encodings.
+ *
+ * Please inform tcpdump-workers@lists.tcpdump.org if you use any
+ * of the reserved values, so that we can note that they're used
+ * (and perhaps implement it in the reference BPF implementation
+ * and encourage its implementation elsewhere).
+ */
+
+/*
+ * The upper 8 bits of the opcode aren't used. BSD/OS used 0x8000.
+ */
+
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define		BPF_LD		0x00
+#define		BPF_LDX		0x01
+#define		BPF_ST		0x02
+#define		BPF_STX		0x03
+#define		BPF_ALU		0x04
+#define		BPF_JMP		0x05
+#define		BPF_RET		0x06
+#define		BPF_MISC	0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code)	((code) & 0x18)
+#define		BPF_W		0x00
+#define		BPF_H		0x08
+#define		BPF_B		0x10
+/*				0x18	reserved; used by BSD/OS */
+#define BPF_MODE(code)	((code) & 0xe0)
+#define		BPF_IMM 	0x00
+#define		BPF_ABS		0x20
+#define		BPF_IND		0x40
+#define		BPF_MEM		0x60
+#define		BPF_LEN		0x80
+#define		BPF_MSH		0xa0
+/*				0xc0	reserved; used by BSD/OS */
+/*				0xe0	reserved; used by BSD/OS */
+
+/* alu/jmp fields */
+#define BPF_OP(code)	((code) & 0xf0)
+#define		BPF_ADD		0x00
+#define		BPF_SUB		0x10
+#define		BPF_MUL		0x20
+#define		BPF_DIV		0x30
+#define		BPF_OR		0x40
+#define		BPF_AND		0x50
+#define		BPF_LSH		0x60
+#define		BPF_RSH		0x70
+#define		BPF_NEG		0x80
+#define		BPF_MOD		0x90
+#define		BPF_XOR		0xa0
+/*				0xb0	reserved */
+/*				0xc0	reserved */
+/*				0xd0	reserved */
+/*				0xe0	reserved */
+/*				0xf0	reserved */
+
+#define		BPF_JA		0x00
+#define		BPF_JEQ		0x10
+#define		BPF_JGT		0x20
+#define		BPF_JGE		0x30
+#define		BPF_JSET	0x40
+/*				0x50	reserved; used on BSD/OS */
+/*				0x60	reserved */
+/*				0x70	reserved */
+/*				0x80	reserved */
+/*				0x90	reserved */
+/*				0xa0	reserved */
+/*				0xb0	reserved */
+/*				0xc0	reserved */
+/*				0xd0	reserved */
+/*				0xe0	reserved */
+/*				0xf0	reserved */
+#define BPF_SRC(code)	((code) & 0x08)
+#define		BPF_K		0x00
+#define		BPF_X		0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code)	((code) & 0x18)
+#define		BPF_A		0x10
+/*				0x18	reserved */
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define		BPF_TAX		0x00
+/*				0x08	reserved */
+/*				0x10	reserved */
+/*				0x18	reserved */
+/* #define	BPF_COP		0x20	NetBSD "coprocessor" extensions */
+/*				0x28	reserved */
+/*				0x30	reserved */
+/*				0x38	reserved */
+/* #define	BPF_COPX	0x40	NetBSD "coprocessor" extensions */
+/*					also used on BSD/OS */
+/*				0x48	reserved */
+/*				0x50	reserved */
+/*				0x58	reserved */
+/*				0x60	reserved */
+/*				0x68	reserved */
+/*				0x70	reserved */
+/*				0x78	reserved */
+#define		BPF_TXA		0x80
+/*				0x88	reserved */
+/*				0x90	reserved */
+/*				0x98	reserved */
+/*				0xa0	reserved */
+/*				0xa8	reserved */
+/*				0xb0	reserved */
+/*				0xb8	reserved */
+/*				0xc0	reserved; used on BSD/OS */
+/*				0xc8	reserved */
+/*				0xd0	reserved */
+/*				0xd8	reserved */
+/*				0xe0	reserved */
+/*				0xe8	reserved */
+/*				0xf0	reserved */
+/*				0xf8	reserved */
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+	u_short	code;
+	u_char 	jt;
+	u_char 	jf;
+	bpf_u_int32 k;
+};
+
+/*
+ * Macros for insn array initializers.
+ *
+ * In case somebody's included <linux/filter.h>, or something else that
+ * gives the kernel's definitions of BPF statements, get rid of its
+ * definitions, so we can supply ours instead.  If some kernel's
+ * definitions aren't *binary-compatible* with what BPF has had
+ * since it first sprung from the brows of Van Jacobson and Steve
+ * McCanne, that kernel should be fixed.
+ */
+#ifdef BPF_STMT
+#undef BPF_STMT
+#endif
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#ifdef BPF_JUMP
+#undef BPF_JUMP
+#endif
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+PCAP_AVAILABLE_0_4
+PCAP_API u_int	bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+
+PCAP_AVAILABLE_0_6
+PCAP_API int	bpf_validate(const struct bpf_insn *f, int len);
+
+PCAP_AVAILABLE_0_4
+PCAP_API char	*bpf_image(const struct bpf_insn *, int);
+
+PCAP_AVAILABLE_0_6
+PCAP_API void	bpf_dump(const struct bpf_program *, int);
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) */
diff --git a/pcap/can_socketcan.h b/pcap/can_socketcan.h
new file mode 100644
index 0000000..332d9ff
--- /dev/null
+++ b/pcap/can_socketcan.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_pcap_can_socketcan_h
+#define lib_pcap_can_socketcan_h
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * SocketCAN header, as per Documentation/networking/can.txt in the
+ * Linux source.
+ */
+typedef struct {
+	uint32_t can_id;
+	uint8_t payload_length;
+	uint8_t pad;
+	uint8_t reserved1;
+	uint8_t reserved2;
+} pcap_can_socketcan_hdr;
+
+#endif
diff --git a/pcap/compiler-tests.h b/pcap/compiler-tests.h
new file mode 100644
index 0000000..a69c2b0
--- /dev/null
+++ b/pcap/compiler-tests.h
@@ -0,0 +1,163 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_pcap_compiler_tests_h
+#define lib_pcap_compiler_tests_h
+
+/*
+ * This was introduced by Clang:
+ *
+ *     https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+ *
+ * in some version (which version?); it has been picked up by GCC 5.0.
+ */
+#ifndef __has_attribute
+  /*
+   * It's a macro, so you can check whether it's defined to check
+   * whether it's supported.
+   *
+   * If it's not, define it to always return 0, so that we move on to
+   * the fallback checks.
+   */
+  #define __has_attribute(x) 0
+#endif
+
+/*
+ * Note that the C90 spec's "6.8.1 Conditional inclusion" and the
+ * C99 spec's and C11 spec's "6.10.1 Conditional inclusion" say:
+ *
+ *    Prior to evaluation, macro invocations in the list of preprocessing
+ *    tokens that will become the controlling constant expression are
+ *    replaced (except for those macro names modified by the defined unary
+ *    operator), just as in normal text.  If the token "defined" is
+ *    generated as a result of this replacement process or use of the
+ *    "defined" unary operator does not match one of the two specified
+ *    forms prior to macro replacement, the behavior is undefined.
+ *
+ * so you shouldn't use defined() in a #define that's used in #if or
+ * #elif.  Some versions of Clang, for example, will warn about this.
+ *
+ * Instead, we check whether the pre-defined macros for particular
+ * compilers are defined and, if not, define the "is this version XXX
+ * or a later version of this compiler" macros as 0.
+ */
+
+/*
+ * Check whether this is GCC major.minor or a later release, or some
+ * compiler that claims to be "just like GCC" of that version or a
+ * later release.
+ */
+
+#if ! defined(__GNUC__)
+#define PCAP_IS_AT_LEAST_GNUC_VERSION(major, minor) 0
+#else
+#define PCAP_IS_AT_LEAST_GNUC_VERSION(major, minor) \
+	(__GNUC__ > (major) || \
+	 (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+#endif
+
+/*
+ * Check whether this is Clang major.minor or a later release.
+ */
+
+#if !defined(__clang__)
+#define PCAP_IS_AT_LEAST_CLANG_VERSION(major, minor) 0
+#else
+#define PCAP_IS_AT_LEAST_CLANG_VERSION(major, minor) \
+	(__clang_major__ > (major) || \
+	 (__clang_major__ == (major) && __clang_minor__ >= (minor)))
+#endif
+
+/*
+ * Check whether this is Sun C/SunPro C/Oracle Studio major.minor
+ * or a later release.
+ *
+ * The version number in __SUNPRO_C is encoded in hex BCD, with the
+ * uppermost hex digit being the major version number, the next
+ * one or two hex digits being the minor version number, and
+ * the last digit being the patch version.
+ *
+ * It represents the *compiler* version, not the product version;
+ * see
+ *
+ *    https://sourceforge.net/p/predef/wiki/Compilers/
+ *
+ * for a partial mapping, which we assume continues for later
+ * 12.x product releases.
+ */
+
+#if ! defined(__SUNPRO_C)
+#define PCAP_IS_AT_LEAST_SUNC_VERSION(major,minor) 0
+#else
+#define PCAP_SUNPRO_VERSION_TO_BCD(major, minor) \
+	(((minor) >= 10) ? \
+	    (((major) << 12) | (((minor)/10) << 8) | (((minor)%10) << 4)) : \
+	    (((major) << 8) | ((minor) << 4)))
+#define PCAP_IS_AT_LEAST_SUNC_VERSION(major,minor) \
+	(__SUNPRO_C >= PCAP_SUNPRO_VERSION_TO_BCD((major), (minor)))
+#endif
+
+/*
+ * Check whether this is IBM XL C major.minor or a later release.
+ *
+ * The version number in __xlC__ has the major version in the
+ * upper 8 bits and the minor version in the lower 8 bits.
+ */
+
+#if ! defined(__xlC__)
+#define PCAP_IS_AT_LEAST_XL_C_VERSION(major,minor) 0
+#else
+#define PCAP_IS_AT_LEAST_XL_C_VERSION(major, minor) \
+	(__xlC__ >= (((major) << 8) | (minor)))
+#endif
+
+/*
+ * Check whether this is HP aC++/HP C major.minor or a later release.
+ *
+ * The version number in __HP_aCC is encoded in zero-padded decimal BCD,
+ * with the "A." stripped off, the uppermost two decimal digits being
+ * the major version number, the next two decimal digits being the minor
+ * version number, and the last two decimal digits being the patch version.
+ * (Strip off the A., remove the . between the major and minor version
+ * number, and add two digits of patch.)
+ */
+
+#if ! defined(__HP_aCC)
+#define PCAP_IS_AT_LEAST_HP_C_VERSION(major,minor) 0
+#else
+#define PCAP_IS_AT_LEAST_HP_C_VERSION(major,minor) \
+	(__HP_aCC >= ((major)*10000 + (minor)*100))
+#endif
+
+#endif /* lib_pcap_compiler_tests_h */
diff --git a/pcap/dlt.h b/pcap/dlt.h
new file mode 100644
index 0000000..eaba34f
--- /dev/null
+++ b/pcap/dlt.h
@@ -0,0 +1,1514 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)bpf.h       7.1 (Berkeley) 5/7/91
+ */
+
+#ifndef lib_pcap_dlt_h
+#define lib_pcap_dlt_h
+
+/*
+ * Link-layer header type codes.
+ *
+ * Do *NOT* add new values to this list without asking
+ * "tcpdump-workers@lists.tcpdump.org" for a value.  Otherwise, you run
+ * the risk of using a value that's already being used for some other
+ * purpose, and of having tools that read libpcap-format captures not
+ * being able to handle captures with your new DLT_ value, with no hope
+ * that they will ever be changed to do so (as that would destroy their
+ * ability to read captures using that value for that other purpose).
+ *
+ * See
+ *
+ *	https://www.tcpdump.org/linktypes.html
+ *
+ * for detailed descriptions of some of these link-layer header types.
+ */
+
+/*
+ * These are the types that are the same on all platforms, and that
+ * have been defined by <net/bpf.h> for ages.
+ */
+#define DLT_NULL	0	/* BSD loopback encapsulation */
+#define DLT_EN10MB	1	/* Ethernet (10Mb) */
+#define DLT_EN3MB	2	/* Experimental Ethernet (3Mb) */
+#define DLT_AX25	3	/* Amateur Radio AX.25 */
+#define DLT_PRONET	4	/* Proteon ProNET Token Ring */
+#define DLT_CHAOS	5	/* Chaos */
+#define DLT_IEEE802	6	/* 802.5 Token Ring */
+#define DLT_ARCNET	7	/* ARCNET, with BSD-style header */
+#define DLT_SLIP	8	/* Serial Line IP */
+#define DLT_PPP		9	/* Point-to-point Protocol */
+#define DLT_FDDI	10	/* FDDI */
+
+/*
+ * These are types that are different on some platforms, and that
+ * have been defined by <net/bpf.h> for ages.  We use #ifdefs to
+ * detect the BSDs that define them differently from the traditional
+ * libpcap <net/bpf.h>
+ *
+ * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS,
+ * but I don't know what the right #define is for BSD/OS.
+ */
+#define DLT_ATM_RFC1483	11	/* LLC-encapsulated ATM */
+
+#ifdef __OpenBSD__
+#define DLT_RAW		14	/* raw IP */
+#else
+#define DLT_RAW		12	/* raw IP */
+#endif
+
+/*
+ * Given that the only OS that currently generates BSD/OS SLIP or PPP
+ * is, well, BSD/OS, arguably everybody should have chosen its values
+ * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they
+ * didn't.  So it goes.
+ */
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#ifndef DLT_SLIP_BSDOS
+#define DLT_SLIP_BSDOS	13	/* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS	14	/* BSD/OS Point-to-point Protocol */
+#endif
+#else
+#define DLT_SLIP_BSDOS	15	/* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS	16	/* BSD/OS Point-to-point Protocol */
+#endif
+
+/*
+ * 17 was used for DLT_PFLOG in OpenBSD; it no longer is.
+ *
+ * It was DLT_LANE8023 in SuSE 6.3, so we defined LINKTYPE_PFLOG
+ * as 117 so that pflog captures would use a link-layer header type
+ * value that didn't collide with any other values.  On all
+ * platforms other than OpenBSD, we defined DLT_PFLOG as 117,
+ * and we mapped between LINKTYPE_PFLOG and DLT_PFLOG.
+ *
+ * OpenBSD eventually switched to using 117 for DLT_PFLOG as well.
+ *
+ * Don't use 17 for anything else.
+ */
+
+/*
+ * 18 is used for DLT_PFSYNC in OpenBSD, NetBSD, DragonFly BSD and
+ * macOS; don't use it for anything else.  (FreeBSD uses 121, which
+ * collides with DLT_HHDLC, even though it doesn't use 18 for
+ * anything and doesn't appear to have ever used it for anything.)
+ *
+ * We define it as 18 on those platforms; it is, unfortunately, used
+ * for DLT_CIP in Suse 6.3, so we don't define it as DLT_PFSYNC
+ * in general.  As the packet format for it, like that for
+ * DLT_PFLOG, is not only OS-dependent but OS-version-dependent,
+ * we don't support printing it in tcpdump except on OSes that
+ * have the relevant header files, so it's not that useful on
+ * other platforms.
+ */
+#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__)
+#define DLT_PFSYNC	18
+#endif
+
+#define DLT_ATM_CLIP	19	/* Linux Classical IP over ATM */
+
+/*
+ * Apparently Redback uses this for its SmartEdge 400/800.  I hope
+ * nobody else decided to use it, too.
+ */
+#define DLT_REDBACK_SMARTEDGE	32
+
+/*
+ * These values are defined by NetBSD; other platforms should refrain from
+ * using them for other purposes, so that NetBSD savefiles with link
+ * types of 50 or 51 can be read as this type on all platforms.
+ */
+#define DLT_PPP_SERIAL	50	/* PPP over serial with HDLC encapsulation */
+#define DLT_PPP_ETHER	51	/* PPP over Ethernet */
+
+/*
+ * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses
+ * a link-layer type of 99 for the tcpdump it supplies.  The link-layer
+ * header has 6 bytes of unknown data, something that appears to be an
+ * Ethernet type, and 36 bytes that appear to be 0 in at least one capture
+ * I've seen.
+ */
+#define DLT_SYMANTEC_FIREWALL	99
+
+/*
+ * Values between 100 and 103 are used in capture file headers as
+ * link-layer header type LINKTYPE_ values corresponding to DLT_ types
+ * that differ between platforms; don't use those values for new DLT_
+ * new types.
+ */
+
+/*
+ * Values starting with 104 are used for newly-assigned link-layer
+ * header type values; for those link-layer header types, the DLT_
+ * value returned by pcap_datalink() and passed to pcap_open_dead(),
+ * and the LINKTYPE_ value that appears in capture files, are the
+ * same.
+ *
+ * DLT_MATCHING_MIN is the lowest such value; DLT_MATCHING_MAX is
+ * the highest such value.
+ */
+#define DLT_MATCHING_MIN	104
+
+/*
+ * This value was defined by libpcap 0.5; platforms that have defined
+ * it with a different value should define it here with that value -
+ * a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ * whatever value that happens to be, so programs will correctly
+ * handle files with that link type regardless of the value of
+ * DLT_C_HDLC.
+ *
+ * The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ * compatibility with programs written for BSD/OS.
+ *
+ * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ * for source compatibility with programs written for libpcap 0.5.
+ */
+#define DLT_C_HDLC	104	/* Cisco HDLC */
+#define DLT_CHDLC	DLT_C_HDLC
+
+#define DLT_IEEE802_11	105	/* IEEE 802.11 wireless */
+
+/*
+ * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW,
+ * except when it isn't.  (I.e., sometimes it's just raw IP, and
+ * sometimes it isn't.)  We currently handle it as DLT_LINUX_SLL,
+ * so that we don't have to worry about the link-layer header.)
+ */
+
+/*
+ * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides
+ * with other values.
+ * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header
+ * (DLCI, etc.).
+ */
+#define DLT_FRELAY	107
+
+/*
+ * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ * that the AF_ type in the link-layer header is in network byte order.
+ *
+ * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so
+ * we don't use 12 for it in OSes other than OpenBSD.
+ */
+#ifdef __OpenBSD__
+#define DLT_LOOP	12
+#else
+#define DLT_LOOP	108
+#endif
+
+/*
+ * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's
+ * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other
+ * than OpenBSD.
+ */
+#ifdef __OpenBSD__
+#define DLT_ENC		13
+#else
+#define DLT_ENC		109
+#endif
+
+/*
+ * Values between 110 and 112 are reserved for use in capture file headers
+ * as link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ types
+ * other than the corresponding DLT_ types.
+ */
+
+/*
+ * Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL	113
+
+/*
+ * Apple LocalTalk hardware.
+ */
+#define DLT_LTALK	114
+
+/*
+ * Acorn Econet.
+ */
+#define DLT_ECONET	115
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define DLT_IPFILTER	116
+
+/*
+ * OpenBSD DLT_PFLOG.
+ */
+#define DLT_PFLOG	117
+
+/*
+ * Registered for Cisco-internal use.
+ */
+#define DLT_CISCO_IOS	118
+
+/*
+ * For 802.11 cards using the Prism II chips, with a link-layer
+ * header including Prism monitor mode information plus an 802.11
+ * header.
+ */
+#define DLT_PRISM_HEADER	119
+
+/*
+ * Reserved for Aironet 802.11 cards, with an Aironet link-layer header
+ * (see Doug Ambrisko's FreeBSD patches).
+ */
+#define DLT_AIRONET_HEADER	120
+
+/*
+ * Sigh.
+ *
+ * 121 was reserved for Siemens HiPath HDLC on 2002-01-25, as
+ * requested by Tomas Kukosa.
+ *
+ * On 2004-02-25, a FreeBSD checkin to sys/net/bpf.h was made that
+ * assigned 121 as DLT_PFSYNC.  In current versions, its libpcap
+ * does DLT_ <-> LINKTYPE_ mapping, mapping DLT_PFSYNC to a
+ * LINKTYPE_PFSYNC value of 246, so it should write out DLT_PFSYNC
+ * dump files with 246 as the link-layer header type.  (Earlier
+ * versions might not have done mapping, in which case they would
+ * have written them out with a link-layer header type of 121.)
+ *
+ * OpenBSD, from which pf came, however, uses 18 for DLT_PFSYNC;
+ * its libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would
+ * write out DLT_PFSYNC dump files with use 18 as the link-layer
+ * header type.
+ *
+ * NetBSD, DragonFly BSD, and Darwin also use 18 for DLT_PFSYNC; in
+ * current versions, their libpcaps do DLT_ <-> LINKTYPE_ mapping,
+ * mapping DLT_PFSYNC to a LINKTYPE_PFSYNC value of 246, so they
+ * should write out DLT_PFSYNC dump files with 246 as the link-layer
+ * header type.  (Earlier versions might not have done mapping,
+ * in which case they'd work the same way OpenBSD does, writing
+ * them out with a link-layer header type of 18.)
+ *
+ * We'll define DLT_PFSYNC as:
+ *
+ *    18 on NetBSD, OpenBSD, DragonFly BSD, and Darwin;
+ *
+ *    121 on FreeBSD;
+ *
+ *    246 everywhere else.
+ *
+ * We'll define DLT_HHDLC as 121 on everything except for FreeBSD;
+ * anybody who wants to compile, on FreeBSD, code that uses DLT_HHDLC
+ * is out of luck.
+ *
+ * We'll define LINKTYPE_PFSYNC as 246 on *all* platforms, so that
+ * savefiles written using *this* code won't use 18 or 121 for PFSYNC,
+ * they'll all use 246.
+ *
+ * Code that uses pcap_datalink() to determine the link-layer header
+ * type of a savefile won't, when built and run on FreeBSD, be able
+ * to distinguish between LINKTYPE_PFSYNC and LINKTYPE_HHDLC capture
+ * files, as pcap_datalink() will give 121 for both of them.  Code
+ * that doesn't, such as the code in Wireshark, will be able to
+ * distinguish between them.
+ *
+ * FreeBSD's libpcap won't map a link-layer header type of 18 - i.e.,
+ * DLT_PFSYNC files from OpenBSD and possibly older versions of NetBSD,
+ * DragonFly BSD, and macOS - to DLT_PFSYNC, so code built with FreeBSD's
+ * libpcap won't treat those files as DLT_PFSYNC files.
+ *
+ * Other libpcaps won't map a link-layer header type of 121 to DLT_PFSYNC;
+ * this means they can read DLT_HHDLC files, if any exist, but won't
+ * treat pcap files written by any older versions of FreeBSD libpcap that
+ * didn't map to 246 as DLT_PFSYNC files.
+ */
+#ifdef __FreeBSD__
+#define DLT_PFSYNC		121
+#else
+#define DLT_HHDLC		121
+#endif
+
+/*
+ * This is for RFC 2625 IP-over-Fibre Channel.
+ *
+ * This is not for use with raw Fibre Channel, where the link-layer
+ * header starts with a Fibre Channel frame header; it's for IP-over-FC,
+ * where the link-layer header starts with an RFC 2625 Network_Header
+ * field.
+ */
+#define DLT_IP_OVER_FC		122
+
+/*
+ * This is for Full Frontal ATM on Solaris with SunATM, with a
+ * pseudo-header followed by an AALn PDU.
+ *
+ * There may be other forms of Full Frontal ATM on other OSes,
+ * with different pseudo-headers.
+ *
+ * If ATM software returns a pseudo-header with VPI/VCI information
+ * (and, ideally, packet type information, e.g. signalling, ILMI,
+ * LANE, LLC-multiplexed traffic, etc.), it should not use
+ * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump
+ * and the like don't have to infer the presence or absence of a
+ * pseudo-header and the form of the pseudo-header.
+ */
+#define DLT_SUNATM		123	/* Solaris+SunATM */
+
+/*
+ * Reserved as per request from Kent Dahlgren <kent@praesum.com>
+ * for private use.
+ */
+#define DLT_RIO                 124     /* RapidIO */
+#define DLT_PCI_EXP             125     /* PCI Express */
+#define DLT_AURORA              126     /* Xilinx Aurora link layer */
+
+/*
+ * Header for 802.11 plus a number of bits of link-layer information
+ * including radio information, used by some recent BSD drivers as
+ * well as the madwifi Atheros driver for Linux.
+ */
+#define DLT_IEEE802_11_RADIO	127	/* 802.11 plus radiotap radio header */
+
+/*
+ * Reserved for the TZSP encapsulation, as per request from
+ * Chris Waters <chris.waters@networkchemistry.com>
+ * TZSP is a generic encapsulation for any other link type,
+ * which includes a means to include meta-information
+ * with the packet, e.g. signal strength and channel
+ * for 802.11 packets.
+ */
+#define DLT_TZSP                128     /* Tazmen Sniffer Protocol */
+
+/*
+ * BSD's ARCNET headers have the source host, destination host,
+ * and type at the beginning of the packet; that's what's handed
+ * up to userland via BPF.
+ *
+ * Linux's ARCNET headers, however, have a 2-byte offset field
+ * between the host IDs and the type; that's what's handed up
+ * to userland via PF_PACKET sockets.
+ *
+ * We therefore have to have separate DLT_ values for them.
+ */
+#define DLT_ARCNET_LINUX	129	/* ARCNET */
+
+/*
+ * Juniper-private data link types, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MLPPP       130
+#define DLT_JUNIPER_MLFR        131
+#define DLT_JUNIPER_ES          132
+#define DLT_JUNIPER_GGSN        133
+#define DLT_JUNIPER_MFR         134
+#define DLT_JUNIPER_ATM2        135
+#define DLT_JUNIPER_SERVICES    136
+#define DLT_JUNIPER_ATM1        137
+
+/*
+ * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund
+ * <dieter@apple.com>.  The header that's presented is an Ethernet-like
+ * header:
+ *
+ *	#define FIREWIRE_EUI64_LEN	8
+ *	struct firewire_header {
+ *		u_char  firewire_dhost[FIREWIRE_EUI64_LEN];
+ *		u_char  firewire_shost[FIREWIRE_EUI64_LEN];
+ *		u_short firewire_type;
+ *	};
+ *
+ * with "firewire_type" being an Ethernet type value, rather than,
+ * for example, raw GASP frames being handed up.
+ */
+#define DLT_APPLE_IP_OVER_IEEE1394	138
+
+/*
+ * Various SS7 encapsulations, as per a request from Jeff Morriss
+ * <jeff.morriss[AT]ulticom.com> and subsequent discussions.
+ */
+#define DLT_MTP2_WITH_PHDR	139	/* pseudo-header with various info, followed by MTP2 */
+#define DLT_MTP2		140	/* MTP2, without pseudo-header */
+#define DLT_MTP3		141	/* MTP3, without pseudo-header or MTP2 */
+#define DLT_SCCP		142	/* SCCP, without pseudo-header or MTP2 or MTP3 */
+
+/*
+ * DOCSIS MAC frames.
+ */
+#define DLT_DOCSIS		143
+
+/*
+ * Linux-IrDA packets. Protocol defined at https://www.irda.org.
+ * Those packets include IrLAP headers and above (IrLMP...), but
+ * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy
+ * framing can be handled by the hardware and depend on the bitrate.
+ * This is exactly the format you would get capturing on a Linux-IrDA
+ * interface (irdaX), but not on a raw serial port.
+ * Note the capture is done in "Linux-cooked" mode, so each packet include
+ * a fake packet header (struct sll_header). This is because IrDA packet
+ * decoding is dependent on the direction of the packet (incoming or
+ * outgoing).
+ * When/if other platform implement IrDA capture, we may revisit the
+ * issue and define a real DLT_IRDA...
+ * Jean II
+ */
+#define DLT_LINUX_IRDA		144
+
+/*
+ * Reserved for IBM SP switch and IBM Next Federation switch.
+ */
+#define DLT_IBM_SP		145
+#define DLT_IBM_SN		146
+
+/*
+ * Reserved for private use.  If you have some link-layer header type
+ * that you want to use within your organization, with the capture files
+ * using that link-layer header type not ever be sent outside your
+ * organization, you can use these values.
+ *
+ * No libpcap release will use these for any purpose, nor will any
+ * tcpdump release use them, either.
+ *
+ * Do *NOT* use these in capture files that you expect anybody not using
+ * your private versions of capture-file-reading tools to read; in
+ * particular, do *NOT* use them in products, otherwise you may find that
+ * people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ * read capture files from your firewall/intrusion detection/traffic
+ * monitoring/etc. appliance, or whatever product uses that DLT_ value,
+ * and you may also find that the developers of those applications will
+ * not accept patches to let them read those files.
+ *
+ * Also, do not use them if somebody might send you a capture using them
+ * for *their* private type and tools using them for *your* private type
+ * would have to read them.
+ *
+ * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value,
+ * as per the comment above, and use the type you're given.
+ */
+#define DLT_USER0		147
+#define DLT_USER1		148
+#define DLT_USER2		149
+#define DLT_USER3		150
+#define DLT_USER4		151
+#define DLT_USER5		152
+#define DLT_USER6		153
+#define DLT_USER7		154
+#define DLT_USER8		155
+#define DLT_USER9		156
+#define DLT_USER10		157
+#define DLT_USER11		158
+#define DLT_USER12		159
+#define DLT_USER13		160
+#define DLT_USER14		161
+#define DLT_USER15		162
+
+/*
+ * For future use with 802.11 captures - defined by AbsoluteValue
+ * Systems to store a number of bits of link-layer information
+ * including radio information:
+ *
+ *	http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ *
+ * but it might be used by some non-AVS drivers now or in the
+ * future.
+ */
+#define DLT_IEEE802_11_RADIO_AVS 163	/* 802.11 plus AVS radio header */
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MONITOR     164
+
+/*
+ * BACnet MS/TP frames.
+ */
+#define DLT_BACNET_MS_TP	165
+
+/*
+ * Another PPP variant as per request from Karsten Keil <kkeil@suse.de>.
+ *
+ * This is used in some OSes to allow a kernel socket filter to distinguish
+ * between incoming and outgoing packets, on a socket intended to
+ * supply pppd with outgoing packets so it can do dial-on-demand and
+ * hangup-on-lack-of-demand; incoming packets are filtered out so they
+ * don't cause pppd to hold the connection up (you don't want random
+ * input packets such as port scans, packets from old lost connections,
+ * etc. to force the connection to stay up).
+ *
+ * The first byte of the PPP header (0xff03) is modified to accommodate
+ * the direction - 0x00 = IN, 0x01 = OUT.
+ */
+#define DLT_PPP_PPPD		166
+
+/*
+ * Names for backwards compatibility with older versions of some PPP
+ * software; new software should use DLT_PPP_PPPD.
+ */
+#define DLT_PPP_WITH_DIRECTION	DLT_PPP_PPPD
+#define DLT_LINUX_PPP_WITHDIRECTION	DLT_PPP_PPPD
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, cookies, etc..
+ */
+#define DLT_JUNIPER_PPPOE       167
+#define DLT_JUNIPER_PPPOE_ATM   168
+
+#define DLT_GPRS_LLC		169	/* GPRS LLC */
+#define DLT_GPF_T		170	/* GPF-T (ITU-T G.7041/Y.1303) */
+#define DLT_GPF_F		171	/* GPF-F (ITU-T G.7041/Y.1303) */
+
+/*
+ * Requested by Oolan Zimmer <oz@gcom.com> for use in Gcom's T1/E1 line
+ * monitoring equipment.
+ */
+#define DLT_GCOM_T1E1		172
+#define DLT_GCOM_SERIAL		173
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.  The DLT_ is used
+ * for internal communication to Physical Interface Cards (PIC)
+ */
+#define DLT_JUNIPER_PIC_PEER    174
+
+/*
+ * Link types requested by Gregor Maier <gregor@endace.com> of Endace
+ * Measurement Systems.  They add an ERF header (see
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * the link-layer header.
+ */
+#define DLT_ERF_ETH		175	/* Ethernet */
+#define DLT_ERF_POS		176	/* Packet-over-SONET */
+
+/*
+ * Requested by Daniele Orlandi <daniele@orlandi.com> for raw LAPD
+ * for vISDN (http://www.orlandi.com/visdn/).  Its link-layer header
+ * includes additional information before the LAPD header, so it's
+ * not necessarily a generic LAPD header.
+ */
+#define DLT_LINUX_LAPD		177
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ are used for prepending meta-information
+ * like interface index, interface name
+ * before standard Ethernet, PPP, Frelay & C-HDLC Frames
+ */
+#define DLT_JUNIPER_ETHER       178
+#define DLT_JUNIPER_PPP         179
+#define DLT_JUNIPER_FRELAY      180
+#define DLT_JUNIPER_CHDLC       181
+
+/*
+ * Multi Link Frame Relay (FRF.16)
+ */
+#define DLT_MFR                 182
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * voice Adapter Card (PIC)
+ */
+#define DLT_JUNIPER_VP          183
+
+/*
+ * Arinc 429 frames.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Every frame contains a 32bit A429 label.
+ * More documentation on Arinc 429 can be found at
+ * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf
+ */
+#define DLT_A429                184
+
+/*
+ * Arinc 653 Interpartition Communication messages.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Please refer to the A653-1 standard for more information.
+ */
+#define DLT_A653_ICM            185
+
+/*
+ * This used to be "USB packets, beginning with a USB setup header;
+ * requested by Paolo Abeni <paolo.abeni@email.it>."
+ *
+ * However, that header didn't work all that well - it left out some
+ * useful information - and was abandoned in favor of the DLT_USB_LINUX
+ * header.
+ *
+ * This is now used by FreeBSD for its BPF taps for USB; that has its
+ * own headers.  So it is written, so it is done.
+ *
+ * For source-code compatibility, we also define DLT_USB to have this
+ * value.  We do it numerically so that, if code that includes this
+ * file (directly or indirectly) also includes an OS header that also
+ * defines DLT_USB as 186, we don't get a redefinition warning.
+ * (NetBSD 7 does that.)
+ */
+#define DLT_USB_FREEBSD		186
+#define DLT_USB			186
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4); requested by
+ * Paolo Abeni.
+ */
+#define DLT_BLUETOOTH_HCI_H4	187
+
+/*
+ * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz
+ * <cruz_petagay@bah.com>.
+ */
+#define DLT_IEEE802_16_MAC_CPS	188
+
+/*
+ * USB packets, beginning with a Linux USB header; requested by
+ * Paolo Abeni <paolo.abeni@email.it>.
+ */
+#define DLT_USB_LINUX		189
+
+/*
+ * Controller Area Network (CAN) v. 2.0B packets.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Used to dump CAN packets coming from a CAN Vector board.
+ * More documentation on the CAN v2.0B frames can be found at
+ * http://www.can-cia.org/downloads/?269
+ */
+#define DLT_CAN20B              190
+
+/*
+ * IEEE 802.15.4, with address fields padded, as is done by Linux
+ * drivers; requested by Juergen Schimmer.
+ */
+#define DLT_IEEE802_15_4_LINUX	191
+
+/*
+ * Per Packet Information encapsulated packets.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ */
+#define DLT_PPI			192
+
+/*
+ * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header;
+ * requested by Charles Clancy.
+ */
+#define DLT_IEEE802_16_MAC_CPS_RADIO	193
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * integrated service module (ISM).
+ */
+#define DLT_JUNIPER_ISM         194
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing); requested by Mikko Saarnivala <mikko.saarnivala@sensinode.com>.
+ * For this one, we expect the FCS to be present at the end of the frame;
+ * if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be used.
+ *
+ * We keep the name DLT_IEEE802_15_4 as an alias for backwards
+ * compatibility, but, again, this should *only* be used for 802.15.4
+ * frames that include the FCS.
+ */
+#define DLT_IEEE802_15_4_WITHFCS	195
+#define DLT_IEEE802_15_4		DLT_IEEE802_15_4_WITHFCS
+
+/*
+ * Various link-layer types, with a pseudo-header, for SITA
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ */
+#define DLT_SITA		196
+
+/*
+ * Various link-layer types, with a pseudo-header, for Endace DAG cards;
+ * encapsulates Endace ERF records.  Requested by Stephen Donnelly
+ * <stephen@endace.com>.
+ */
+#define DLT_ERF			197
+
+/*
+ * Special header prepended to Ethernet packets when capturing from a
+ * u10 Networks board.  Requested by Phil Mulholland
+ * <phil@u10networks.com>.
+ */
+#define DLT_RAIF1		198
+
+/*
+ * IPMB packet for IPMI, beginning with a 2-byte header, followed by
+ * the I2C slave address, followed by the netFn and LUN, etc..
+ * Requested by Chanthy Toeung <chanthy.toeung@ca.kontron.com>.
+ *
+ * XXX - this used to be called DLT_IPMB, back when we got the
+ * impression from the email thread requesting it that the packet
+ * had no extra 2-byte header.  We've renamed it; if anybody used
+ * DLT_IPMB and assumed no 2-byte header, this will cause the compile
+ * to fail, at which point we'll have to figure out what to do about
+ * the two header types using the same DLT_/LINKTYPE_ value.  If that
+ * doesn't happen, we'll assume nobody used it and that the redefinition
+ * is safe.
+ */
+#define DLT_IPMB_KONTRON	199
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for capturing data on a secure tunnel interface.
+ */
+#define DLT_JUNIPER_ST          200
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4), with pseudo-header
+ * that includes direction information; requested by Paolo Abeni.
+ */
+#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR	201
+
+/*
+ * AX.25 packet with a 1-byte KISS header; see
+ *
+ *	http://www.ax25.net/kiss.htm
+ *
+ * as per Richard Stearn <richard@rns-stearn.demon.co.uk>.
+ */
+#define DLT_AX25_KISS		202
+
+/*
+ * LAPD packets from an ISDN channel, starting with the address field,
+ * with no pseudo-header.
+ * Requested by Varuna De Silva <varunax@gmail.com>.
+ */
+#define DLT_LAPD		203
+
+/*
+ * PPP, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host", non-zero (any non-zero value) means "sent by
+ * this host" - as per Will Barker <w.barker@zen.co.uk>.
+ *
+ * Don't confuse this with DLT_PPP_WITH_DIRECTION, which is an old
+ * name for what is now called DLT_PPP_PPPD.
+ */
+#define DLT_PPP_WITH_DIR	204
+
+/*
+ * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host", non-zero (any non-zero value) means
+ * "sent by this host" - as per Will Barker <w.barker@zen.co.uk>.
+ */
+#define DLT_C_HDLC_WITH_DIR	205
+
+/*
+ * Frame Relay, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host" (DCE -> DTE), non-zero (any non-zero
+ * value) means "sent by this host" (DTE -> DCE) - as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define DLT_FRELAY_WITH_DIR	206
+
+/*
+ * LAPB, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host" (DCE -> DTE), non-zero (any non-zero value)
+ * means "sent by this host" (DTE -> DCE)- as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define DLT_LAPB_WITH_DIR	207
+
+/*
+ * 208 is reserved for an as-yet-unspecified proprietary link-layer
+ * type, as requested by Will Barker.
+ */
+
+/*
+ * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman
+ * <avn@pigeonpoint.com>.
+ */
+#define DLT_IPMB_LINUX		209
+
+/*
+ * FlexRay automotive bus - http://www.flexray.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_FLEXRAY		210
+
+/*
+ * Media Oriented Systems Transport (MOST) bus for multimedia
+ * transport - https://www.mostcooperation.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_MOST		211
+
+/*
+ * Local Interconnect Network (LIN) bus for vehicle networks -
+ * http://www.lin-subbus.org/ - as requested by Hannes Kaelber
+ * <hannes.kaelber@x2e.de>.
+ */
+#define DLT_LIN			212
+
+/*
+ * X2E-private data link type used for serial line capture,
+ * as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_X2E_SERIAL		213
+
+/*
+ * X2E-private data link type used for the Xoraya data logger
+ * family, as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_X2E_XORAYA		214
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), but with the PHY-level data for non-ASK PHYs (4 octets
+ * of 0 as preamble, one octet of SFD, one octet of frame length+
+ * reserved bit, and then the MAC-layer data, starting with the
+ * frame control field).
+ *
+ * Requested by Max Filippov <jcmvbkbc@gmail.com>.
+ */
+#define DLT_IEEE802_15_4_NONASK_PHY	215
+
+/*
+ * David Gibson <david@gibson.dropbear.id.au> requested this for
+ * captures from the Linux kernel /dev/input/eventN devices. This
+ * is used to communicate keystrokes and mouse movements from the
+ * Linux kernel to display systems, such as Xorg.
+ */
+#define DLT_LINUX_EVDEV		216
+
+/*
+ * GSM Um and Abis interfaces, preceded by a "gsmtap" header.
+ *
+ * Requested by Harald Welte <laforge@gnumonks.org>.
+ */
+#define DLT_GSMTAP_UM		217
+#define DLT_GSMTAP_ABIS		218
+
+/*
+ * MPLS, with an MPLS label as the link-layer header.
+ * Requested by Michele Marchetto <michele@openbsd.org> on behalf
+ * of OpenBSD.
+ */
+#define DLT_MPLS		219
+
+/*
+ * USB packets, beginning with a Linux USB header, with the USB header
+ * padded to 64 bytes; required for memory-mapped access.
+ */
+#define DLT_USB_LINUX_MMAPPED	220
+
+/*
+ * DECT packets, with a pseudo-header; requested by
+ * Matthias Wenzel <tcpdump@mazzoo.de>.
+ */
+#define DLT_DECT		221
+
+/*
+ * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" <eric.lidwa-1@nasa.gov>
+ * Date: Mon, 11 May 2009 11:18:30 -0500
+ *
+ * DLT_AOS. We need it for AOS Space Data Link Protocol.
+ *   I have already written dissectors for but need an OK from
+ *   legal before I can submit a patch.
+ *
+ */
+#define DLT_AOS                 222
+
+/*
+ * Wireless HART (Highway Addressable Remote Transducer)
+ * From the HART Communication Foundation
+ * IES/PAS 62591
+ *
+ * Requested by Sam Roberts <vieuxtech@gmail.com>.
+ */
+#define DLT_WIHART		223
+
+/*
+ * Fibre Channel FC-2 frames, beginning with a Frame_Header.
+ * Requested by Kahou Lei <kahou82@gmail.com>.
+ */
+#define DLT_FC_2		224
+
+/*
+ * Fibre Channel FC-2 frames, beginning with an encoding of the
+ * SOF, and ending with an encoding of the EOF.
+ *
+ * The encodings represent the frame delimiters as 4-byte sequences
+ * representing the corresponding ordered sets, with K28.5
+ * represented as 0xBC, and the D symbols as the corresponding
+ * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2,
+ * is represented as 0xBC 0xB5 0x55 0x55.
+ *
+ * Requested by Kahou Lei <kahou82@gmail.com>.
+ */
+#define DLT_FC_2_WITH_FRAME_DELIMS	225
+
+/*
+ * Solaris ipnet pseudo-header; requested by Darren Reed <Darren.Reed@Sun.COM>.
+ *
+ * The pseudo-header starts with a one-byte version number; for version 2,
+ * the pseudo-header is:
+ *
+ * struct dl_ipnetinfo {
+ *     uint8_t   dli_version;
+ *     uint8_t   dli_family;
+ *     uint16_t  dli_htype;
+ *     uint32_t  dli_pktlen;
+ *     uint32_t  dli_ifindex;
+ *     uint32_t  dli_grifindex;
+ *     uint32_t  dli_zsrc;
+ *     uint32_t  dli_zdst;
+ * };
+ *
+ * dli_version is 2 for the current version of the pseudo-header.
+ *
+ * dli_family is a Solaris address family value, so it's 2 for IPv4
+ * and 26 for IPv6.
+ *
+ * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing
+ * packets, and 2 for packets arriving from another zone on the same
+ * machine.
+ *
+ * dli_pktlen is the length of the packet data following the pseudo-header
+ * (so the captured length minus dli_pktlen is the length of the
+ * pseudo-header, assuming the entire pseudo-header was captured).
+ *
+ * dli_ifindex is the interface index of the interface on which the
+ * packet arrived.
+ *
+ * dli_grifindex is the group interface index number (for IPMP interfaces).
+ *
+ * dli_zsrc is the zone identifier for the source of the packet.
+ *
+ * dli_zdst is the zone identifier for the destination of the packet.
+ *
+ * A zone number of 0 is the global zone; a zone number of 0xffffffff
+ * means that the packet arrived from another host on the network, not
+ * from another zone on the same machine.
+ *
+ * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates
+ * which of those it is.
+ */
+#define DLT_IPNET		226
+
+/*
+ * CAN (Controller Area Network) frames, with a pseudo-header as supplied
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in big-endian byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
+ *
+ * Requested by Felix Obenhuber <felix@obenhuber.de>.
+ */
+#define DLT_CAN_SOCKETCAN	227
+
+/*
+ * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies
+ * whether it's v4 or v6.  Requested by Darren Reed <Darren.Reed@Sun.COM>.
+ */
+#define DLT_IPV4		228
+#define DLT_IPV6		229
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), and with no FCS at the end of the frame; requested by
+ * Jon Smirl <jonsmirl@gmail.com>.
+ */
+#define DLT_IEEE802_15_4_NOFCS	230
+
+/*
+ * Raw D-Bus:
+ *
+ *	https://www.freedesktop.org/wiki/Software/dbus
+ *
+ * messages:
+ *
+ *	https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ *
+ * starting with the endianness flag, followed by the message type, etc.,
+ * but without the authentication handshake before the message sequence:
+ *
+ *	https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ *
+ * Requested by Martin Vidner <martin@vidner.net>.
+ */
+#define DLT_DBUS		231
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define DLT_JUNIPER_VS			232
+#define DLT_JUNIPER_SRX_E2E		233
+#define DLT_JUNIPER_FIBRECHANNEL	234
+
+/*
+ * DVB-CI (DVB Common Interface for communication between a PC Card
+ * module and a DVB receiver).  See
+ *
+ *	https://www.kaiser.cx/pcap-dvbci.html
+ *
+ * for the specification.
+ *
+ * Requested by Martin Kaiser <martin@kaiser.cx>.
+ */
+#define DLT_DVB_CI		235
+
+/*
+ * Variant of 3GPP TS 27.010 multiplexing protocol (similar to, but
+ * *not* the same as, 27.010).  Requested by Hans-Christoph Schemmel
+ * <hans-christoph.schemmel@cinterion.com>.
+ */
+#define DLT_MUX27010		236
+
+/*
+ * STANAG 5066 D_PDUs.  Requested by M. Baris Demiray
+ * <barisdemiray@gmail.com>.
+ */
+#define DLT_STANAG_5066_D_PDU	237
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define DLT_JUNIPER_ATM_CEMIC	238
+
+/*
+ * NetFilter LOG messages
+ * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets)
+ *
+ * Requested by Jakub Zawadzki <darkjames-ws@darkjames.pl>
+ */
+#define DLT_NFLOG		239
+
+/*
+ * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type
+ * for Ethernet packets with a 4-byte pseudo-header and always
+ * with the payload including the FCS, as supplied by their
+ * netANALYZER hardware and software.
+ *
+ * Requested by Holger P. Frommer <HPfrommer@hilscher.com>
+ */
+#define DLT_NETANALYZER		240
+
+/*
+ * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type
+ * for Ethernet packets with a 4-byte pseudo-header and FCS and
+ * with the Ethernet header preceded by 7 bytes of preamble and
+ * 1 byte of SFD, as supplied by their netANALYZER hardware and
+ * software.
+ *
+ * Requested by Holger P. Frommer <HPfrommer@hilscher.com>
+ */
+#define DLT_NETANALYZER_TRANSPARENT	241
+
+/*
+ * IP-over-InfiniBand, as specified by RFC 4391.
+ *
+ * Requested by Petr Sumbera <petr.sumbera@oracle.com>.
+ */
+#define DLT_IPOIB		242
+
+/*
+ * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0).
+ *
+ * Requested by Guy Martin <gmsoft@tuxicoman.be>.
+ */
+#define DLT_MPEG_2_TS		243
+
+/*
+ * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as
+ * used by their ng40 protocol tester.
+ *
+ * Requested by Jens Grimmer <jens.grimmer@ng4t.com>.
+ */
+#define DLT_NG40		244
+
+/*
+ * Pseudo-header giving adapter number and flags, followed by an NFC
+ * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU,
+ * as specified by NFC Forum Logical Link Control Protocol Technical
+ * Specification LLCP 1.1.
+ *
+ * Requested by Mike Wakerly <mikey@google.com>.
+ */
+#define DLT_NFC_LLCP		245
+
+/*
+ * 246 is used as LINKTYPE_PFSYNC; do not use it for any other purpose.
+ *
+ * DLT_PFSYNC has different values on different platforms, and all of
+ * them collide with something used elsewhere.  On platforms that
+ * don't already define it, define it as 246.
+ */
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__)
+#define DLT_PFSYNC		246
+#endif
+
+/*
+ * Raw InfiniBand packets, starting with the Local Routing Header.
+ *
+ * Requested by Oren Kladnitsky <orenk@mellanox.com>.
+ */
+#define DLT_INFINIBAND		247
+
+/*
+ * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6).
+ *
+ * Requested by Michael Tuexen <Michael.Tuexen@lurchi.franken.de>.
+ */
+#define DLT_SCTP		248
+
+/*
+ * USB packets, beginning with a USBPcap header.
+ *
+ * Requested by Tomasz Mon <desowin@gmail.com>
+ */
+#define DLT_USBPCAP		249
+
+/*
+ * Schweitzer Engineering Laboratories "RTAC" product serial-line
+ * packets.
+ *
+ * Requested by Chris Bontje <chris_bontje@selinc.com>.
+ */
+#define DLT_RTAC_SERIAL		250
+
+/*
+ * Bluetooth Low Energy air interface link-layer packets.
+ *
+ * Requested by Mike Kershaw <dragorn@kismetwireless.net>.
+ */
+#define DLT_BLUETOOTH_LE_LL	251
+
+/*
+ * DLT type for upper-protocol layer PDU saves from wireshark.
+ *
+ * the actual contents are determined by two TAGs stored with each
+ * packet:
+ *   EXP_PDU_TAG_LINKTYPE          the link type (LINKTYPE_ value) of the
+ *				   original packet.
+ *
+ *   EXP_PDU_TAG_PROTO_NAME        the name of the wireshark dissector
+ * 				   that can make sense of the data stored.
+ */
+#define DLT_WIRESHARK_UPPER_PDU	252
+
+/*
+ * DLT type for the netlink protocol (nlmon devices).
+ */
+#define DLT_NETLINK		253
+
+/*
+ * Bluetooth Linux Monitor headers for the BlueZ stack.
+ */
+#define DLT_BLUETOOTH_LINUX_MONITOR	254
+
+/*
+ * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as
+ * captured by Ubertooth.
+ */
+#define DLT_BLUETOOTH_BREDR_BB	255
+
+/*
+ * Bluetooth Low Energy link layer packets, as captured by Ubertooth.
+ */
+#define DLT_BLUETOOTH_LE_LL_WITH_PHDR	256
+
+/*
+ * PROFIBUS data link layer.
+ */
+#define DLT_PROFIBUS_DL		257
+
+/*
+ * Apple's DLT_PKTAP headers.
+ *
+ * Sadly, the folks at Apple either had no clue that the DLT_USERn values
+ * are for internal use within an organization and partners only, and
+ * didn't know that the right way to get a link-layer header type is to
+ * ask tcpdump.org for one, or knew and didn't care, so they just
+ * used DLT_USER2, which causes problems for everything except for
+ * their version of tcpdump.
+ *
+ * So I'll just give them one; hopefully this will show up in a
+ * libpcap release in time for them to get this into 10.10 Big Sur
+ * or whatever Mavericks' successor is called.  LINKTYPE_PKTAP
+ * will be 258 *even on macOS*; that is *intentional*, so that
+ * PKTAP files look the same on *all* OSes (different OSes can have
+ * different numerical values for a given DLT_, but *MUST NOT* have
+ * different values for what goes in a file, as files can be moved
+ * between OSes!).
+ *
+ * When capturing, on a system with a Darwin-based OS, on a device
+ * that returns 149 (DLT_USER2 and Apple's DLT_PKTAP) with this
+ * version of libpcap, the DLT_ value for the pcap_t  will be DLT_PKTAP,
+ * and that will continue to be DLT_USER2 on Darwin-based OSes. That way,
+ * binary compatibility with Mavericks is preserved for programs using
+ * this version of libpcap.  This does mean that if you were using
+ * DLT_USER2 for some capture device on macOS, you can't do so with
+ * this version of libpcap, just as you can't with Apple's libpcap -
+ * on macOS, they define DLT_PKTAP to be DLT_USER2, so programs won't
+ * be able to distinguish between PKTAP and whatever you were using
+ * DLT_USER2 for.
+ *
+ * If the program saves the capture to a file using this version of
+ * libpcap's pcap_dump code, the LINKTYPE_ value in the file will be
+ * LINKTYPE_PKTAP, which will be 258, even on Darwin-based OSes.
+ * That way, the file will *not* be a DLT_USER2 file.  That means
+ * that the latest version of tcpdump, when built with this version
+ * of libpcap, and sufficiently recent versions of Wireshark will
+ * be able to read those files and interpret them correctly; however,
+ * Apple's version of tcpdump in OS X 10.9 won't be able to handle
+ * them.  (Hopefully, Apple will pick up this version of libpcap,
+ * and the corresponding version of tcpdump, so that tcpdump will
+ * be able to handle the old LINKTYPE_USER2 captures *and* the new
+ * LINKTYPE_PKTAP captures.)
+ */
+#ifdef __APPLE__
+#define DLT_PKTAP	DLT_USER2
+#else
+#define DLT_PKTAP	258
+#endif
+
+/*
+ * Ethernet packets preceded by a header giving the last 6 octets
+ * of the preamble specified by 802.3-2012 Clause 65, section
+ * 65.1.3.2 "Transmit".
+ */
+#define DLT_EPON	259
+
+/*
+ * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format"
+ * in the PICMG HPM.2 specification.
+ */
+#define DLT_IPMI_HPM_2	260
+
+/*
+ * per  Joshua Wright <jwright@hasborg.com>, formats for Zwave captures.
+ */
+#define DLT_ZWAVE_R1_R2  261
+#define DLT_ZWAVE_R3     262
+
+/*
+ * per Steve Karg <skarg@users.sourceforge.net>, formats for Wattstopper
+ * Digital Lighting Management room bus serial protocol captures.
+ */
+#define DLT_WATTSTOPPER_DLM     263
+
+/*
+ * ISO 14443 contactless smart card messages.
+ */
+#define DLT_ISO_14443	264
+
+/*
+ * Radio data system (RDS) groups.  IEC 62106.
+ * Per Jonathan Brucker <jonathan.brucke@gmail.com>.
+ */
+#define DLT_RDS		265
+
+/*
+ * USB packets, beginning with a Darwin (macOS, etc.) header.
+ */
+#define DLT_USB_DARWIN	266
+
+/*
+ * OpenBSD DLT_OPENFLOW.
+ */
+#define DLT_OPENFLOW	267
+
+/*
+ * SDLC frames containing SNA PDUs.
+ */
+#define DLT_SDLC	268
+
+/*
+ * per "Selvig, Bjorn" <b.selvig@ti.com> used for
+ * TI protocol sniffer.
+ */
+#define DLT_TI_LLN_SNIFFER	269
+
+/*
+ * per: Erik de Jong <erikdejong at gmail.com> for
+ *   https://github.com/eriknl/LoRaTap/releases/tag/v0.1
+ */
+#define DLT_LORATAP             270
+
+/*
+ * per: Stefanha at gmail.com for
+ *   https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h
+ * for: https://qemu-project.org/Features/VirtioVsock
+ */
+#define DLT_VSOCK               271
+
+/*
+ * Nordic Semiconductor Bluetooth LE sniffer.
+ */
+#define DLT_NORDIC_BLE		272
+
+/*
+ * Excentis DOCSIS 3.1 RF sniffer (XRA-31)
+ *   per: bruno.verstuyft at excentis.com
+ *        https://www.xra31.com/xra-header
+ */
+#define DLT_DOCSIS31_XRA31	273
+
+/*
+ * mPackets, as specified by IEEE 802.3br Figure 99-4, starting
+ * with the preamble and always ending with a CRC field.
+ */
+#define DLT_ETHERNET_MPACKET	274
+
+/*
+ * DisplayPort AUX channel monitoring data as specified by VESA
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
+ *    per dirk.eibach at gdsys.cc
+ */
+#define DLT_DISPLAYPORT_AUX	275
+
+/*
+ * Linux cooked sockets v2.
+ */
+#define DLT_LINUX_SLL2	276
+
+/*
+ * Sercos Monitor, per Manuel Jacob <manuel.jacob at steinbeis-stg.de>
+ */
+#define DLT_SERCOS_MONITOR 277
+
+/*
+ * OpenVizsla http://openvizsla.org is open source USB analyzer hardware.
+ * It consists of FPGA with attached USB phy and FTDI chip for streaming
+ * the data to the host PC.
+ *
+ * Current OpenVizsla data encapsulation format is described here:
+ * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description
+ *
+ */
+#define DLT_OPENVIZSLA	        278
+
+/*
+ * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced
+ * by a PCIe Card for interfacing high speed automotive interfaces.
+ *
+ * The specification for this frame format can be found at:
+ *   https://www.elektrobit.com/ebhscr
+ *
+ * for Guenter.Ebermann at elektrobit.com
+ *
+ */
+#define DLT_EBHSCR	        279
+
+/*
+ * The https://fd.io vpp graph dispatch tracer produces pcap trace files
+ * in the format documented here:
+ * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing
+ */
+#define DLT_VPP_DISPATCH	280
+
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define DLT_DSA_TAG_BRCM	281
+#define DLT_DSA_TAG_BRCM_PREPEND	282
+
+/*
+ * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload
+ * exactly as it appears in the spec (no padding, no nothing), and FCS if
+ * specified by FCS Type TLV;  requested by James Ko <jck@exegin.com>.
+ * Specification at https://github.com/jkcko/ieee802.15.4-tap
+ */
+#define DLT_IEEE802_15_4_TAP    283
+
+/*
+ * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format.
+ */
+#define DLT_DSA_TAG_DSA		284
+#define DLT_DSA_TAG_EDSA	285
+
+/*
+ * Payload of lawful intercept packets using the ELEE protocol;
+ * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii
+ */
+#define DLT_ELEE		286
+
+/*
+ * Serial frames transmitted between a host and a Z-Wave chip.
+ */
+#define DLT_Z_WAVE_SERIAL	287
+
+/*
+ * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable.
+ */
+#define DLT_USB_2_0		288
+
+/*
+ * ATSC Link-Layer Protocol (A/330) packets.
+ */
+#define DLT_ATSC_ALP		289
+
+/*
+ * In case the code that includes this file (directly or indirectly)
+ * has also included OS files that happen to define DLT_MATCHING_MAX,
+ * with a different value (perhaps because that OS hasn't picked up
+ * the latest version of our DLT definitions), we undefine the
+ * previous value of DLT_MATCHING_MAX.
+ */
+#ifdef DLT_MATCHING_MAX
+#undef DLT_MATCHING_MAX
+#endif
+#define DLT_MATCHING_MAX	289	/* highest value in the "matching" range */
+
+/*
+ * DLT and savefile link type values are split into a class and
+ * a member of that class.  A class value of 0 indicates a regular
+ * DLT_/LINKTYPE_ value.
+ */
+#define DLT_CLASS(x)		((x) & 0x03ff0000)
+
+/*
+ * NetBSD-specific generic "raw" link type.  The class value indicates
+ * that this is the generic raw type, and the lower 16 bits are the
+ * address family we're dealing with.  Those values are NetBSD-specific;
+ * do not assume that they correspond to AF_ values for your operating
+ * system.
+ */
+#define	DLT_CLASS_NETBSD_RAWAF	0x02240000
+#define	DLT_NETBSD_RAWAF(af)	(DLT_CLASS_NETBSD_RAWAF | (af))
+#define	DLT_NETBSD_RAWAF_AF(x)	((x) & 0x0000ffff)
+#define	DLT_IS_NETBSD_RAWAF(x)	(DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF)
+
+#endif /* !defined(lib_pcap_dlt_h) */
diff --git a/pcap/funcattrs.h b/pcap/funcattrs.h
new file mode 100644
index 0000000..a2ca542
--- /dev/null
+++ b/pcap/funcattrs.h
@@ -0,0 +1,325 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_pcap_funcattrs_h
+#define lib_pcap_funcattrs_h
+
+#include <pcap/compiler-tests.h>
+
+/*
+ * Attributes to apply to functions and their arguments, using various
+ * compiler-specific extensions.
+ */
+
+/*
+ * PCAP_API_DEF must be used when defining *data* exported from
+ * libpcap.  It can be used when defining *functions* exported
+ * from libpcap, but it doesn't have to be used there.  It
+ * should not be used in declarations in headers.
+ *
+ * PCAP_API must be used when *declaring* data or functions
+ * exported from libpcap; PCAP_API_DEF won't work on all platforms.
+ */
+
+#if defined(_WIN32)
+  /*
+   * For Windows:
+   *
+   *    when building libpcap:
+   *
+   *       if we're building it as a DLL, we have to declare API
+   *       functions with __declspec(dllexport);
+   *
+   *       if we're building it as a static library, we don't want
+   *       to do so.
+   *
+   *    when using libpcap:
+   *
+   *       if we're using the DLL, calls to its functions are a
+   *       little more efficient if they're declared with
+   *       __declspec(dllimport);
+   *
+   *       if we're not using the dll, we don't want to declare
+   *       them that way.
+   *
+   * So:
+   *
+   *    if pcap_EXPORTS is defined, we define PCAP_API_DEF as
+   *     __declspec(dllexport);
+   *
+   *    if PCAP_DLL is defined, we define PCAP_API_DEF as
+   *    __declspec(dllimport);
+   *
+   *    otherwise, we define PCAP_API_DEF as nothing.
+   */
+  #if defined(pcap_EXPORTS)
+    /*
+     * We're compiling libpcap as a DLL, so we should export functions
+     * in our API.
+     */
+    #define PCAP_API_DEF	__declspec(dllexport)
+  #elif defined(PCAP_DLL)
+    /*
+     * We're using libpcap as a DLL, so the calls will be a little more
+     * efficient if we explicitly import the functions.
+     */
+    #define PCAP_API_DEF	__declspec(dllimport)
+  #else
+    /*
+     * Either we're building libpcap as a static library, or we're using
+     * it as a static library, or we don't know for certain that we're
+     * using it as a dynamic library, so neither import nor export the
+     * functions explicitly.
+     */
+    #define PCAP_API_DEF
+  #endif
+#elif defined(MSDOS)
+  /* XXX - does this need special treatment? */
+  #define PCAP_API_DEF
+#else /* UN*X */
+  #ifdef pcap_EXPORTS
+    /*
+     * We're compiling libpcap as a (dynamic) shared library, so we should
+     * export functions in our API.  The compiler might be configured not
+     * to export functions from a shared library by default, so we might
+     * have to explicitly mark functions as exported.
+     */
+    #if PCAP_IS_AT_LEAST_GNUC_VERSION(3,4) \
+        || PCAP_IS_AT_LEAST_XL_C_VERSION(12,0)
+      /*
+       * GCC 3.4 or later, or some compiler asserting compatibility with
+       * GCC 3.4 or later, or XL C 13.0 or later, so we have
+       * __attribute__((visibility()).
+       */
+      #define PCAP_API_DEF	__attribute__((visibility("default")))
+    #elif PCAP_IS_AT_LEAST_SUNC_VERSION(5,5)
+      /*
+       * Sun C 5.5 or later, so we have __global.
+       * (Sun C 5.9 and later also have __attribute__((visibility()),
+       * but there's no reason to prefer it with Sun C.)
+       */
+      #define PCAP_API_DEF	__global
+    #else
+      /*
+       * We don't have anything to say.
+       */
+      #define PCAP_API_DEF
+    #endif
+  #else
+    /*
+     * We're not building libpcap.
+     */
+    #define PCAP_API_DEF
+  #endif
+#endif /* _WIN32/MSDOS/UN*X */
+
+#define PCAP_API	PCAP_API_DEF extern
+
+/*
+ * Definitions to 1) indicate what version of libpcap first had a given
+ * API and 2) allow upstream providers whose build environments allow
+ * APIs to be designated as "first available in this release" to do so
+ * by appropriately defining them.
+ *
+ * Yes, that's you, Apple. :-)  Please define PCAP_AVAILABLE_MACOS()
+ * as necessary to make various APIs "weak exports" to make it easier
+ * for software that's distributed in binary form and that uses libpcap
+ * to run on multiple macOS versions and use new APIs when available.
+ * (Yes, such third-party software exists - Wireshark provides binary
+ * packages for macOS, for example.  tcpdump doesn't count, as that's
+ * provided by Apple, so each release can come with a version compiled
+ * to use the APIs present in that release.)
+ *
+ * We don't define it ourselves because, if you're building and
+ * installing libpcap on macOS yourself, the APIs will be available
+ * no matter what OS version you're installing it on.
+ *
+ * For other platforms, we don't define them, leaving it up to
+ * others to do so based on their OS versions, if appropriate.
+ *
+ * We start with libpcap 0.4, as that was the last LBL release, and
+ * I've never seen earlier releases.
+ */
+#ifdef __APPLE__
+#define PCAP_AVAILABLE_MACOS(v)	/* define to say "first appears in v" */
+#define PCAP_AVAILABLE_0_4	PCAP_AVAILABLE_MACOS(10.0) /* Did any version of Mac OS X ship with this? */
+#define PCAP_AVAILABLE_0_5	PCAP_AVAILABLE_MACOS(10.0) /* Did any version of Mac OS X ship with this? */
+#define PCAP_AVAILABLE_0_6	PCAP_AVAILABLE_MACOS(10.1)
+#define PCAP_AVAILABLE_0_7	PCAP_AVAILABLE_MACOS(10.4)
+#define PCAP_AVAILABLE_0_8	PCAP_AVAILABLE_MACOS(10.4)
+#define PCAP_AVAILABLE_0_9	PCAP_AVAILABLE_MACOS(10.5)
+#define PCAP_AVAILABLE_1_0	PCAP_AVAILABLE_MACOS(10.6)
+/* #define PCAP_AVAILABLE_1_1	no routines added to the API */
+#define PCAP_AVAILABLE_1_2	PCAP_AVAILABLE_MACOS(10.9)
+/* #define PCAP_AVAILABLE_1_3	no routines added to the API */
+/* #define PCAP_AVAILABLE_1_4	no routines added to the API */
+#define PCAP_AVAILABLE_1_5	PCAP_AVAILABLE_MACOS(10.10)
+/* #define PCAP_AVAILABLE_1_6	no routines added to the API */
+#define PCAP_AVAILABLE_1_7	PCAP_AVAILABLE_MACOS(10.12)
+#define PCAP_AVAILABLE_1_8	PCAP_AVAILABLE_MACOS(10.13) /* only Windows adds routines to the API; XXX - what version first had it? */
+#define PCAP_AVAILABLE_1_9	PCAP_AVAILABLE_MACOS(10.13)
+#define PCAP_AVAILABLE_1_10	/* not in macOS yet */
+#define PCAP_AVAILABLE_1_11	/* not released yet, so not in macOS yet */ 
+#else /* __APPLE__ */
+#define PCAP_AVAILABLE_0_4
+#define PCAP_AVAILABLE_0_5
+#define PCAP_AVAILABLE_0_6
+#define PCAP_AVAILABLE_0_7
+#define PCAP_AVAILABLE_0_8
+#define PCAP_AVAILABLE_0_9
+#define PCAP_AVAILABLE_1_0
+/* #define PCAP_AVAILABLE_1_1	no routines added to the API */
+#define PCAP_AVAILABLE_1_2
+/* #define PCAP_AVAILABLE_1_3	no routines added to the API */
+/* #define PCAP_AVAILABLE_1_4	no routines added to the API */
+#define PCAP_AVAILABLE_1_5
+/* #define PCAP_AVAILABLE_1_6	no routines added to the API */
+#define PCAP_AVAILABLE_1_7
+#define PCAP_AVAILABLE_1_8
+#define PCAP_AVAILABLE_1_9
+#define PCAP_AVAILABLE_1_10
+#define PCAP_AVAILABLE_1_11
+#endif /* __APPLE__ */
+
+/*
+ * PCAP_NORETURN, before a function declaration, means "this function
+ * never returns".  (It must go before the function declaration, e.g.
+ * "extern PCAP_NORETURN func(...)" rather than after the function
+ * declaration, as the MSVC version has to go before the declaration.)
+ *
+ * PCAP_NORETURN_DEF, before a function *definition*, means "this
+ * function never returns"; it would be used only for static functions
+ * that are defined before any use, and thus have no declaration.
+ * (MSVC doesn't support that; I guess the "decl" in "__declspec"
+ * means "declaration", and __declspec doesn't work with definitions.)
+ */
+#if __has_attribute(noreturn) \
+    || PCAP_IS_AT_LEAST_GNUC_VERSION(2,5) \
+    || PCAP_IS_AT_LEAST_SUNC_VERSION(5,9) \
+    || PCAP_IS_AT_LEAST_XL_C_VERSION(10,1) \
+    || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10)
+  /*
+   * Compiler with support for __attribute((noreturn)), or GCC 2.5 or
+   * later, or some compiler asserting compatibility with GCC 2.5 or
+   * later, or Solaris Studio 12 (Sun C 5.9) or later, or IBM XL C 10.1
+   * or later (do any earlier versions of XL C support this?), or HP aCC
+   * A.06.10 or later.
+   */
+  #define PCAP_NORETURN __attribute((noreturn))
+  #define PCAP_NORETURN_DEF __attribute((noreturn))
+#elif defined(_MSC_VER)
+  /*
+   * MSVC.
+   */
+  #define PCAP_NORETURN __declspec(noreturn)
+  #define PCAP_NORETURN_DEF
+#else
+  #define PCAP_NORETURN
+  #define PCAP_NORETURN_DEF
+#endif
+
+/*
+ * PCAP_PRINTFLIKE(x,y), after a function declaration, means "this function
+ * does printf-style formatting, with the xth argument being the format
+ * string and the yth argument being the first argument for the format
+ * string".
+ */
+#if __has_attribute(__format__) \
+    || PCAP_IS_AT_LEAST_GNUC_VERSION(2,3) \
+    || PCAP_IS_AT_LEAST_XL_C_VERSION(10,1) \
+    || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10)
+  /*
+   * Compiler with support for it, or GCC 2.3 or later, or some compiler
+   * asserting compatibility with GCC 2.3 or later, or IBM XL C 10.1
+   * and later (do any earlier versions of XL C support this?),
+   * or HP aCC A.06.10 and later.
+   */
+  #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y)))
+#else
+  #define PCAP_PRINTFLIKE(x,y)
+#endif
+
+/*
+ * PCAP_DEPRECATED(func, msg), after a function declaration, marks the
+ * function as deprecated.
+ *
+ * The first argument is the name of the function; the second argument is
+ * a string giving the warning message to use if the compiler supports that.
+ *
+ * (Thank you, Microsoft, for requiring the function name.)
+ */
+#if __has_attribute(deprecated) \
+    || PCAP_IS_AT_LEAST_GNUC_VERSION(4,5) \
+    || PCAP_IS_AT_LEAST_SUNC_VERSION(5,13)
+  /*
+   * Compiler that supports __has_attribute and __attribute__((deprecated)),
+   * or GCC 4.5 or later, or Sun/Oracle C 12.4 (Sun C 5.13) or later.
+   *
+   * Those support __attribute__((deprecated(msg))) (we assume, perhaps
+   * incorrectly, that anything that supports __has_attribute() is
+   * recent enough to support __attribute__((deprecated(msg)))).
+   */
+  #define PCAP_DEPRECATED(func, msg)	__attribute__((deprecated(msg)))
+#elif PCAP_IS_AT_LEAST_GNUC_VERSION(3,1)
+  /*
+   * GCC 3.1 through 4.4.
+   *
+   * Those support __attribute__((deprecated)) but not
+   * __attribute__((deprecated(msg))).
+   */
+  #define PCAP_DEPRECATED(func, msg)	__attribute__((deprecated))
+#elif defined(_MSC_VER) && !defined(BUILDING_PCAP)
+  /*
+   * MSVC, and we're not building libpcap itself; it's VS 2015
+   * or later, so we have the deprecated pragma.
+   *
+   * If we *are* building libpcap, we don't want this, as it'll warn
+   * us even if we *define* the function.
+   */
+  #define PCAP_DEPRECATED(func, msg)	__pragma(deprecated(func))
+#else
+  #define PCAP_DEPRECATED(func, msg)
+#endif
+
+/*
+ * For flagging arguments as format strings in MSVC.
+ */
+#ifdef _MSC_VER
+ #include <sal.h>
+ #define PCAP_FORMAT_STRING(p) _Printf_format_string_ p
+#else
+ #define PCAP_FORMAT_STRING(p) p
+#endif
+
+#endif /* lib_pcap_funcattrs_h */
diff --git a/pcap/ipnet.h b/pcap/ipnet.h
new file mode 100644
index 0000000..5330847
--- /dev/null
+++ b/pcap/ipnet.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define	IPH_AF_INET	2		/* Matches Solaris's AF_INET */
+#define	IPH_AF_INET6	26		/* Matches Solaris's AF_INET6 */
+
+#define	IPNET_OUTBOUND		1
+#define	IPNET_INBOUND		2
diff --git a/pcap/namedb.h b/pcap/namedb.h
new file mode 100644
index 0000000..34a0ae7
--- /dev/null
+++ b/pcap/namedb.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1994, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_pcap_namedb_h
+#define lib_pcap_namedb_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * As returned by the pcap_next_etherent()
+ * XXX this stuff doesn't belong in this interface, but this
+ * library already must do name to address translation, so
+ * on systems that don't have support for /etc/ethers, we
+ * export these hooks since they're already being used by
+ * some applications (such as tcpdump) and already being
+ * marked as exported in some OSes offering libpcap (such
+ * as Debian).
+ */
+struct pcap_etherent {
+	u_char addr[6];
+	char name[122];
+};
+#ifndef PCAP_ETHERS_FILE
+#define PCAP_ETHERS_FILE "/etc/ethers"
+#endif
+PCAP_API struct	pcap_etherent *pcap_next_etherent(FILE *);
+PCAP_API u_char *pcap_ether_hostton(const char*);
+PCAP_API u_char *pcap_ether_aton(const char *);
+
+PCAP_API bpf_u_int32 **pcap_nametoaddr(const char *)
+PCAP_DEPRECATED(pcap_nametoaddr, "this is not reentrant; use 'pcap_nametoaddrinfo' instead");
+PCAP_API struct addrinfo *pcap_nametoaddrinfo(const char *);
+PCAP_API bpf_u_int32 pcap_nametonetaddr(const char *);
+
+PCAP_API int	pcap_nametoport(const char *, int *, int *);
+PCAP_API int	pcap_nametoportrange(const char *, int *, int *, int *);
+PCAP_API int	pcap_nametoproto(const char *);
+PCAP_API int	pcap_nametoeproto(const char *);
+PCAP_API int	pcap_nametollc(const char *);
+/*
+ * If a protocol is unknown, PROTO_UNDEF is returned.
+ * Also, pcap_nametoport() returns the protocol along with the port number.
+ * If there are ambiguous entried in /etc/services (i.e. domain
+ * can be either tcp or udp) PROTO_UNDEF is returned.
+ */
+#define PROTO_UNDEF		-1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pcap/nflog.h b/pcap/nflog.h
new file mode 100644
index 0000000..f7c85b5
--- /dev/null
+++ b/pcap/nflog.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013, Petar Alilovic,
+ * Faculty of Electrical Engineering and Computing, University of Zagreb
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *	 this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *	 notice, this list of conditions and the following disclaimer in the
+ *	 documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#ifndef lib_pcap_nflog_h
+#define lib_pcap_nflog_h
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * Structure of an NFLOG header and TLV parts, as described at
+ * https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
+ *
+ * The NFLOG header is big-endian.
+ *
+ * The TLV length and type are in host byte order.  The value is either
+ * big-endian or is an array of bytes in some externally-specified byte
+ * order (text string, link-layer address, link-layer header, packet
+ * data, etc.).
+ */
+typedef struct nflog_hdr {
+	uint8_t		nflog_family;	/* address family */
+	uint8_t		nflog_version;	/* version */
+	uint16_t	nflog_rid;	/* resource ID */
+} nflog_hdr_t;
+
+typedef struct nflog_tlv {
+	uint16_t	tlv_length;	/* tlv length */
+	uint16_t	tlv_type;	/* tlv type */
+	/* value follows this */
+} nflog_tlv_t;
+
+typedef struct nflog_packet_hdr {
+	uint16_t	hw_protocol;	/* hw protocol */
+	uint8_t		hook;		/* netfilter hook */
+	uint8_t		pad;		/* padding to 32 bits */
+} nflog_packet_hdr_t;
+
+typedef struct nflog_hwaddr {
+	uint16_t	hw_addrlen;	/* address length */
+	uint16_t	pad;		/* padding to 32-bit boundary */
+	uint8_t		hw_addr[8];	/* address, up to 8 bytes */
+} nflog_hwaddr_t;
+
+typedef struct nflog_timestamp {
+	uint64_t	sec;
+	uint64_t	usec;
+} nflog_timestamp_t;
+
+/*
+ * TLV types.
+ */
+#define NFULA_PACKET_HDR		1	/* nflog_packet_hdr_t */
+#define NFULA_MARK			2	/* packet mark from skbuff */
+#define NFULA_TIMESTAMP			3	/* nflog_timestamp_t for skbuff's time stamp */
+#define NFULA_IFINDEX_INDEV		4	/* ifindex of device on which packet received (possibly bridge group) */
+#define NFULA_IFINDEX_OUTDEV		5	/* ifindex of device on which packet transmitted (possibly bridge group) */
+#define NFULA_IFINDEX_PHYSINDEV		6	/* ifindex of physical device on which packet received (not bridge group) */
+#define NFULA_IFINDEX_PHYSOUTDEV	7	/* ifindex of physical device on which packet transmitted (not bridge group) */
+#define NFULA_HWADDR			8	/* nflog_hwaddr_t for hardware address */
+#define NFULA_PAYLOAD			9	/* packet payload */
+#define NFULA_PREFIX			10	/* text string - null-terminated, count includes NUL */
+#define NFULA_UID			11	/* UID owning socket on which packet was sent/received */
+#define NFULA_SEQ			12	/* sequence number of packets on this NFLOG socket */
+#define NFULA_SEQ_GLOBAL		13	/* sequence number of pakets on all NFLOG sockets */
+#define NFULA_GID			14	/* GID owning socket on which packet was sent/received */
+#define NFULA_HWTYPE			15	/* ARPHRD_ type of skbuff's device */
+#define NFULA_HWHEADER			16	/* skbuff's MAC-layer header */
+#define NFULA_HWLEN			17	/* length of skbuff's MAC-layer header */
+
+#endif
diff --git a/pcap/pcap-inttypes.h b/pcap/pcap-inttypes.h
new file mode 100644
index 0000000..1cfa0bf
--- /dev/null
+++ b/pcap/pcap-inttypes.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef pcap_pcap_inttypes_h
+#define pcap_pcap_inttypes_h
+
+/*
+ * If we're compiling with Visual Studio, make sure we have at least
+ * VS 2015 or later, so we have sufficient C99 support.
+ *
+ * XXX - verify that we have at least C99 support on UN*Xes?
+ *
+ * What about MinGW or various DOS toolchains?  We're currently assuming
+ * sufficient C99 support there.
+ */
+#if defined(_MSC_VER)
+  /*
+   * Compiler is MSVC.  Make sure we have VS 2015 or later.
+   */
+  #if _MSC_VER < 1900
+    #error "Building libpcap requires VS 2015 or later"
+  #endif
+#endif
+
+/*
+ * Include <inttypes.h> to get the integer types and PRi[doux]64 values
+ * defined.
+ *
+ * If the compiler is MSVC, we require VS 2015 or newer, so we
+ * have <inttypes.h> - and support for %zu in the formatted
+ * printing functions.
+ *
+ * If the compiler is MinGW, we assume we have <inttypes.h> - and
+ * support for %zu in the formatted printing functions.
+ *
+ * If the target is UN*X, we assume we have a C99-or-later development
+ * environment, and thus have <inttypes.h> - and support for %zu in
+ * the formatted printing functions.
+ *
+ * If the target is MS-DOS, we assume we have <inttypes.h> - and support
+ * for %zu in the formatted printing functions.
+ *
+ * I.e., assume we have <inttypes.h> and that it suffices.
+ */
+
+/*
+ * XXX - somehow make sure we have enough C99 support with other
+ * compilers and support libraries?
+ */
+
+#include <inttypes.h>
+
+#endif /* pcap/pcap-inttypes.h */
diff --git a/pcap/pcap.h b/pcap/pcap.h
new file mode 100644
index 0000000..8182bef
--- /dev/null
+++ b/pcap/pcap.h
@@ -0,0 +1,1219 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Remote packet capture mechanisms and extensions from WinPcap:
+ *
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef lib_pcap_pcap_h
+#define lib_pcap_pcap_h
+
+/*
+ * Some software that uses libpcap/WinPcap/Npcap defines _MSC_VER before
+ * includeing pcap.h if it's not defined - and it defines it to 1500.
+ * (I'm looking at *you*, lwIP!)
+ *
+ * Attempt to detect this, and undefine _MSC_VER so that we can *reliably*
+ * use it to know what compiler is being used and, if it's Visual Studio,
+ * what version is being used.
+ */
+#if defined(_MSC_VER)
+  /*
+   * We assume here that software such as that doesn't define _MSC_FULL_VER
+   * as well and that it defines _MSC_VER with a value > 1200.
+   *
+   * DO NOT BREAK THESE ASSUMPTIONS.  IF YOU FEEL YOU MUST DEFINE _MSC_VER
+   * WITH A COMPILER THAT'S NOT MICROSOFT'S C COMPILER, PLEASE CONTACT
+   * US SO THAT WE CAN MAKE IT SO THAT YOU DON'T HAVE TO DO THAT.  THANK
+   * YOU.
+   *
+   * OK, is _MSC_FULL_VER defined?
+   */
+  #if !defined(_MSC_FULL_VER)
+    /*
+     * According to
+     *
+     *    https://sourceforge.net/p/predef/wiki/Compilers/
+     *
+     * with "Visual C++ 6.0 Processor Pack"/Visual C++ 6.0 SP6 and
+     * later, _MSC_FULL_VER is defined, so either this is an older
+     * version of Visual C++ or it's not Visual C++ at all.
+     *
+     * For Visual C++ 6.0, _MSC_VER is defined as 1200.
+     */
+    #if _MSC_VER > 1200
+      /*
+       * If this is Visual C++, _MSC_FULL_VER should be defined, so we
+       * assume this isn't Visual C++, and undo the lie that it is.
+       */
+      #undef _MSC_VER
+    #endif
+  #endif
+#endif
+
+#include <pcap/funcattrs.h>
+
+#include <pcap/pcap-inttypes.h>
+
+#if defined(_WIN32)
+  #include <winsock2.h>		/* u_int, u_char etc. */
+  #include <io.h>		/* _get_osfhandle() */
+#elif defined(MSDOS)
+  #include <sys/types.h>	/* u_int, u_char etc. */
+  #include <sys/socket.h>
+#else /* UN*X */
+  #include <sys/types.h>	/* u_int, u_char etc. */
+  #include <sys/time.h>
+#endif /* _WIN32/MSDOS/UN*X */
+
+#include <pcap/socket.h>	/* for SOCKET, as the active-mode rpcap APIs use it */
+
+#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H
+#include <pcap/bpf.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Version number of the current version of the pcap file format.
+ *
+ * NOTE: this is *NOT* the version number of the libpcap library.
+ * To fetch the version information for the version of libpcap
+ * you're using, use pcap_lib_version().
+ */
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+
+#define PCAP_ERRBUF_SIZE 256
+
+/*
+ * Compatibility for systems that have a bpf.h that
+ * predates the bpf typedefs for 64-bit support.
+ */
+#if BPF_RELEASE - 0 < 199406
+typedef	int bpf_int32;
+typedef	u_int bpf_u_int32;
+#endif
+
+typedef struct pcap pcap_t;
+typedef struct pcap_dumper pcap_dumper_t;
+typedef struct pcap_if pcap_if_t;
+typedef struct pcap_addr pcap_addr_t;
+
+/*
+ * The first record in the file contains saved values for some
+ * of the flags used in the printout phases of tcpdump.
+ * Many fields here are 32 bit ints so compilers won't insert unwanted
+ * padding; these files need to be interchangeable across architectures.
+ * Documentation: https://www.tcpdump.org/manpages/pcap-savefile.5.txt.
+ *
+ * Do not change the layout of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure).
+ *
+ * Also, do not change the interpretation of any of the members of this
+ * structure, in any way (this includes using values other than
+ * LINKTYPE_ values, as defined in "savefile.c", in the "linktype"
+ * field).
+ *
+ * Instead:
+ *
+ *	introduce a new structure for the new format, if the layout
+ *	of the structure changed;
+ *
+ *	send mail to "tcpdump-workers@lists.tcpdump.org", requesting
+ *	a new magic number for your new capture file format, and, when
+ *	you get the new magic number, put it in "savefile.c";
+ *
+ *	use that magic number for save files with the changed file
+ *	header;
+ *
+ *	make the code in "savefile.c" capable of reading files with
+ *	the old file header as well as files with the new file header
+ *	(using the magic number to determine the header format).
+ *
+ * Then supply the changes by forking the branch at
+ *
+ *	https://github.com/the-tcpdump-group/libpcap/tree/master
+ *
+ * and issuing a pull request, so that future versions of libpcap and
+ * programs that use it (such as tcpdump) will be able to read your new
+ * capture file format.
+ */
+struct pcap_file_header {
+	bpf_u_int32 magic;
+	u_short version_major;
+	u_short version_minor;
+	bpf_int32 thiszone;	/* gmt to local correction; this is always 0 */
+	bpf_u_int32 sigfigs;	/* accuracy of timestamps; this is always 0 */
+	bpf_u_int32 snaplen;	/* max length saved portion of each pkt */
+	bpf_u_int32 linktype;	/* data link type (LINKTYPE_*) */
+};
+
+/*
+ * Macros for the value returned by pcap_datalink_ext().
+ *
+ * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro
+ * gives the FCS length of packets in the capture.
+ */
+#define LT_FCS_LENGTH_PRESENT(x)	((x) & 0x04000000)
+#define LT_FCS_LENGTH(x)		(((x) & 0xF0000000) >> 28)
+#define LT_FCS_DATALINK_EXT(x)		((((x) & 0xF) << 28) | 0x04000000)
+
+typedef enum {
+       PCAP_D_INOUT = 0,
+       PCAP_D_IN,
+       PCAP_D_OUT
+} pcap_direction_t;
+
+/*
+ * Generic per-packet information, as supplied by libpcap.
+ *
+ * The time stamp can and should be a "struct timeval", regardless of
+ * whether your system supports 32-bit tv_sec in "struct timeval",
+ * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit
+ * and 64-bit applications.  The on-disk format of savefiles uses 32-bit
+ * tv_sec (and tv_usec); this structure is irrelevant to that.  32-bit
+ * and 64-bit versions of libpcap, even if they're on the same platform,
+ * should supply the appropriate version of "struct timeval", even if
+ * that's not what the underlying packet capture mechanism supplies.
+ */
+struct pcap_pkthdr {
+	struct timeval ts;	/* time stamp */
+	bpf_u_int32 caplen;	/* length of portion present */
+	bpf_u_int32 len;	/* length of this packet (off wire) */
+};
+
+/*
+ * As returned by the pcap_stats()
+ */
+struct pcap_stat {
+	u_int ps_recv;		/* number of packets received */
+	u_int ps_drop;		/* number of packets dropped */
+	u_int ps_ifdrop;	/* drops by interface -- only supported on some platforms */
+#ifdef _WIN32
+	u_int ps_capt;		/* number of packets that reach the application */
+	u_int ps_sent;		/* number of packets sent by the server on the network */
+	u_int ps_netdrop;	/* number of packets lost on the network */
+#endif /* _WIN32 */
+};
+
+#ifdef MSDOS
+/*
+ * As returned by the pcap_stats_ex()
+ */
+struct pcap_stat_ex {
+       u_long  rx_packets;        /* total packets received       */
+       u_long  tx_packets;        /* total packets transmitted    */
+       u_long  rx_bytes;          /* total bytes received         */
+       u_long  tx_bytes;          /* total bytes transmitted      */
+       u_long  rx_errors;         /* bad packets received         */
+       u_long  tx_errors;         /* packet transmit problems     */
+       u_long  rx_dropped;        /* no space in Rx buffers       */
+       u_long  tx_dropped;        /* no space available for Tx    */
+       u_long  multicast;         /* multicast packets received   */
+       u_long  collisions;
+
+       /* detailed rx_errors: */
+       u_long  rx_length_errors;
+       u_long  rx_over_errors;    /* receiver ring buff overflow  */
+       u_long  rx_crc_errors;     /* recv'd pkt with crc error    */
+       u_long  rx_frame_errors;   /* recv'd frame alignment error */
+       u_long  rx_fifo_errors;    /* recv'r fifo overrun          */
+       u_long  rx_missed_errors;  /* recv'r missed packet         */
+
+       /* detailed tx_errors */
+       u_long  tx_aborted_errors;
+       u_long  tx_carrier_errors;
+       u_long  tx_fifo_errors;
+       u_long  tx_heartbeat_errors;
+       u_long  tx_window_errors;
+     };
+#endif
+
+/*
+ * Item in a list of interfaces.
+ */
+struct pcap_if {
+	struct pcap_if *next;
+	char *name;		/* name to hand to "pcap_open_live()" */
+	char *description;	/* textual description of interface, or NULL */
+	struct pcap_addr *addresses;
+	bpf_u_int32 flags;	/* PCAP_IF_ interface flags */
+};
+
+#define PCAP_IF_LOOPBACK				0x00000001	/* interface is loopback */
+#define PCAP_IF_UP					0x00000002	/* interface is up */
+#define PCAP_IF_RUNNING					0x00000004	/* interface is running */
+#define PCAP_IF_WIRELESS				0x00000008	/* interface is wireless (*NOT* necessarily Wi-Fi!) */
+#define PCAP_IF_CONNECTION_STATUS			0x00000030	/* connection status: */
+#define PCAP_IF_CONNECTION_STATUS_UNKNOWN		0x00000000	/* unknown */
+#define PCAP_IF_CONNECTION_STATUS_CONNECTED		0x00000010	/* connected */
+#define PCAP_IF_CONNECTION_STATUS_DISCONNECTED		0x00000020	/* disconnected */
+#define PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE	0x00000030	/* not applicable */
+
+/*
+ * Representation of an interface address.
+ */
+struct pcap_addr {
+	struct pcap_addr *next;
+	struct sockaddr *addr;		/* address */
+	struct sockaddr *netmask;	/* netmask for that address */
+	struct sockaddr *broadaddr;	/* broadcast address for that address */
+	struct sockaddr *dstaddr;	/* P2P destination address for that address */
+};
+
+typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
+			     const u_char *);
+
+/*
+ * Error codes for the pcap API.
+ * These will all be negative, so you can check for the success or
+ * failure of a call that returns these codes by checking for a
+ * negative value.
+ */
+#define PCAP_ERROR			-1	/* generic error code */
+#define PCAP_ERROR_BREAK		-2	/* loop terminated by pcap_breakloop */
+#define PCAP_ERROR_NOT_ACTIVATED	-3	/* the capture needs to be activated */
+#define PCAP_ERROR_ACTIVATED		-4	/* the operation can't be performed on already activated captures */
+#define PCAP_ERROR_NO_SUCH_DEVICE	-5	/* no such device exists */
+#define PCAP_ERROR_RFMON_NOTSUP		-6	/* this device doesn't support rfmon (monitor) mode */
+#define PCAP_ERROR_NOT_RFMON		-7	/* operation supported only in monitor mode */
+#define PCAP_ERROR_PERM_DENIED		-8	/* no permission to open the device */
+#define PCAP_ERROR_IFACE_NOT_UP		-9	/* interface isn't up */
+#define PCAP_ERROR_CANTSET_TSTAMP_TYPE	-10	/* this device doesn't support setting the time stamp type */
+#define PCAP_ERROR_PROMISC_PERM_DENIED	-11	/* you don't have permission to capture in promiscuous mode */
+#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12  /* the requested time stamp precision is not supported */
+
+/*
+ * Warning codes for the pcap API.
+ * These will all be positive and non-zero, so they won't look like
+ * errors.
+ */
+#define PCAP_WARNING			1	/* generic warning code */
+#define PCAP_WARNING_PROMISC_NOTSUP	2	/* this device doesn't support promiscuous mode */
+#define PCAP_WARNING_TSTAMP_TYPE_NOTSUP	3	/* the requested time stamp type is not supported */
+
+/*
+ * Value to pass to pcap_compile() as the netmask if you don't know what
+ * the netmask is.
+ */
+#define PCAP_NETMASK_UNKNOWN	0xffffffff
+
+/*
+ * Initialize pcap.  If this isn't called, pcap is initialized to
+ * a mode source-compatible and binary-compatible with older versions
+ * that lack this routine.
+ */
+
+/*
+ * Initialization options.
+ * All bits not listed here are reserved for expansion.
+ *
+ * On UNIX-like systems, the local character encoding is assumed to be
+ * UTF-8, so no character encoding transformations are done.
+ *
+ * On Windows, the local character encoding is the local ANSI code page.
+ */
+#define PCAP_CHAR_ENC_LOCAL	0x00000000U	/* strings are in the local character encoding */
+#define PCAP_CHAR_ENC_UTF_8	0x00000001U	/* strings are in UTF-8 */
+
+PCAP_AVAILABLE_1_10
+PCAP_API int	pcap_init(unsigned int, char *);
+
+/*
+ * We're deprecating pcap_lookupdev() for various reasons (not
+ * thread-safe, can behave weirdly with WinPcap).  Callers
+ * should use pcap_findalldevs() and use the first device.
+ */
+PCAP_AVAILABLE_0_4
+PCAP_API char	*pcap_lookupdev(char *)
+PCAP_DEPRECATED(pcap_lookupdev, "use 'pcap_findalldevs' and use the first device");
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API pcap_t	*pcap_create(const char *, char *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_set_snaplen(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_set_promisc(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_can_set_rfmon(pcap_t *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_set_rfmon(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_set_timeout(pcap_t *, int);
+
+PCAP_AVAILABLE_1_2
+PCAP_API int	pcap_set_tstamp_type(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API int	pcap_set_immediate_mode(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_set_buffer_size(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API int	pcap_set_tstamp_precision(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API int	pcap_get_tstamp_precision(pcap_t *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_activate(pcap_t *);
+
+PCAP_AVAILABLE_1_2
+PCAP_API int	pcap_list_tstamp_types(pcap_t *, int **);
+
+PCAP_AVAILABLE_1_2
+PCAP_API void	pcap_free_tstamp_types(int *);
+
+PCAP_AVAILABLE_1_2
+PCAP_API int	pcap_tstamp_type_name_to_val(const char *);
+
+PCAP_AVAILABLE_1_2
+PCAP_API const char *pcap_tstamp_type_val_to_name(int);
+
+PCAP_AVAILABLE_1_2
+PCAP_API const char *pcap_tstamp_type_val_to_description(int);
+
+#ifdef __linux__
+PCAP_AVAILABLE_1_9
+PCAP_API int	pcap_set_protocol_linux(pcap_t *, int);
+#endif
+
+/*
+ * Time stamp types.
+ * Not all systems and interfaces will necessarily support all of these.
+ *
+ * A system that supports PCAP_TSTAMP_HOST is offering time stamps
+ * provided by the host machine, rather than by the capture device,
+ * but not committing to any characteristics of the time stamp.
+ *
+ * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine,
+ * that's low-precision but relatively cheap to fetch; it's normally done
+ * using the system clock, so it's normally synchronized with times you'd
+ * fetch from system calls.
+ *
+ * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine,
+ * that's high-precision; it might be more expensive to fetch.  It is
+ * synchronized with the system clock.
+ *
+ * PCAP_TSTAMP_HOST_HIPREC_UNSYNCED is a time stamp, provided by the host
+ * machine, that's high-precision; it might be more expensive to fetch.
+ * It is not synchronized with the system clock, and might have
+ * problems with time stamps for packets received on different CPUs,
+ * depending on the platform.  It might be more likely to be strictly
+ * monotonic than PCAP_TSTAMP_HOST_HIPREC.
+ *
+ * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the
+ * capture device; it's synchronized with the system clock.
+ *
+ * PCAP_TSTAMP_ADAPTER_UNSYNCED is a high-precision time stamp supplied by
+ * the capture device; it's not synchronized with the system clock.
+ *
+ * Note that time stamps synchronized with the system clock can go
+ * backwards, as the system clock can go backwards.  If a clock is
+ * not in sync with the system clock, that could be because the
+ * system clock isn't keeping accurate time, because the other
+ * clock isn't keeping accurate time, or both.
+ *
+ * Note that host-provided time stamps generally correspond to the
+ * time when the time-stamping code sees the packet; this could
+ * be some unknown amount of time after the first or last bit of
+ * the packet is received by the network adapter, due to batching
+ * of interrupts for packet arrival, queueing delays, etc..
+ */
+#define PCAP_TSTAMP_HOST			0	/* host-provided, unknown characteristics */
+#define PCAP_TSTAMP_HOST_LOWPREC		1	/* host-provided, low precision, synced with the system clock */
+#define PCAP_TSTAMP_HOST_HIPREC			2	/* host-provided, high precision, synced with the system clock */
+#define PCAP_TSTAMP_ADAPTER			3	/* device-provided, synced with the system clock */
+#define PCAP_TSTAMP_ADAPTER_UNSYNCED		4	/* device-provided, not synced with the system clock */
+#define PCAP_TSTAMP_HOST_HIPREC_UNSYNCED	5	/* host-provided, high precision, not synced with the system clock */
+
+/*
+ * Time stamp resolution types.
+ * Not all systems and interfaces will necessarily support all of these
+ * resolutions when doing live captures; all of them can be requested
+ * when reading a savefile.
+ */
+#define PCAP_TSTAMP_PRECISION_MICRO	0	/* use timestamps with microsecond precision, default */
+#define PCAP_TSTAMP_PRECISION_NANO	1	/* use timestamps with nanosecond precision */
+
+PCAP_AVAILABLE_0_4
+PCAP_API pcap_t	*pcap_open_live(const char *, int, int, int, char *);
+
+PCAP_AVAILABLE_0_6
+PCAP_API pcap_t	*pcap_open_dead(int, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API pcap_t	*pcap_open_dead_with_tstamp_precision(int, int, u_int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API pcap_t	*pcap_open_offline_with_tstamp_precision(const char *, u_int, char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API pcap_t	*pcap_open_offline(const char *, char *);
+
+#ifdef _WIN32
+  PCAP_AVAILABLE_1_5
+  PCAP_API pcap_t  *pcap_hopen_offline_with_tstamp_precision(intptr_t, u_int, char *);
+
+  PCAP_API pcap_t  *pcap_hopen_offline(intptr_t, char *);
+  /*
+   * If we're building libpcap, these are internal routines in savefile.c,
+   * so we must not define them as macros.
+   *
+   * If we're not building libpcap, given that the version of the C runtime
+   * with which libpcap was built might be different from the version
+   * of the C runtime with which an application using libpcap was built,
+   * and that a FILE structure may differ between the two versions of the
+   * C runtime, calls to _fileno() must use the version of _fileno() in
+   * the C runtime used to open the FILE *, not the version in the C
+   * runtime with which libpcap was built.  (Maybe once the Universal CRT
+   * rules the world, this will cease to be a problem.)
+   */
+  #ifndef BUILDING_PCAP
+    #define pcap_fopen_offline_with_tstamp_precision(f,p,b) \
+	pcap_hopen_offline_with_tstamp_precision(_get_osfhandle(_fileno(f)), p, b)
+    #define pcap_fopen_offline(f,b) \
+	pcap_hopen_offline(_get_osfhandle(_fileno(f)), b)
+  #endif
+#else /*_WIN32*/
+  PCAP_AVAILABLE_1_5
+  PCAP_API pcap_t	*pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *);
+
+  PCAP_AVAILABLE_0_9
+  PCAP_API pcap_t	*pcap_fopen_offline(FILE *, char *);
+#endif /*_WIN32*/
+
+PCAP_AVAILABLE_0_4
+PCAP_API void	pcap_close(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_loop(pcap_t *, int, pcap_handler, u_char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_dispatch(pcap_t *, int, pcap_handler, u_char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API const u_char *pcap_next(pcap_t *, struct pcap_pkthdr *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int 	pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **);
+
+PCAP_AVAILABLE_0_8
+PCAP_API void	pcap_breakloop(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_stats(pcap_t *, struct pcap_stat *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_setfilter(pcap_t *, struct bpf_program *);
+
+PCAP_AVAILABLE_0_9
+PCAP_API int 	pcap_setdirection(pcap_t *, pcap_direction_t);
+
+PCAP_AVAILABLE_0_7
+PCAP_API int	pcap_getnonblock(pcap_t *, char *);
+
+PCAP_AVAILABLE_0_7
+PCAP_API int	pcap_setnonblock(pcap_t *, int, char *);
+
+PCAP_AVAILABLE_0_9
+PCAP_API int	pcap_inject(pcap_t *, const void *, size_t);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int	pcap_sendpacket(pcap_t *, const u_char *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API const char *pcap_statustostr(int);
+
+PCAP_AVAILABLE_0_4
+PCAP_API const char *pcap_strerror(int);
+
+PCAP_AVAILABLE_0_4
+PCAP_API char	*pcap_geterr(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API void	pcap_perror(pcap_t *, const char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_compile(pcap_t *, struct bpf_program *, const char *, int,
+	    bpf_u_int32);
+
+PCAP_AVAILABLE_0_5
+PCAP_API int	pcap_compile_nopcap(int, int, struct bpf_program *,
+	    const char *, int, bpf_u_int32);
+
+/* XXX - this took two arguments in 0.4 and 0.5 */
+PCAP_AVAILABLE_0_6
+PCAP_API void	pcap_freecode(struct bpf_program *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_offline_filter(const struct bpf_program *,
+	    const struct pcap_pkthdr *, const u_char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_datalink(pcap_t *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int	pcap_datalink_ext(pcap_t *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int	pcap_list_datalinks(pcap_t *, int **);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int	pcap_set_datalink(pcap_t *, int);
+
+PCAP_AVAILABLE_0_8
+PCAP_API void	pcap_free_datalinks(int *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int	pcap_datalink_name_to_val(const char *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API const char *pcap_datalink_val_to_name(int);
+
+PCAP_AVAILABLE_0_8
+PCAP_API const char *pcap_datalink_val_to_description(int);
+
+PCAP_AVAILABLE_1_10
+PCAP_API const char *pcap_datalink_val_to_description_or_dlt(int);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_snapshot(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_is_swapped(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_major_version(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_minor_version(pcap_t *);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int	pcap_bufsize(pcap_t *);
+
+/* XXX */
+PCAP_AVAILABLE_0_4
+PCAP_API FILE	*pcap_file(pcap_t *);
+
+#ifdef _WIN32
+/*
+ * This probably shouldn't have been kept in WinPcap; most if not all
+ * UN*X code that used it won't work on Windows.  We deprecate it; if
+ * anybody really needs access to whatever HANDLE may be associated
+ * with a pcap_t (there's no guarantee that there is one), we can add
+ * a Windows-only pcap_handle() API that returns the HANDLE.
+ */
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_fileno(pcap_t *)
+PCAP_DEPRECATED(pcap_fileno, "use 'pcap_handle'");
+#else /* _WIN32 */
+PCAP_AVAILABLE_0_4
+PCAP_API int	pcap_fileno(pcap_t *);
+#endif /* _WIN32 */
+
+#ifdef _WIN32
+  PCAP_API int	pcap_wsockinit(void);
+#endif
+
+PCAP_AVAILABLE_0_4
+PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *);
+
+#ifdef _WIN32
+  PCAP_AVAILABLE_0_9
+  PCAP_API pcap_dumper_t *pcap_dump_hopen(pcap_t *, intptr_t);
+
+  /*
+   * If we're building libpcap, this is an internal routine in sf-pcap.c, so
+   * we must not define it as a macro.
+   *
+   * If we're not building libpcap, given that the version of the C runtime
+   * with which libpcap was built might be different from the version
+   * of the C runtime with which an application using libpcap was built,
+   * and that a FILE structure may differ between the two versions of the
+   * C runtime, calls to _fileno() must use the version of _fileno() in
+   * the C runtime used to open the FILE *, not the version in the C
+   * runtime with which libpcap was built.  (Maybe once the Universal CRT
+   * rules the world, this will cease to be a problem.)
+   */
+  #ifndef BUILDING_PCAP
+    #define pcap_dump_fopen(p,f) \
+	pcap_dump_hopen(p, _get_osfhandle(_fileno(f)))
+  #endif
+#else /*_WIN32*/
+  PCAP_AVAILABLE_0_9
+  PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp);
+#endif /*_WIN32*/
+
+PCAP_AVAILABLE_1_7
+PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API FILE	*pcap_dump_file(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_9
+PCAP_API long	pcap_dump_ftell(pcap_dumper_t *);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int64_t	pcap_dump_ftell64(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int	pcap_dump_flush(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API void	pcap_dump_close(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API void	pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *);
+
+PCAP_AVAILABLE_0_7
+PCAP_API int	pcap_findalldevs(pcap_if_t **, char *);
+
+PCAP_AVAILABLE_0_7
+PCAP_API void	pcap_freealldevs(pcap_if_t *);
+
+/*
+ * We return a pointer to the version string, rather than exporting the
+ * version string directly.
+ *
+ * On at least some UNIXes, if you import data from a shared library into
+ * a program, the data is bound into the program binary, so if the string
+ * in the version of the library with which the program was linked isn't
+ * the same as the string in the version of the library with which the
+ * program is being run, various undesirable things may happen (warnings,
+ * the string being the one from the version of the library with which the
+ * program was linked, or even weirder things, such as the string being the
+ * one from the library but being truncated).
+ *
+ * On Windows, the string is constructed at run time.
+ */
+PCAP_AVAILABLE_0_8
+PCAP_API const char *pcap_lib_version(void);
+
+#if defined(_WIN32)
+
+  /*
+   * Win32 definitions
+   */
+
+  /*!
+    \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit().
+  */
+  struct pcap_send_queue
+  {
+	u_int maxlen;	/* Maximum size of the queue, in bytes. This
+			   variable contains the size of the buffer field. */
+	u_int len;	/* Current size of the queue, in bytes. */
+	char *buffer;	/* Buffer containing the packets to be sent. */
+  };
+
+  typedef struct pcap_send_queue pcap_send_queue;
+
+  /*!
+    \brief This typedef is a support for the pcap_get_airpcap_handle() function
+  */
+  #if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_)
+    #define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_
+    typedef struct _AirpcapHandle *PAirpcapHandle;
+  #endif
+
+  PCAP_API int pcap_setbuff(pcap_t *p, int dim);
+  PCAP_API int pcap_setmode(pcap_t *p, int mode);
+  PCAP_API int pcap_setmintocopy(pcap_t *p, int size);
+
+  PCAP_API HANDLE pcap_getevent(pcap_t *p);
+
+  PCAP_AVAILABLE_1_8
+  PCAP_API int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *);
+
+  PCAP_AVAILABLE_1_8
+  PCAP_API int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *);
+
+  PCAP_API pcap_send_queue* pcap_sendqueue_alloc(u_int memsize);
+
+  PCAP_API void pcap_sendqueue_destroy(pcap_send_queue* queue);
+
+  PCAP_API int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data);
+
+  PCAP_API u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync);
+
+  PCAP_API struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size);
+
+  PCAP_API int pcap_setuserbuffer(pcap_t *p, int size);
+
+  PCAP_API int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks);
+
+  PCAP_API int pcap_live_dump_ended(pcap_t *p, int sync);
+
+  PCAP_API int pcap_start_oem(char* err_str, int flags);
+
+  PCAP_API PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p);
+
+  #define MODE_CAPT 0
+  #define MODE_STAT 1
+  #define MODE_MON 2
+
+#elif defined(MSDOS)
+
+  /*
+   * MS-DOS definitions
+   */
+
+  PCAP_API int  pcap_stats_ex (pcap_t *, struct pcap_stat_ex *);
+  PCAP_API void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait);
+  PCAP_API u_long pcap_mac_packets (void);
+
+#else /* UN*X */
+
+  /*
+   * UN*X definitions
+   */
+
+  PCAP_AVAILABLE_0_8
+  PCAP_API int	pcap_get_selectable_fd(pcap_t *);
+
+  PCAP_AVAILABLE_1_9
+  PCAP_API const struct timeval *pcap_get_required_select_timeout(pcap_t *);
+
+#endif /* _WIN32/MSDOS/UN*X */
+
+/*
+ * Remote capture definitions.
+ *
+ * These routines are only present if libpcap has been configured to
+ * include remote capture support.
+ */
+
+/*
+ * The maximum buffer size in which address, port, interface names are kept.
+ *
+ * In case the adapter name or such is larger than this value, it is truncated.
+ * This is not used by the user; however it must be aware that an hostname / interface
+ * name longer than this value will be truncated.
+ */
+#define PCAP_BUF_SIZE 1024
+
+/*
+ * The type of input source, passed to pcap_open().
+ */
+#define PCAP_SRC_FILE		2	/* local savefile */
+#define PCAP_SRC_IFLOCAL	3	/* local network interface */
+#define PCAP_SRC_IFREMOTE	4	/* interface on a remote host, using RPCAP */
+
+/*
+ * The formats allowed by pcap_open() are the following:
+ * - file://path_and_filename [opens a local file]
+ * - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol]
+ * - rpcap://host/devicename [opens the selected device available on a remote host]
+ * - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP]
+ * - adaptername [to open a local adapter; kept for compatibility, but it is strongly discouraged]
+ * - (NULL) [to open the first local adapter; kept for compatibility, but it is strongly discouraged]
+ *
+ * The formats allowed by the pcap_findalldevs_ex() are the following:
+ * - file://folder/ [lists all the files in the given folder]
+ * - rpcap:// [lists all local adapters]
+ * - rpcap://host:port/ [lists the devices available on a remote host]
+ *
+ * In all the above, "rpcaps://" can be substituted for "rpcap://" to enable
+ * SSL (if it has been compiled in).
+ *
+ * Referring to the 'host' and 'port' parameters, they can be either numeric or literal. Since
+ * IPv6 is fully supported, these are the allowed formats:
+ *
+ * - host (literal): e.g. host.foo.bar
+ * - host (numeric IPv4): e.g. 10.11.12.13
+ * - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13]
+ * - host (numeric IPv6): e.g. [1:2:3::4]
+ * - port: can be either numeric (e.g. '80') or literal (e.g. 'http')
+ *
+ * Here you find some allowed examples:
+ * - rpcap://host.foo.bar/devicename [everything literal, no port number]
+ * - rpcap://host.foo.bar:1234/devicename [everything literal, with port number]
+ * - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number]
+ * - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number]
+ * - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number]
+ * - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number]
+ * - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number]
+ * - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number]
+ */
+
+/*
+ * URL schemes for capture source.
+ */
+/*
+ * This string indicates that the user wants to open a capture from a
+ * local file.
+ */
+#define PCAP_SRC_FILE_STRING "file://"
+/*
+ * This string indicates that the user wants to open a capture from a
+ * network interface.  This string does not necessarily involve the use
+ * of the RPCAP protocol. If the interface required resides on the local
+ * host, the RPCAP protocol is not involved and the local functions are used.
+ */
+#define PCAP_SRC_IF_STRING "rpcap://"
+
+/*
+ * Flags to pass to pcap_open().
+ */
+
+/*
+ * Specifies whether promiscuous mode is to be used.
+ */
+#define PCAP_OPENFLAG_PROMISCUOUS		0x00000001
+
+/*
+ * Specifies, for an RPCAP capture, whether the data transfer (in
+ * case of a remote capture) has to be done with UDP protocol.
+ *
+ * If it is '1' if you want a UDP data connection, '0' if you want
+ * a TCP data connection; control connection is always TCP-based.
+ * A UDP connection is much lighter, but it does not guarantee that all
+ * the captured packets arrive to the client workstation. Moreover,
+ * it could be harmful in case of network congestion.
+ * This flag is meaningless if the source is not a remote interface.
+ * In that case, it is simply ignored.
+ */
+#define PCAP_OPENFLAG_DATATX_UDP		0x00000002
+
+/*
+ * Specifies whether the remote probe will capture its own generated
+ * traffic.
+ *
+ * In case the remote probe uses the same interface to capture traffic
+ * and to send data back to the caller, the captured traffic includes
+ * the RPCAP traffic as well.  If this flag is turned on, the RPCAP
+ * traffic is excluded from the capture, so that the trace returned
+ * back to the collector is does not include this traffic.
+ *
+ * Has no effect on local interfaces or savefiles.
+ */
+#define PCAP_OPENFLAG_NOCAPTURE_RPCAP		0x00000004
+
+/*
+ * Specifies whether the local adapter will capture its own generated traffic.
+ *
+ * This flag tells the underlying capture driver to drop the packets
+ * that were sent by itself.  This is useful when building applications
+ * such as bridges that should ignore the traffic they just sent.
+ *
+ * Supported only on Windows.
+ */
+#define PCAP_OPENFLAG_NOCAPTURE_LOCAL		0x00000008
+
+/*
+ * This flag configures the adapter for maximum responsiveness.
+ *
+ * In presence of a large value for nbytes, WinPcap waits for the arrival
+ * of several packets before copying the data to the user. This guarantees
+ * a low number of system calls, i.e. lower processor usage, i.e. better
+ * performance, which is good for applications like sniffers. If the user
+ * sets the PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will
+ * copy the packets as soon as the application is ready to receive them.
+ * This is suggested for real time applications (such as, for example,
+ * a bridge) that need the best responsiveness.
+ *
+ * The equivalent with pcap_create()/pcap_activate() is "immediate mode".
+ */
+#define PCAP_OPENFLAG_MAX_RESPONSIVENESS	0x00000010
+
+/*
+ * Remote authentication methods.
+ * These are used in the 'type' member of the pcap_rmtauth structure.
+ */
+
+/*
+ * NULL authentication.
+ *
+ * The 'NULL' authentication has to be equal to 'zero', so that old
+ * applications can just put every field of struct pcap_rmtauth to zero,
+ * and it does work.
+ */
+#define RPCAP_RMTAUTH_NULL 0
+/*
+ * Username/password authentication.
+ *
+ * With this type of authentication, the RPCAP protocol will use the username/
+ * password provided to authenticate the user on the remote machine. If the
+ * authentication is successful (and the user has the right to open network
+ * devices) the RPCAP connection will continue; otherwise it will be dropped.
+ *
+ * *******NOTE********: the username and password are sent over the network
+ * to the capture server *IN CLEAR TEXT*.  Don't use this on a network
+ * that you don't completely control!  (And be *really* careful in your
+ * definition of "completely"!)
+ */
+#define RPCAP_RMTAUTH_PWD 1
+
+/*
+ * This structure keeps the information needed to authenticate the user
+ * on a remote machine.
+ *
+ * The remote machine can either grant or refuse the access according
+ * to the information provided.
+ * In case the NULL authentication is required, both 'username' and
+ * 'password' can be NULL pointers.
+ *
+ * This structure is meaningless if the source is not a remote interface;
+ * in that case, the functions which requires such a structure can accept
+ * a NULL pointer as well.
+ */
+struct pcap_rmtauth
+{
+	/*
+	 * \brief Type of the authentication required.
+	 *
+	 * In order to provide maximum flexibility, we can support different types
+	 * of authentication based on the value of this 'type' variable. The currently
+	 * supported authentication methods are defined into the
+	 * \link remote_auth_methods Remote Authentication Methods Section\endlink.
+	 */
+	int type;
+	/*
+	 * \brief Zero-terminated string containing the username that has to be
+	 * used on the remote machine for authentication.
+	 *
+	 * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+	 * and it can be NULL.
+	 */
+	char *username;
+	/*
+	 * \brief Zero-terminated string containing the password that has to be
+	 * used on the remote machine for authentication.
+	 *
+	 * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+	 * and it can be NULL.
+	 */
+	char *password;
+};
+
+/*
+ * This routine can open a savefile, a local device, or a device on
+ * a remote machine running an RPCAP server.
+ *
+ * For opening a savefile, the pcap_open_offline routines can be used,
+ * and will work just as well; code using them will work on more
+ * platforms than code using pcap_open() to open savefiles.
+ *
+ * For opening a local device, pcap_open_live() can be used; it supports
+ * most of the capabilities that pcap_open() supports, and code using it
+ * will work on more platforms than code using pcap_open().  pcap_create()
+ * and pcap_activate() can also be used; they support all capabilities
+ * that pcap_open() supports, except for the Windows-only
+ * PCAP_OPENFLAG_NOCAPTURE_LOCAL, and support additional capabilities.
+ *
+ * For opening a remote capture, pcap_open() is currently the only
+ * API available.
+ */
+PCAP_AVAILABLE_1_9
+PCAP_API pcap_t	*pcap_open(const char *source, int snaplen, int flags,
+	    int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int	pcap_createsrcstr(char *source, int type, const char *host,
+	    const char *port, const char *name, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int	pcap_parsesrcstr(const char *source, int *type, char *host,
+	    char *port, char *name, char *errbuf);
+
+/*
+ * This routine can scan a directory for savefiles, list local capture
+ * devices, or list capture devices on a remote machine running an RPCAP
+ * server.
+ *
+ * For scanning for savefiles, it can be used on both UN*X systems and
+ * Windows systems; for each directory entry it sees, it tries to open
+ * the file as a savefile using pcap_open_offline(), and only includes
+ * it in the list of files if the open succeeds, so it filters out
+ * files for which the user doesn't have read permission, as well as
+ * files that aren't valid savefiles readable by libpcap.
+ *
+ * For listing local capture devices, it's just a wrapper around
+ * pcap_findalldevs(); code using pcap_findalldevs() will work on more
+ * platforms than code using pcap_findalldevs_ex().
+ *
+ * For listing remote capture devices, pcap_findalldevs_ex() is currently
+ * the only API available.
+ */
+PCAP_AVAILABLE_1_9
+PCAP_API int	pcap_findalldevs_ex(const char *source,
+	    struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf);
+
+/*
+ * Sampling methods.
+ *
+ * These allow pcap_loop(), pcap_dispatch(), pcap_next(), and pcap_next_ex()
+ * to see only a sample of packets, rather than all packets.
+ *
+ * Currently, they work only on Windows local captures.
+ */
+
+/*
+ * Specifies that no sampling is to be done on the current capture.
+ *
+ * In this case, no sampling algorithms are applied to the current capture.
+ */
+#define PCAP_SAMP_NOSAMP	0
+
+/*
+ * Specifies that only 1 out of N packets must be returned to the user.
+ *
+ * In this case, the 'value' field of the 'pcap_samp' structure indicates the
+ * number of packets (minus 1) that must be discarded before one packet got
+ * accepted.
+ * In other words, if 'value = 10', the first packet is returned to the
+ * caller, while the following 9 are discarded.
+ */
+#define PCAP_SAMP_1_EVERY_N	1
+
+/*
+ * Specifies that we have to return 1 packet every N milliseconds.
+ *
+ * In this case, the 'value' field of the 'pcap_samp' structure indicates
+ * the 'waiting time' in milliseconds before one packet got accepted.
+ * In other words, if 'value = 10', the first packet is returned to the
+ * caller; the next returned one will be the first packet that arrives
+ * when 10ms have elapsed.
+ */
+#define PCAP_SAMP_FIRST_AFTER_N_MS 2
+
+/*
+ * This structure defines the information related to sampling.
+ *
+ * In case the sampling is requested, the capturing device should read
+ * only a subset of the packets coming from the source. The returned packets
+ * depend on the sampling parameters.
+ *
+ * WARNING: The sampling process is applied *after* the filtering process.
+ * In other words, packets are filtered first, then the sampling process
+ * selects a subset of the 'filtered' packets and it returns them to the
+ * caller.
+ */
+struct pcap_samp
+{
+	/*
+	 * Method used for sampling; see above.
+	 */
+	int method;
+
+	/*
+	 * This value depends on the sampling method defined.
+	 * For its meaning, see above.
+	 */
+	int value;
+};
+
+/*
+ * New functions.
+ */
+PCAP_AVAILABLE_1_9
+PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p);
+
+/*
+ * RPCAP active mode.
+ */
+
+/* Maximum length of an host name (needed for the RPCAP active mode) */
+#define RPCAP_HOSTLIST_SIZE 1024
+
+PCAP_AVAILABLE_1_9
+PCAP_API SOCKET	pcap_remoteact_accept(const char *address, const char *port,
+	    const char *hostlist, char *connectinghost,
+	    struct pcap_rmtauth *auth, char *errbuf);
+
+PCAP_AVAILABLE_1_10
+PCAP_API SOCKET	pcap_remoteact_accept_ex(const char *address, const char *port,
+	    const char *hostlist, char *connectinghost,
+	    struct pcap_rmtauth *auth, int uses_ssl, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int	pcap_remoteact_list(char *hostlist, char sep, int size,
+	    char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int	pcap_remoteact_close(const char *host, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API void	pcap_remoteact_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* lib_pcap_pcap_h */
diff --git a/pcap/sll.h b/pcap/sll.h
new file mode 100644
index 0000000..392faae
--- /dev/null
+++ b/pcap/sll.h
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * For captures on Linux cooked sockets, we construct a fake header
+ * that includes:
+ *
+ *	a 2-byte "packet type" which is one of:
+ *
+ *		LINUX_SLL_HOST		packet was sent to us
+ *		LINUX_SLL_BROADCAST	packet was broadcast
+ *		LINUX_SLL_MULTICAST	packet was multicast
+ *		LINUX_SLL_OTHERHOST	packet was sent to somebody else
+ *		LINUX_SLL_OUTGOING	packet was sent *by* us;
+ *
+ *	a 2-byte Ethernet protocol field;
+ *
+ *	a 2-byte link-layer type;
+ *
+ *	a 2-byte link-layer address length;
+ *
+ *	an 8-byte source link-layer address, whose actual length is
+ *	specified by the previous value.
+ *
+ * All fields except for the link-layer address are in network byte order.
+ *
+ * DO NOT change the layout of this structure, or change any of the
+ * LINUX_SLL_ values below.  If you must change the link-layer header
+ * for a "cooked" Linux capture, introduce a new DLT_ type (ask
+ * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it
+ * a value that collides with a value already being used), and use the
+ * new header in captures of that type, so that programs that can
+ * handle DLT_LINUX_SLL captures will continue to handle them correctly
+ * without any change, and so that capture files with different headers
+ * can be told apart and programs that read them can dissect the
+ * packets in them.
+ */
+
+#ifndef lib_pcap_sll_h
+#define lib_pcap_sll_h
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * A DLT_LINUX_SLL fake link-layer header.
+ */
+#define SLL_HDR_LEN	16		/* total header length */
+#define SLL_ADDRLEN	8		/* length of address field */
+
+struct sll_header {
+	uint16_t sll_pkttype;		/* packet type */
+	uint16_t sll_hatype;		/* link-layer address type */
+	uint16_t sll_halen;		/* link-layer address length */
+	uint8_t  sll_addr[SLL_ADDRLEN];	/* link-layer address */
+	uint16_t sll_protocol;		/* protocol */
+};
+
+/*
+ * A DLT_LINUX_SLL2 fake link-layer header.
+ */
+#define SLL2_HDR_LEN	20		/* total header length */
+
+struct sll2_header {
+	uint16_t sll2_protocol;			/* protocol */
+	uint16_t sll2_reserved_mbz;		/* reserved - must be zero */
+	uint32_t sll2_if_index;			/* 1-based interface index */
+	uint16_t sll2_hatype;			/* link-layer address type */
+	uint8_t  sll2_pkttype;			/* packet type */
+	uint8_t  sll2_halen;			/* link-layer address length */
+	uint8_t  sll2_addr[SLL_ADDRLEN];	/* link-layer address */
+};
+
+/*
+ * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for
+ * "sll2_pkttype"; these correspond to the PACKET_ values on Linux,
+ * which are defined by a header under include/uapi in the current
+ * kernel source, and are thus not going to change on Linux.  We
+ * define them here so that they're available even on systems other
+ * than Linux.
+ */
+#define LINUX_SLL_HOST		0
+#define LINUX_SLL_BROADCAST	1
+#define LINUX_SLL_MULTICAST	2
+#define LINUX_SLL_OTHERHOST	3
+#define LINUX_SLL_OUTGOING	4
+
+/*
+ * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for
+ * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but
+ * are defined here so that they're available even on systems other than
+ * Linux.  We assume, for now, that the ETH_P_ values won't change in
+ * Linux; if they do, then:
+ *
+ *	if we don't translate them in "pcap-linux.c", capture files
+ *	won't necessarily be readable if captured on a system that
+ *	defines ETH_P_ values that don't match these values;
+ *
+ *	if we do translate them in "pcap-linux.c", that makes life
+ *	unpleasant for the BPF code generator, as the values you test
+ *	for in the kernel aren't the values that you test for when
+ *	reading a capture file, so the fixup code run on BPF programs
+ *	handed to the kernel ends up having to do more work.
+ *
+ * Add other values here as necessary, for handling packet types that
+ * might show up on non-Ethernet, non-802.x networks.  (Not all the ones
+ * in the Linux "if_ether.h" will, I suspect, actually show up in
+ * captures.)
+ */
+#define LINUX_SLL_P_802_3	0x0001	/* Novell 802.3 frames without 802.2 LLC header */
+#define LINUX_SLL_P_802_2	0x0004	/* 802.2 frames (not D/I/X Ethernet) */
+#define LINUX_SLL_P_CAN		0x000C	/* CAN frames, with SocketCAN pseudo-headers */
+#define LINUX_SLL_P_CANFD	0x000D	/* CAN FD frames, with SocketCAN pseudo-headers */
+
+#endif
diff --git a/pcap/socket.h b/pcap/socket.h
new file mode 100644
index 0000000..ee2e393
--- /dev/null
+++ b/pcap/socket.h
@@ -0,0 +1,84 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_pcap_socket_h
+#define lib_pcap_socket_h
+
+/*
+ * Some minor differences between sockets on various platforms.
+ * We include whatever sockets are needed for Internet-protocol
+ * socket access on UN*X and Windows.
+ */
+#ifdef _WIN32
+  /* Need windef.h for defines used in winsock2.h under MingW32 */
+  #ifdef __MINGW32__
+    #include <windef.h>
+  #endif
+  #include <winsock2.h>
+  #include <ws2tcpip.h>
+
+  /*
+   * Winsock doesn't have this POSIX type; it's used for the
+   * tv_usec value of struct timeval.
+   */
+  typedef long suseconds_t;
+#else /* _WIN32 */
+  #include <sys/types.h>
+  #include <sys/socket.h>
+  #include <netdb.h>		/* for struct addrinfo/getaddrinfo() */
+  #include <netinet/in.h>	/* for sockaddr_in, in BSD at least */
+  #include <arpa/inet.h>
+
+  /*!
+   * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's
+   * a file descriptor, and therefore a signed integer.
+   * We define SOCKET to be a signed integer on UN*X, so that it can
+   * be used on both platforms.
+   */
+  #ifndef SOCKET
+    #define SOCKET int
+  #endif
+
+  /*!
+   * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET;
+   * in UN*X, it's -1.
+   * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on
+   * both platforms.
+   */
+  #ifndef INVALID_SOCKET
+    #define INVALID_SOCKET -1
+  #endif
+#endif /* _WIN32 */
+
+#endif /* lib_pcap_socket_h */
diff --git a/pcap/usb.h b/pcap/usb.h
new file mode 100644
index 0000000..e485ec8
--- /dev/null
+++ b/pcap/usb.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2006 Paolo Abeni (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Basic USB data struct
+ * By Paolo Abeni <paolo.abeni@email.it>
+ */
+
+#ifndef lib_pcap_usb_h
+#define lib_pcap_usb_h
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * possible transfer mode
+ */
+#define URB_TRANSFER_IN   0x80
+#define URB_ISOCHRONOUS   0x0
+#define URB_INTERRUPT     0x1
+#define URB_CONTROL       0x2
+#define URB_BULK          0x3
+
+/*
+ * possible event type
+ */
+#define URB_SUBMIT        'S'
+#define URB_COMPLETE      'C'
+#define URB_ERROR         'E'
+
+/*
+ * USB setup header as defined in USB specification.
+ * Appears at the front of each Control S-type packet in DLT_USB captures.
+ */
+typedef struct _usb_setup {
+	uint8_t bmRequestType;
+	uint8_t bRequest;
+	uint16_t wValue;
+	uint16_t wIndex;
+	uint16_t wLength;
+} pcap_usb_setup;
+
+/*
+ * Information from the URB for Isochronous transfers.
+ */
+typedef struct _iso_rec {
+	int32_t	error_count;
+	int32_t	numdesc;
+} iso_rec;
+
+/*
+ * Header prepended by linux kernel to each event.
+ * Appears at the front of each packet in DLT_USB_LINUX captures.
+ */
+typedef struct _usb_header {
+	uint64_t id;
+	uint8_t event_type;
+	uint8_t transfer_type;
+	uint8_t endpoint_number;
+	uint8_t device_address;
+	uint16_t bus_id;
+	char setup_flag;/*if !=0 the urb setup header is not present*/
+	char data_flag; /*if !=0 no urb data is present*/
+	int64_t ts_sec;
+	int32_t ts_usec;
+	int32_t status;
+	uint32_t urb_len;
+	uint32_t data_len; /* amount of urb data really present in this event*/
+	pcap_usb_setup setup;
+} pcap_usb_header;
+
+/*
+ * Header prepended by linux kernel to each event for the 2.6.31
+ * and later kernels; for the 2.6.21 through 2.6.30 kernels, the
+ * "iso_rec" information, and the fields starting with "interval"
+ * are zeroed-out padding fields.
+ *
+ * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures.
+ */
+typedef struct _usb_header_mmapped {
+	uint64_t id;
+	uint8_t event_type;
+	uint8_t transfer_type;
+	uint8_t endpoint_number;
+	uint8_t device_address;
+	uint16_t bus_id;
+	char setup_flag;/*if !=0 the urb setup header is not present*/
+	char data_flag; /*if !=0 no urb data is present*/
+	int64_t ts_sec;
+	int32_t ts_usec;
+	int32_t status;
+	uint32_t urb_len;
+	uint32_t data_len; /* amount of urb data really present in this event*/
+	union {
+		pcap_usb_setup setup;
+		iso_rec iso;
+	} s;
+	int32_t	interval;	/* for Interrupt and Isochronous events */
+	int32_t start_frame;	/* for Isochronous events */
+	uint32_t xfer_flags;	/* copy of URB's transfer flags */
+	uint32_t ndesc;	/* number of isochronous descriptors */
+} pcap_usb_header_mmapped;
+
+/*
+ * Isochronous descriptors; for isochronous transfers there might be
+ * one or more of these at the beginning of the packet data.  The
+ * number of descriptors is given by the "ndesc" field in the header;
+ * as indicated, in older kernels that don't put the descriptors at
+ * the beginning of the packet, that field is zeroed out, so that field
+ * can be trusted even in captures from older kernels.
+ */
+typedef struct _usb_isodesc {
+	int32_t		status;
+	uint32_t	offset;
+	uint32_t	len;
+	uint8_t	pad[4];
+} usb_isodesc;
+
+#endif
diff --git a/portability.h b/portability.h
new file mode 100644
index 0000000..84d0778
--- /dev/null
+++ b/portability.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef portability_h
+#define	portability_h
+
+/*
+ * Helpers for portability between Windows and UN*X and between different
+ * flavors of UN*X.
+ */
+#include <stdarg.h>	/* we declare varargs functions on some platforms */
+
+#include "pcap/funcattrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_STRLCAT
+  #define pcap_strlcat	strlcat
+#else
+  #if defined(_MSC_VER) || defined(__MINGW32__)
+    /*
+     * strncat_s() is supported at least back to Visual
+     * Studio 2005; we require Visual Studio 2015 or later.
+     */
+    #define pcap_strlcat(x, y, z) \
+	strncat_s((x), (z), (y), _TRUNCATE)
+  #else
+    /*
+     * Define it ourselves.
+     */
+    extern size_t pcap_strlcat(char * restrict dst, const char * restrict src, size_t dstsize);
+  #endif
+#endif
+
+#ifdef HAVE_STRLCPY
+  #define pcap_strlcpy	strlcpy
+#else
+  #if defined(_MSC_VER) || defined(__MINGW32__)
+    /*
+     * strncpy_s() is supported at least back to Visual
+     * Studio 2005; we require Visual Studio 2015 or later.
+     */
+    #define pcap_strlcpy(x, y, z) \
+	strncpy_s((x), (z), (y), _TRUNCATE)
+  #else
+    /*
+     * Define it ourselves.
+     */
+    extern size_t pcap_strlcpy(char * restrict dst, const char * restrict src, size_t dstsize);
+  #endif
+#endif
+
+#ifdef _MSC_VER
+  /*
+   * If <crtdbg.h> has been included, and _DEBUG is defined, and
+   * __STDC__ is zero, <crtdbg.h> will define strdup() to call
+   * _strdup_dbg().  So if it's already defined, don't redefine
+   * it.
+   */
+  #ifndef strdup
+  #define strdup	_strdup
+  #endif
+#endif
+
+/*
+ * We want asprintf(), for some cases where we use it to construct
+ * dynamically-allocated variable-length strings; it's present on
+ * some, but not all, platforms.
+ */
+#ifdef HAVE_ASPRINTF
+#define pcap_asprintf asprintf
+#else
+extern int pcap_asprintf(char **, PCAP_FORMAT_STRING(const char *), ...)
+    PCAP_PRINTFLIKE(2, 3);
+#endif
+
+#ifdef HAVE_VASPRINTF
+#define pcap_vasprintf vasprintf
+#else
+extern int pcap_vasprintf(char **, const char *, va_list ap);
+#endif
+
+/* For Solaris before 11. */
+#ifndef timeradd
+#define timeradd(a, b, result)                       \
+  do {                                               \
+    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;    \
+    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
+    if ((result)->tv_usec >= 1000000) {              \
+      ++(result)->tv_sec;                            \
+      (result)->tv_usec -= 1000000;                  \
+    }                                                \
+  } while (0)
+#endif /* timeradd */
+#ifndef timersub
+#define timersub(a, b, result)                       \
+  do {                                               \
+    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;    \
+    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+    if ((result)->tv_usec < 0) {                     \
+      --(result)->tv_sec;                            \
+      (result)->tv_usec += 1000000;                  \
+    }                                                \
+  } while (0)
+#endif /* timersub */
+
+#ifdef HAVE_STRTOK_R
+  #define pcap_strtok_r	strtok_r
+#else
+  #ifdef _WIN32
+    /*
+     * Microsoft gives it a different name.
+     */
+    #define pcap_strtok_r	strtok_s
+  #else
+    /*
+     * Define it ourselves.
+     */
+    extern char *pcap_strtok_r(char *, const char *, char **);
+  #endif
+#endif /* HAVE_STRTOK_R */
+
+#ifdef _WIN32
+  #if !defined(__cplusplus)
+    #define inline __inline
+  #endif
+#endif /* _WIN32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ppp.h b/ppp.h
new file mode 100644
index 0000000..d6e70c1
--- /dev/null
+++ b/ppp.h
@@ -0,0 +1,57 @@
+/*
+ * Point to Point Protocol (PPP) RFC1331
+ *
+ * Copyright 1989 by Carnegie Mellon.
+ *
+ * Permission to use, copy, modify, and distribute this program for any
+ * purpose and without fee is hereby granted, provided that this copyright
+ * and permission notice appear on all copies and supporting documentation,
+ * the name of Carnegie Mellon not be used in advertising or publicity
+ * pertaining to distribution of the program without specific prior
+ * permission, and notice be given in supporting documentation that copying
+ * and distribution is by permission of Carnegie Mellon and Stanford
+ * University.  Carnegie Mellon makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+#define PPP_ADDRESS	0xff	/* The address byte value */
+#define PPP_CONTROL	0x03	/* The control byte value */
+
+#define PPP_PPPD_IN	0x00	/* non-standard for DLT_PPP_PPPD */
+#define PPP_PPPD_OUT	0x01	/* non-standard for DLT_PPP_PPPD */
+
+/* Protocol numbers */
+#define PPP_IP		0x0021	/* Raw IP */
+#define PPP_OSI		0x0023	/* OSI Network Layer */
+#define PPP_NS		0x0025	/* Xerox NS IDP */
+#define PPP_DECNET	0x0027	/* DECnet Phase IV */
+#define PPP_APPLE	0x0029	/* Appletalk */
+#define PPP_IPX		0x002b	/* Novell IPX */
+#define PPP_VJC		0x002d	/* Van Jacobson Compressed TCP/IP */
+#define PPP_VJNC	0x002f	/* Van Jacobson Uncompressed TCP/IP */
+#define PPP_BRPDU	0x0031	/* Bridging PDU */
+#define PPP_STII	0x0033	/* Stream Protocol (ST-II) */
+#define PPP_VINES	0x0035	/* Banyan Vines */
+#define PPP_IPV6	0x0057	/* Internet Protocol version 6 */
+
+#define PPP_HELLO	0x0201	/* 802.1d Hello Packets */
+#define PPP_LUXCOM	0x0231	/* Luxcom */
+#define PPP_SNS		0x0233	/* Sigma Network Systems */
+#define PPP_MPLS_UCAST  0x0281  /* rfc 3032 */
+#define PPP_MPLS_MCAST  0x0283  /* rfc 3022 */
+
+#define PPP_IPCP	0x8021	/* IP Control Protocol */
+#define PPP_OSICP	0x8023	/* OSI Network Layer Control Protocol */
+#define PPP_NSCP	0x8025	/* Xerox NS IDP Control Protocol */
+#define PPP_DECNETCP	0x8027	/* DECnet Control Protocol */
+#define PPP_APPLECP	0x8029	/* Appletalk Control Protocol */
+#define PPP_IPXCP	0x802b	/* Novell IPX Control Protocol */
+#define PPP_STIICP	0x8033	/* Strean Protocol Control Protocol */
+#define PPP_VINESCP	0x8035	/* Banyan Vines Control Protocol */
+#define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
+#define PPP_MPLSCP      0x8281  /* rfc 3022 */
+
+#define PPP_LCP		0xc021	/* Link Control Protocol */
+#define PPP_PAP		0xc023	/* Password Authentication Protocol */
+#define PPP_LQM		0xc025	/* Link Quality Monitoring */
+#define PPP_CHAP	0xc223	/* Challenge Handshake Authentication Protocol */
diff --git a/savefile.c b/savefile.c
new file mode 100644
index 0000000..d04b917
--- /dev/null
+++ b/savefile.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * savefile.c - supports offline use of tcpdump
+ *	Extraction/creation by Jeffrey Mogul, DECWRL
+ *	Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif /* _WIN32 */
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h> /* for INT_MAX */
+
+#include "pcap-int.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "sf-pcap.h"
+#include "sf-pcapng.h"
+#include "pcap-common.h"
+#include "charconv.h"
+
+#ifdef _WIN32
+/*
+ * This isn't exported on Windows, because it would only work if both
+ * WinPcap/Npcap and the code using it were to use the Universal CRT; otherwise,
+ * a FILE structure in WinPcap/Npcap and a FILE structure in the code using it
+ * could be different if they're using different versions of the C runtime.
+ *
+ * Instead, pcap/pcap.h defines it as a macro that wraps the hopen version,
+ * with the wrapper calling _fileno() and _get_osfhandle() themselves,
+ * so that it convert the appropriate CRT version's FILE structure to
+ * a HANDLE (which is OS-defined, not CRT-defined, and is part of the Win32
+ * and Win64 ABIs).
+ */
+static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *);
+#endif
+
+/*
+ * Setting O_BINARY on DOS/Windows is a bit tricky
+ */
+#if defined(_WIN32)
+  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
+#elif defined(MSDOS)
+  #if defined(__HIGHC__)
+  #define SET_BINMODE(f)  setmode(f, O_BINARY)
+  #else
+  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
+  #endif
+#endif
+
+static int
+sf_getnonblock(pcap_t *p _U_)
+{
+	/*
+	 * This is a savefile, not a live capture file, so never say
+	 * it's in non-blocking mode.
+	 */
+	return (0);
+}
+
+static int
+sf_setnonblock(pcap_t *p, int nonblock _U_)
+{
+	/*
+	 * This is a savefile, not a live capture file, so reject
+	 * requests to put it in non-blocking mode.  (If it's a
+	 * pipe, it could be put in non-blocking mode, but that
+	 * would significantly complicate the code to read packets,
+	 * as it would have to handle reading partial packets and
+	 * keeping the state of the read.)
+	 */
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Savefiles cannot be put into non-blocking mode");
+	return (-1);
+}
+
+static int
+sf_stats(pcap_t *p, struct pcap_stat *ps _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Statistics aren't available from savefiles");
+	return (-1);
+}
+
+#ifdef _WIN32
+static struct pcap_stat *
+sf_stats_ex(pcap_t *p, int *size _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Statistics aren't available from savefiles");
+	return (NULL);
+}
+
+static int
+sf_setbuff(pcap_t *p, int dim _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The kernel buffer size cannot be set while reading from a file");
+	return (-1);
+}
+
+static int
+sf_setmode(pcap_t *p, int mode _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "impossible to set mode while reading from a file");
+	return (-1);
+}
+
+static int
+sf_setmintocopy(pcap_t *p, int size _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The mintocopy parameter cannot be set while reading from a file");
+	return (-1);
+}
+
+static HANDLE
+sf_getevent(pcap_t *pcap)
+{
+	(void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+	    "The read event cannot be retrieved while reading from a file");
+	return (INVALID_HANDLE_VALUE);
+}
+
+static int
+sf_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+    size_t *lenp _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "An OID get request cannot be performed on a file");
+	return (PCAP_ERROR);
+}
+
+static int
+sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+    size_t *lenp _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "An OID set request cannot be performed on a file");
+	return (PCAP_ERROR);
+}
+
+static u_int
+sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
+{
+	pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
+	    PCAP_ERRBUF_SIZE);
+	return (0);
+}
+
+static int
+sf_setuserbuffer(pcap_t *p, int size _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "The user buffer cannot be set when reading from a file");
+	return (-1);
+}
+
+static int
+sf_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Live packet dumping cannot be performed when reading from a file");
+	return (-1);
+}
+
+static int
+sf_live_dump_ended(pcap_t *p, int sync _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+	return (-1);
+}
+
+static PAirpcapHandle
+sf_get_airpcap_handle(pcap_t *pcap _U_)
+{
+	return (NULL);
+}
+#endif
+
+static int
+sf_inject(pcap_t *p, const void *buf _U_, int size _U_)
+{
+	pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
+	    PCAP_ERRBUF_SIZE);
+	return (-1);
+}
+
+/*
+ * Set direction flag: Which packets do we accept on a forwarding
+ * single device? IN, OUT or both?
+ */
+static int
+sf_setdirection(pcap_t *p, pcap_direction_t d _U_)
+{
+	snprintf(p->errbuf, sizeof(p->errbuf),
+	    "Setting direction is not supported on savefiles");
+	return (-1);
+}
+
+void
+sf_cleanup(pcap_t *p)
+{
+	if (p->rfile != stdin)
+		(void)fclose(p->rfile);
+	if (p->buffer != NULL)
+		free(p->buffer);
+	pcap_freecode(&p->fcode);
+}
+
+#ifdef _WIN32
+/*
+ * Wrapper for fopen() and _wfopen().
+ *
+ * If we're in UTF-8 mode, map the pathname from UTF-8 to UTF-16LE and
+ * call _wfopen().
+ *
+ * If we're not, just use fopen(); that'll treat it as being in the
+ * local code page.
+ */
+FILE *
+charset_fopen(const char *path, const char *mode)
+{
+	wchar_t *utf16_path;
+#define MAX_MODE_LEN	16
+	wchar_t utf16_mode[MAX_MODE_LEN+1];
+	int i;
+	char c;
+	FILE *fp;
+	int save_errno;
+
+	if (pcap_utf_8_mode) {
+		/*
+		 * Map from UTF-8 to UTF-16LE.
+		 * Fail if there are invalid characters in the input
+		 * string, rather than converting them to REPLACEMENT
+		 * CHARACTER; the latter is appropriate for strings
+		 * to be displayed to the user, but for file names
+		 * you just want the attempt to open the file to fail.
+		 */
+		utf16_path = cp_to_utf_16le(CP_UTF8, path,
+		    MB_ERR_INVALID_CHARS);
+		if (utf16_path == NULL) {
+			/*
+			 * Error.  Assume errno has been set.
+			 *
+			 * XXX - what about Windows errors?
+			 */
+			return (NULL);
+		}
+
+		/*
+		 * Now convert the mode to UTF-16LE as well.
+		 * We assume the mode is ASCII, and that
+		 * it's short, so that's easy.
+		 */
+		for (i = 0; (c = *mode) != '\0'; i++, mode++) {
+			if (c > 0x7F) {
+				/* Not an ASCII character; fail with EINVAL. */
+				free(utf16_path);
+				errno = EINVAL;
+				return (NULL);
+			}
+			if (i >= MAX_MODE_LEN) {
+				/* The mode string is longer than we allow. */
+				free(utf16_path);
+				errno = EINVAL;
+				return (NULL);
+			}
+			utf16_mode[i] = c;
+		}
+		utf16_mode[i] = '\0';
+
+		/*
+		 * OK, we have UTF-16LE strings; hand them to
+		 * _wfopen().
+		 */
+		fp = _wfopen(utf16_path, utf16_mode);
+
+		/*
+		 * Make sure freeing the UTF-16LE string doesn't
+		 * overwrite the error code we got from _wfopen().
+		 */
+		save_errno = errno;
+		free(utf16_path);
+		errno = save_errno;
+
+		return (fp);
+	} else {
+		/*
+		 * This takes strings in the local code page as an
+		 * argument.
+		 */
+		return (fopen(path, mode));
+	}
+}
+#endif
+
+pcap_t *
+pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
+					char *errbuf)
+{
+	FILE *fp;
+	pcap_t *p;
+
+	if (fname == NULL) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "A null pointer was supplied as the file name");
+		return (NULL);
+	}
+	if (fname[0] == '-' && fname[1] == '\0')
+	{
+		fp = stdin;
+		if (stdin == NULL) {
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "The standard input is not open");
+			return (NULL);
+		}
+#if defined(_WIN32) || defined(MSDOS)
+		/*
+		 * We're reading from the standard input, so put it in binary
+		 * mode, as savefiles are binary files.
+		 */
+		SET_BINMODE(fp);
+#endif
+	}
+	else {
+		/*
+		 * Use charset_fopen(); on Windows, it tests whether we're
+		 * in "local code page" or "UTF-8" mode, and treats the
+		 * pathname appropriately, and on other platforms, it just
+		 * wraps fopen().
+		 *
+		 * "b" is supported as of C90, so *all* UN*Xes should
+		 * support it, even though it does nothing.  For MS-DOS,
+		 * we again need it.
+		 */
+		fp = charset_fopen(fname, "rb");
+		if (fp == NULL) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "%s", fname);
+			return (NULL);
+		}
+	}
+	p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf);
+	if (p == NULL) {
+		if (fp != stdin)
+			fclose(fp);
+	}
+	return (p);
+}
+
+pcap_t *
+pcap_open_offline(const char *fname, char *errbuf)
+{
+	return (pcap_open_offline_with_tstamp_precision(fname,
+	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
+}
+
+#ifdef _WIN32
+pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision,
+    char *errbuf)
+{
+	int fd;
+	FILE *file;
+
+	fd = _open_osfhandle(osfd, _O_RDONLY);
+	if ( fd < 0 )
+	{
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "_open_osfhandle");
+		return NULL;
+	}
+
+	file = _fdopen(fd, "rb");
+	if ( file == NULL )
+	{
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "_fdopen");
+		_close(fd);
+		return NULL;
+	}
+
+	return pcap_fopen_offline_with_tstamp_precision(file, precision,
+	    errbuf);
+}
+
+pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf)
+{
+	return pcap_hopen_offline_with_tstamp_precision(osfd,
+	    PCAP_TSTAMP_PRECISION_MICRO, errbuf);
+}
+#endif
+
+/*
+ * Given a link-layer header type and snapshot length, return a
+ * snapshot length to use when reading the file; it's guaranteed
+ * to be > 0 and <= INT_MAX.
+ *
+ * XXX - the only reason why we limit it to <= INT_MAX is so that
+ * it fits in p->snapshot, and the only reason that p->snapshot is
+ * signed is that pcap_snapshot() returns an int, not an unsigned int.
+ */
+bpf_u_int32
+pcap_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen)
+{
+	if (snaplen == 0 || snaplen > INT_MAX) {
+		/*
+		 * Bogus snapshot length; use the maximum for this
+		 * link-layer type as a fallback.
+		 *
+		 * XXX - we don't clamp snapshot lengths that are
+		 * <= INT_MAX but > max_snaplen_for_dlt(linktype),
+		 * so a capture file could cause us to allocate
+		 * a Really Big Buffer.
+		 */
+		snaplen = max_snaplen_for_dlt(linktype);
+	}
+	return snaplen;
+}
+
+static pcap_t *(*check_headers[])(const uint8_t *, FILE *, u_int, char *, int *) = {
+	pcap_check_header,
+	pcap_ng_check_header
+};
+
+#define	N_FILE_TYPES	(sizeof check_headers / sizeof check_headers[0])
+
+#ifdef _WIN32
+static
+#endif
+pcap_t *
+pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
+    char *errbuf)
+{
+	register pcap_t *p;
+	uint8_t magic[4];
+	size_t amt_read;
+	u_int i;
+	int err;
+
+	/*
+	 * Fail if we were passed a NULL fp.
+	 *
+	 * That shouldn't happen if we're opening with a path name, but
+	 * it could happen if buggy code is opening with a FILE * and
+	 * didn't bother to make sure the FILE * isn't null.
+	 */
+	if (fp == NULL) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "Null FILE * pointer provided to savefile open routine");
+		return (NULL);
+	}
+
+	/*
+	 * Read the first 4 bytes of the file; the network analyzer dump
+	 * file formats we support (pcap and pcapng), and several other
+	 * formats we might support in the future (such as snoop, DOS and
+	 * Windows Sniffer, and Microsoft Network Monitor) all have magic
+	 * numbers that are unique in their first 4 bytes.
+	 */
+	amt_read = fread(&magic, 1, sizeof(magic), fp);
+	if (amt_read != sizeof(magic)) {
+		if (ferror(fp)) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "error reading dump file");
+		} else {
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "truncated dump file; tried to read %zu file header bytes, only got %zu",
+			    sizeof(magic), amt_read);
+		}
+		return (NULL);
+	}
+
+	/*
+	 * Try all file types.
+	 */
+	for (i = 0; i < N_FILE_TYPES; i++) {
+		p = (*check_headers[i])(magic, fp, precision, errbuf, &err);
+		if (p != NULL) {
+			/* Yup, that's it. */
+			goto found;
+		}
+		if (err) {
+			/*
+			 * Error trying to read the header.
+			 */
+			return (NULL);
+		}
+	}
+
+	/*
+	 * Well, who knows what this mess is....
+	 */
+	snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
+	return (NULL);
+
+found:
+	p->rfile = fp;
+
+	/* Padding only needed for live capture fcode */
+	p->fddipad = 0;
+
+#if !defined(_WIN32) && !defined(MSDOS)
+	/*
+	 * You can do "select()" and "poll()" on plain files on most
+	 * platforms, and should be able to do so on pipes.
+	 *
+	 * You can't do "select()" on anything other than sockets in
+	 * Windows, so, on Win32 systems, we don't have "selectable_fd".
+	 */
+	p->selectable_fd = fileno(fp);
+#endif
+
+	p->read_op = pcap_offline_read;
+	p->inject_op = sf_inject;
+	p->setfilter_op = install_bpf_program;
+	p->setdirection_op = sf_setdirection;
+	p->set_datalink_op = NULL;	/* we don't support munging link-layer headers */
+	p->getnonblock_op = sf_getnonblock;
+	p->setnonblock_op = sf_setnonblock;
+	p->stats_op = sf_stats;
+#ifdef _WIN32
+	p->stats_ex_op = sf_stats_ex;
+	p->setbuff_op = sf_setbuff;
+	p->setmode_op = sf_setmode;
+	p->setmintocopy_op = sf_setmintocopy;
+	p->getevent_op = sf_getevent;
+	p->oid_get_request_op = sf_oid_get_request;
+	p->oid_set_request_op = sf_oid_set_request;
+	p->sendqueue_transmit_op = sf_sendqueue_transmit;
+	p->setuserbuffer_op = sf_setuserbuffer;
+	p->live_dump_op = sf_live_dump;
+	p->live_dump_ended_op = sf_live_dump_ended;
+	p->get_airpcap_handle_op = sf_get_airpcap_handle;
+#endif
+
+	/*
+	 * For offline captures, the standard one-shot callback can
+	 * be used for pcap_next()/pcap_next_ex().
+	 */
+	p->oneshot_callback = pcap_oneshot;
+
+	/*
+	 * Default breakloop operation.
+	 */
+	p->breakloop_op = pcap_breakloop_common;
+
+	/*
+	 * Savefiles never require special BPF code generation.
+	 */
+	p->bpf_codegen_flags = 0;
+
+	p->activated = 1;
+
+	return (p);
+}
+
+/*
+ * This isn't needed on Windows; we #define pcap_fopen_offline() as
+ * a wrapper around pcap_hopen_offline(), and we don't call it from
+ * inside this file, so it's unused.
+ */
+#ifndef _WIN32
+pcap_t *
+pcap_fopen_offline(FILE *fp, char *errbuf)
+{
+	return (pcap_fopen_offline_with_tstamp_precision(fp,
+	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
+}
+#endif
+
+/*
+ * Read packets from a capture file, and call the callback for each
+ * packet.
+ * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
+ */
+int
+pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+	struct bpf_insn *fcode;
+	int status = 0;
+	int n = 0;
+	u_char *data;
+
+	while (status == 0) {
+		struct pcap_pkthdr h;
+
+		/*
+		 * 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.
+		 */
+		if (p->break_loop) {
+			if (n == 0) {
+				p->break_loop = 0;
+				return (-2);
+			} else
+				return (n);
+		}
+
+		status = p->next_packet_op(p, &h, &data);
+		if (status) {
+			if (status == 1)
+				return (0);
+			return (status);
+		}
+
+		if ((fcode = p->fcode.bf_insns) == NULL ||
+		    pcap_filter(fcode, data, h.len, h.caplen)) {
+			(*callback)(user, &h, data);
+			if (++n >= cnt && cnt > 0)
+				break;
+		}
+	}
+	/*XXX this breaks semantics tcpslice expects */
+	return (n);
+}
diff --git a/scanner.l b/scanner.l
new file mode 100644
index 0000000..06b9acc
--- /dev/null
+++ b/scanner.l
@@ -0,0 +1,596 @@
+%top {
+/* Must come first for _LARGE_FILE_API on AIX. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * Must come first to avoid warnings on Windows.
+ *
+ * Flex-generated scanners may only include <inttypes.h> if __STDC_VERSION__
+ * is defined with a value >= 199901, meaning "full C99", and MSVC may not
+ * define it with that value, because it isn't 100% C99-compliant, even
+ * though it has an <inttypes.h> capable of defining everything the Flex
+ * scanner needs.
+ *
+ * We, however, will include it if we know we have an MSVC version that has
+ * it; this means that we may define the INTn_MAX and UINTn_MAX values in
+ * scanner.c, and then include <stdint.h>, which may define them differently
+ * (same value, but different string of characters), causing compiler warnings.
+ *
+ * If we include it here, and they're defined, that'll prevent scanner.c
+ * from defining them.  So we include <pcap/pcap-inttypes.h>, to get
+ * <inttypes.h> if we have it.
+ */
+#include <pcap/pcap-inttypes.h>
+
+#include "diag-control.h"
+}
+
+/*
+ * We want a reentrant scanner.
+ */
+%option reentrant
+
+/*
+ * And we need to pass the compiler state to the scanner.
+ */
+%option extra-type="compiler_state_t *"
+
+/*
+ * We don't use input, so don't generate code for it.
+ */
+%option noinput
+
+/*
+ * We don't use unput, so don't generate code for it.
+ */
+%option nounput
+
+/*
+ * We don't read from the terminal.
+ */
+%option never-interactive
+
+/*
+ * We want to stop processing when we get to the end of the input.
+ */
+%option noyywrap
+
+/*
+ * We want to generate code that can be used by a reentrant parser
+ * generated by Bison or Berkeley YACC.
+ */
+%option bison-bridge
+
+%{
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <string.h>
+
+#include "pcap-int.h"
+
+#include "gencode.h"
+
+#include "grammar.h"
+
+/*
+ * Earlier versions of Flex don't declare these, so we declare them
+ * ourselves to squelch warnings.
+ */
+int pcap_get_column(yyscan_t);
+void pcap_set_column(int, yyscan_t);
+
+#ifdef INET6
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+/*
+ * To quote the MSDN page for getaddrinfo() at
+ *
+ *    https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
+ *
+ * "Support for getaddrinfo on Windows 2000 and older versions
+ * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
+ * later. To execute an application that uses this function on earlier
+ * versions of Windows, then you need to include the Ws2tcpip.h and
+ * Wspiapi.h files. When the Wspiapi.h include file is added, the
+ * getaddrinfo function is defined to the WspiapiGetAddrInfo inline
+ * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
+ * function is implemented in such a way that if the Ws2_32.dll or the
+ * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
+ * Preview for Windows 2000) does not include getaddrinfo, then a
+ * version of getaddrinfo is implemented inline based on code in the
+ * Wspiapi.h header file. This inline code will be used on older Windows
+ * platforms that do not natively support the getaddrinfo function."
+ *
+ * We use getaddrinfo(), so we include Wspiapi.h here.
+ */
+#include <wspiapi.h>
+#else /* _WIN32 */
+#include <sys/socket.h>	/* for "struct sockaddr" in "struct addrinfo" */
+#include <netdb.h>	/* for "struct addrinfo" */
+#endif /* _WIN32 */
+
+/* Workaround for AIX 4.3 */
+#if !defined(AI_NUMERICHOST)
+#define AI_NUMERICHOST 0x04
+#endif
+
+#endif /*INET6*/
+
+#include <pcap/namedb.h>
+#include "grammar.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+static int stou(char *, YYSTYPE *, compiler_state_t *);
+
+/*
+ * Disable diagnostics in the code generated by Flex.
+ */
+DIAG_OFF_FLEX
+
+%}
+
+N		([0-9]+|(0X|0x)[0-9A-Fa-f]+)
+B		([0-9A-Fa-f][0-9A-Fa-f]?)
+B2		([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])
+W		([0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?)
+
+%a 18400
+%o 21500
+%e 7600
+%k 4550
+%p 27600
+%n 2000
+
+V680		{W}:{W}:{W}:{W}:{W}:{W}:{W}:{W}
+
+V670		::{W}:{W}:{W}:{W}:{W}:{W}:{W}
+V671		{W}::{W}:{W}:{W}:{W}:{W}:{W}
+V672		{W}:{W}::{W}:{W}:{W}:{W}:{W}
+V673		{W}:{W}:{W}::{W}:{W}:{W}:{W}
+V674		{W}:{W}:{W}:{W}::{W}:{W}:{W}
+V675		{W}:{W}:{W}:{W}:{W}::{W}:{W}
+V676		{W}:{W}:{W}:{W}:{W}:{W}::{W}
+V677		{W}:{W}:{W}:{W}:{W}:{W}:{W}::
+
+V660		::{W}:{W}:{W}:{W}:{W}:{W}
+V661		{W}::{W}:{W}:{W}:{W}:{W}
+V662		{W}:{W}::{W}:{W}:{W}:{W}
+V663		{W}:{W}:{W}::{W}:{W}:{W}
+V664		{W}:{W}:{W}:{W}::{W}:{W}
+V665		{W}:{W}:{W}:{W}:{W}::{W}
+V666		{W}:{W}:{W}:{W}:{W}:{W}::
+
+V650		::{W}:{W}:{W}:{W}:{W}
+V651		{W}::{W}:{W}:{W}:{W}
+V652		{W}:{W}::{W}:{W}:{W}
+V653		{W}:{W}:{W}::{W}:{W}
+V654		{W}:{W}:{W}:{W}::{W}
+V655		{W}:{W}:{W}:{W}:{W}::
+
+V640		::{W}:{W}:{W}:{W}
+V641		{W}::{W}:{W}:{W}
+V642		{W}:{W}::{W}:{W}
+V643		{W}:{W}:{W}::{W}
+V644		{W}:{W}:{W}:{W}::
+
+V630		::{W}:{W}:{W}
+V631		{W}::{W}:{W}
+V632		{W}:{W}::{W}
+V633		{W}:{W}:{W}::
+
+V620		::{W}:{W}
+V621		{W}::{W}
+V622		{W}:{W}::
+
+V610		::{W}
+V611		{W}::
+
+V600		::
+
+V6604		{W}:{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+
+V6504		::{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6514		{W}::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6524		{W}:{W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6534		{W}:{W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6544		{W}:{W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
+V6554		{W}:{W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6404		::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6414		{W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6424		{W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6434		{W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
+V6444		{W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6304		::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6314		{W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6324		{W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
+V6334		{W}:{W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6204		::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6214		{W}::{W}:{N}\.{N}\.{N}\.{N}
+V6224		{W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6104		::{W}:{N}\.{N}\.{N}\.{N}
+V6114		{W}::{N}\.{N}\.{N}\.{N}
+
+V6004		::{N}\.{N}\.{N}\.{N}
+
+
+V6		({V680}|{V670}|{V671}|{V672}|{V673}|{V674}|{V675}|{V676}|{V677}|{V660}|{V661}|{V662}|{V663}|{V664}|{V665}|{V666}|{V650}|{V651}|{V652}|{V653}|{V654}|{V655}|{V640}|{V641}|{V642}|{V643}|{V644}|{V630}|{V631}|{V632}|{V633}|{V620}|{V621}|{V622}|{V610}|{V611}|{V600}|{V6604}|{V6504}|{V6514}|{V6524}|{V6534}|{V6544}|{V6554}|{V6404}|{V6414}|{V6424}|{V6434}|{V6444}|{V6304}|{V6314}|{V6324}|{V6334}|{V6204}|{V6214}|{V6224}|{V6104}|{V6114}|{V6004})
+
+MAC		({B}:{B}:{B}:{B}:{B}:{B}|{B}\-{B}\-{B}\-{B}\-{B}\-{B}|{B}\.{B}\.{B}\.{B}\.{B}\.{B}|{B2}\.{B2}\.{B2}|{B2}{3})
+
+
+
+%%
+dst		return DST;
+src		return SRC;
+
+link|ether|ppp|slip  return LINK;
+fddi|tr|wlan	return LINK;
+arp		return ARP;
+rarp		return RARP;
+ip		return IP;
+sctp		return SCTP;
+tcp		return TCP;
+udp		return UDP;
+icmp		return ICMP;
+igmp		return IGMP;
+igrp		return IGRP;
+pim		return PIM;
+vrrp		return VRRP;
+carp		return CARP;
+radio		return RADIO;
+
+ip6		return IPV6;
+icmp6		return ICMPV6;
+ah		return AH;
+esp		return ESP;
+
+atalk		return ATALK;
+aarp		return AARP;
+decnet		return DECNET;
+lat		return LAT;
+sca		return SCA;
+moprc		return MOPRC;
+mopdl		return MOPDL;
+
+iso		return ISO;
+esis		return ESIS;
+es-is		return ESIS;
+isis		return ISIS;
+is-is		return ISIS;
+l1              return L1;
+l2              return L2;
+iih             return IIH;
+lsp             return LSP;
+snp             return SNP;
+csnp            return CSNP;
+psnp            return PSNP;
+
+clnp		return CLNP;
+
+stp		return STP;
+
+ipx		return IPX;
+
+netbeui		return NETBEUI;
+
+host		return HOST;
+net		return NET;
+mask		return NETMASK;
+port		return PORT;
+portrange	return PORTRANGE;
+proto		return PROTO;
+protochain	return PROTOCHAIN;
+
+gateway		return GATEWAY;
+
+type		return TYPE;
+subtype		return SUBTYPE;
+direction|dir	return DIR;
+address1|addr1	return ADDR1;
+address2|addr2	return ADDR2;
+address3|addr3	return ADDR3;
+address4|addr4	return ADDR4;
+ra		return RA;
+ta		return TA;
+
+less		return LESS;
+greater		return GREATER;
+byte		return CBYTE;
+broadcast	return TK_BROADCAST;
+multicast	return TK_MULTICAST;
+
+and|"&&"	return AND;
+or|"||"		return OR;
+not		return '!';
+
+len|length	return LEN;
+inbound		return INBOUND;
+outbound	return OUTBOUND;
+
+ifindex		return IFINDEX;
+
+vlan		return VLAN;
+mpls		return MPLS;
+pppoed		return PPPOED;
+pppoes		return PPPOES;
+geneve		return GENEVE;
+
+lane		return LANE;
+llc		return LLC;
+metac		return METAC;
+bcc		return BCC;
+oam		return OAM;
+oamf4		return OAMF4;
+oamf4ec		return OAMF4EC;
+oamf4sc		return OAMF4SC;
+sc		return SC;
+ilmic		return ILMIC;
+vpi		return VPI;
+vci		return VCI;
+connectmsg	return CONNECTMSG;
+metaconnect	return METACONNECT;
+
+on|ifname	return PF_IFNAME;
+rset|ruleset	return PF_RSET;
+rnr|rulenum	return PF_RNR;
+srnr|subrulenum	return PF_SRNR;
+reason		return PF_REASON;
+action		return PF_ACTION;
+
+fisu		return FISU;
+lssu		return LSSU;
+lsu		return LSSU;
+msu		return MSU;
+hfisu		return HFISU;
+hlssu		return HLSSU;
+hmsu		return HMSU;
+sio		return SIO;
+opc		return OPC;
+dpc		return DPC;
+sls		return SLS;
+hsio		return HSIO;
+hopc		return HOPC;
+hdpc		return HDPC;
+hsls		return HSLS;
+
+[ \r\n\t]		;
+[+\-*/%:\[\]!<>()&|\^=]	return yytext[0];
+">="			return GEQ;
+"<="			return LEQ;
+"!="			return NEQ;
+"=="			return '=';
+"<<"			return LSH;
+">>"			return RSH;
+${B}			{ yylval->s = sdup(yyextra, yytext); return AID; }
+{MAC}			{ yylval->s = sdup(yyextra, yytext); return EID; }
+{N}			{ return stou(yytext, yylval, yyextra); }
+({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N})	{
+			yylval->s = sdup(yyextra, (char *)yytext); return HID; }
+{V6}			{
+#ifdef INET6
+			  struct addrinfo hints, *res;
+			  memset(&hints, 0, sizeof(hints));
+			  hints.ai_family = AF_INET6;
+			  hints.ai_flags = AI_NUMERICHOST;
+			  if (getaddrinfo(yytext, NULL, &hints, &res)) {
+				bpf_set_error(yyextra, "bogus IPv6 address %s", yytext);
+				yylval->s = NULL;
+			  } else {
+				freeaddrinfo(res);
+				yylval->s = sdup(yyextra, (char *)yytext);
+			  }
+#else
+			  bpf_set_error(yyextra, "IPv6 address %s not supported", yytext);
+			  yylval->s = NULL;
+#endif /*INET6*/
+			  return HID6;
+			}
+{B}:+({B}:+)+		{ bpf_set_error(yyextra, "bogus ethernet address %s", yytext); yylval->s = NULL; return EID; }
+icmptype		{ yylval->h = 0; return NUM; }
+icmpcode		{ yylval->h = 1; return NUM; }
+icmp-echoreply		{ yylval->h = 0; return NUM; }
+icmp-unreach		{ yylval->h = 3; return NUM; }
+icmp-sourcequench	{ yylval->h = 4; return NUM; }
+icmp-redirect		{ yylval->h = 5; return NUM; }
+icmp-echo		{ yylval->h = 8; return NUM; }
+icmp-routeradvert	{ yylval->h = 9; return NUM; }
+icmp-routersolicit	{ yylval->h = 10; return NUM; }
+icmp-timxceed		{ yylval->h = 11; return NUM; }
+icmp-paramprob		{ yylval->h = 12; return NUM; }
+icmp-tstamp		{ yylval->h = 13; return NUM; }
+icmp-tstampreply	{ yylval->h = 14; return NUM; }
+icmp-ireq		{ yylval->h = 15; return NUM; }
+icmp-ireqreply		{ yylval->h = 16; return NUM; }
+icmp-maskreq		{ yylval->h = 17; return NUM; }
+icmp-maskreply		{ yylval->h = 18; return NUM; }
+
+icmp6type       { yylval->h = 0; return NUM; }
+icmp6code       { yylval->h = 1; return NUM; }
+
+icmp6-destinationunreach	{ yylval->h = 1; return NUM; }
+icmp6-packettoobig		{ yylval->h = 2; return NUM; }
+icmp6-timeexceeded		{ yylval->h = 3; return NUM; }
+icmp6-parameterproblem		{ yylval->h = 4; return NUM; }
+icmp6-echo      { yylval->h = 128; return NUM; }
+icmp6-echoreply { yylval->h = 129; return NUM; }
+icmp6-multicastlistenerquery    { yylval->h = 130; return NUM; }
+icmp6-multicastlistenerreportv1 { yylval->h = 131; return NUM; }
+icmp6-multicastlistenerdone     { yylval->h = 132; return NUM; }
+icmp6-routersolicit   { yylval->h = 133; return NUM; }
+icmp6-routeradvert    { yylval->h = 134; return NUM; }
+icmp6-neighborsolicit { yylval->h = 135; return NUM; }
+icmp6-neighboradvert  { yylval->h = 136; return NUM; }
+icmp6-redirect    { yylval->h = 137; return NUM; }
+icmp6-routerrenum { yylval->h = 138; return NUM; }
+icmp6-nodeinformationquery      { yylval->h = 139; return NUM; }
+icmp6-nodeinformationresponse   { yylval->h = 140; return NUM; }
+icmp6-ineighbordiscoverysolicit { yylval->h = 141; return NUM; }
+icmp6-ineighbordiscoveryadvert  { yylval->h = 142; return NUM; }
+icmp6-multicastlistenerreportv2 { yylval->h = 143; return NUM; }
+icmp6-homeagentdiscoveryrequest { yylval->h = 144; return NUM; }
+icmp6-homeagentdiscoveryreply   { yylval->h = 145; return NUM; }
+icmp6-mobileprefixsolicit       { yylval->h = 146; return NUM; }
+icmp6-mobileprefixadvert        { yylval->h = 147; return NUM; }
+icmp6-certpathsolicit           { yylval->h = 148; return NUM; }
+icmp6-certpathadvert            { yylval->h = 149; return NUM; }
+icmp6-multicastrouteradvert     { yylval->h = 151; return NUM; }
+icmp6-multicastroutersolicit    { yylval->h = 152; return NUM; }
+icmp6-multicastrouterterm       { yylval->h = 153; return NUM; }
+
+tcpflags		{ yylval->h = 13; return NUM; }
+tcp-fin			{ yylval->h = 0x01; return NUM; }
+tcp-syn			{ yylval->h = 0x02; return NUM; }
+tcp-rst			{ yylval->h = 0x04; return NUM; }
+tcp-push		{ yylval->h = 0x08; return NUM; }
+tcp-ack			{ yylval->h = 0x10; return NUM; }
+tcp-urg			{ yylval->h = 0x20; return NUM; }
+tcp-ece			{ yylval->h = 0x40; return NUM; }
+tcp-cwr			{ yylval->h = 0x80; return NUM; }
+[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? {
+			 yylval->s = sdup(yyextra, (char *)yytext); return ID; }
+"\\"[^ !()\n\t]+	{ yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; }
+.			{ return LEX_ERROR; }
+%%
+
+/*
+ * Turn diagnostics back on, so we check the code that we've written.
+ */
+DIAG_ON_FLEX
+
+/*
+ * Convert string to 32-bit unsigned integer.  Just like atoi(), but checks for
+ * preceding 0x or 0 and uses hex or octal instead of decimal.
+ *
+ * On success, sets yylval->h to the value and returns NUM.
+ * On failure, sets the BPF error string and returns LEX_ERROR, to force
+ * the parse to stop.
+ */
+static int
+stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
+{
+	bpf_u_int32 n = 0;
+	unsigned int digit;
+	char *s = yytext_arg;
+
+	/*
+	 * yytext_arg is guaranteed either to be a string of decimal digits
+	 * or 0[xX] followed by a string of hex digits.
+	 */
+	if (*s == '0') {
+		if (s[1] == 'x' || s[1] == 'X') {
+			/*
+			 * Begins with 0x or 0X, so hex.
+			 * Guaranteed to be all hex digits following the
+			 * prefix, so anything that's not 0-9 or a-f is
+			 * A-F.
+			 */
+			s += 2;	/* skip the prefix */
+			while ((digit = *s++) != '\0') {
+				if (digit >= '0' && digit <= '9')
+					digit = digit - '0';
+				else if (digit >= 'a' && digit <= 'f')
+					digit = digit - 'a' + 10;
+				else
+					digit = digit - 'A' + 10;
+
+				/*
+				 * Check for overflow.
+				 */
+				if (n > 0xFFFFFFFU) {
+					/*
+					 * We have more than 28 bits of
+					 * number, and are about to
+					 * add 4 more; that won't fit
+					 * in 32 bits.
+					 */
+					bpf_set_error(yyextra_arg,
+					    "number %s overflows 32 bits",
+					    yytext_arg);
+					return LEX_ERROR;
+				}
+				n = (n << 4) + digit;
+			}
+		} else {
+			/*
+			 * Begins with 0, but not 0x or 0X, so octal.
+			 * Guaranteed to be all *decimal* digits following
+			 * the prefix, so we need to catch 8 and 9 and
+			 * report an error.
+			 */
+			s += 1;
+			while ((digit = *s++) != '\0') {
+				if (digit >= '0' && digit <= '7')
+					digit = digit - '0';
+				else {
+					bpf_set_error(yyextra_arg,
+					    "number %s contains non-octal digit",
+					    yytext_arg);
+					return LEX_ERROR;
+				}
+				if (n > 03777777777U) {
+					/*
+					 * We have more than 29 bits of
+					 * number, and are about to add
+					 * 3 more; that won't fit in
+					 * 32 bits.
+					 */
+					bpf_set_error(yyextra_arg,
+					    "number %s overflows 32 bits",
+					    yytext_arg);
+					return LEX_ERROR;
+				}
+				n = (n << 3) + digit;
+			}
+		}
+	} else {
+		/*
+		 * Decimal.
+		 */
+		while ((digit = *s++) != '\0') {
+			digit = digit - '0';
+#define CUTOFF_DEC	(0xFFFFFFFFU / 10U)
+#define CUTLIM_DEC	(0xFFFFFFFFU % 10U)
+			if (n > CUTOFF_DEC ||
+			    (n == CUTOFF_DEC && digit > CUTLIM_DEC)) {
+				bpf_set_error(yyextra_arg,
+				    "number %s overflows 32 bits",
+				    yytext_arg);
+				return LEX_ERROR;
+			}
+			n = (n * 10) + digit;
+		}
+	}
+
+	yylval_arg->h = n;
+	return NUM;
+}
diff --git a/sf-pcap.c b/sf-pcap.c
new file mode 100644
index 0000000..d8443e9
--- /dev/null
+++ b/sf-pcap.c
@@ -0,0 +1,1164 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcap.c - libpcap-file-format-specific code from savefile.c
+ *	Extraction/creation by Jeffrey Mogul, DECWRL
+ *	Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif /* _WIN32 */
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h> /* for INT_MAX */
+
+#include "pcap-int.h"
+
+#include "pcap-common.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "sf-pcap.h"
+
+/*
+ * Setting O_BINARY on DOS/Windows is a bit tricky
+ */
+#if defined(_WIN32)
+  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
+#elif defined(MSDOS)
+  #if defined(__HIGHC__)
+  #define SET_BINMODE(f)  setmode(f, O_BINARY)
+  #else
+  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
+  #endif
+#endif
+
+/*
+ * Standard libpcap format.
+ */
+#define TCPDUMP_MAGIC		0xa1b2c3d4
+
+/*
+ * Alexey Kuznetzov's modified libpcap format.
+ */
+#define KUZNETZOV_TCPDUMP_MAGIC	0xa1b2cd34
+
+/*
+ * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt>
+ * for another modified format.
+ */
+#define FMESQUITA_TCPDUMP_MAGIC	0xa1b234cd
+
+/*
+ * Navtel Communcations' format, with nanosecond timestamps,
+ * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>.
+ */
+#define NAVTEL_TCPDUMP_MAGIC	0xa12b3c4d
+
+/*
+ * Normal libpcap format, except for seconds/nanoseconds timestamps,
+ * as per a request by Ulf Lamping <ulf.lamping@web.de>
+ */
+#define NSEC_TCPDUMP_MAGIC	0xa1b23c4d
+
+/*
+ * Mechanism for storing information about a capture in the upper
+ * 6 bits of a linktype value in a capture file.
+ *
+ * LT_LINKTYPE_EXT(x) extracts the additional information.
+ *
+ * The rest of the bits are for a value describing the link-layer
+ * value.  LT_LINKTYPE(x) extracts that value.
+ */
+#define LT_LINKTYPE(x)		((x) & 0x03FFFFFF)
+#define LT_LINKTYPE_EXT(x)	((x) & 0xFC000000)
+
+static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap);
+
+#ifdef _WIN32
+/*
+ * This isn't exported on Windows, because it would only work if both
+ * libpcap and the code using it were using the same C runtime; otherwise they
+ * would be using different definitions of a FILE structure.
+ *
+ * Instead we define this as a macro in pcap/pcap.h that wraps the hopen
+ * version that we do export, passing it a raw OS HANDLE, as defined by the
+ * Win32 / Win64 ABI, obtained from the _fileno() and _get_osfhandle()
+ * functions of the appropriate CRT.
+ */
+static pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *f);
+#endif /* _WIN32 */
+
+/*
+ * Private data for reading pcap savefiles.
+ */
+typedef enum {
+	NOT_SWAPPED,
+	SWAPPED,
+	MAYBE_SWAPPED
+} swapped_type_t;
+
+typedef enum {
+	PASS_THROUGH,
+	SCALE_UP,
+	SCALE_DOWN
+} tstamp_scale_type_t;
+
+struct pcap_sf {
+	size_t hdrsize;
+	swapped_type_t lengths_swapped;
+	tstamp_scale_type_t scale_type;
+};
+
+/*
+ * Check whether this is a pcap savefile and, if it is, extract the
+ * relevant information from the header.
+ */
+pcap_t *
+pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
+		  int *err)
+{
+	bpf_u_int32 magic_int;
+	struct pcap_file_header hdr;
+	size_t amt_read;
+	pcap_t *p;
+	int swapped = 0;
+	struct pcap_sf *ps;
+
+	/*
+	 * Assume no read errors.
+	 */
+	*err = 0;
+
+	/*
+	 * Check whether the first 4 bytes of the file are the magic
+	 * number for a pcap savefile, or for a byte-swapped pcap
+	 * savefile.
+	 */
+	memcpy(&magic_int, magic, sizeof(magic_int));
+	if (magic_int != TCPDUMP_MAGIC &&
+	    magic_int != KUZNETZOV_TCPDUMP_MAGIC &&
+	    magic_int != NSEC_TCPDUMP_MAGIC) {
+		magic_int = SWAPLONG(magic_int);
+		if (magic_int != TCPDUMP_MAGIC &&
+		    magic_int != KUZNETZOV_TCPDUMP_MAGIC &&
+		    magic_int != NSEC_TCPDUMP_MAGIC)
+			return (NULL);	/* nope */
+		swapped = 1;
+	}
+
+	/*
+	 * They are.  Put the magic number in the header, and read
+	 * the rest of the header.
+	 */
+	hdr.magic = magic_int;
+	amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1,
+	    sizeof(hdr) - sizeof(hdr.magic), fp);
+	if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) {
+		if (ferror(fp)) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "error reading dump file");
+		} else {
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "truncated dump file; tried to read %zu file header bytes, only got %zu",
+			    sizeof(hdr), amt_read);
+		}
+		*err = 1;
+		return (NULL);
+	}
+
+	/*
+	 * If it's a byte-swapped capture file, byte-swap the header.
+	 */
+	if (swapped) {
+		hdr.version_major = SWAPSHORT(hdr.version_major);
+		hdr.version_minor = SWAPSHORT(hdr.version_minor);
+		hdr.thiszone = SWAPLONG(hdr.thiszone);
+		hdr.sigfigs = SWAPLONG(hdr.sigfigs);
+		hdr.snaplen = SWAPLONG(hdr.snaplen);
+		hdr.linktype = SWAPLONG(hdr.linktype);
+	}
+
+	if (hdr.version_major < PCAP_VERSION_MAJOR) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "archaic pcap savefile format");
+		*err = 1;
+		return (NULL);
+	}
+
+	/*
+	 * currently only versions 2.[0-4] are supported with
+	 * the exception of 543.0 for DG/UX tcpdump.
+	 */
+	if (! ((hdr.version_major == PCAP_VERSION_MAJOR &&
+		hdr.version_minor <= PCAP_VERSION_MINOR) ||
+	       (hdr.version_major == 543 &&
+		hdr.version_minor == 0))) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			 "unsupported pcap savefile version %u.%u",
+			 hdr.version_major, hdr.version_minor);
+		*err = 1;
+		return NULL;
+	}
+
+	/*
+	 * OK, this is a good pcap file.
+	 * Allocate a pcap_t for it.
+	 */
+	p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_sf);
+	if (p == NULL) {
+		/* Allocation failed. */
+		*err = 1;
+		return (NULL);
+	}
+	p->swapped = swapped;
+	p->version_major = hdr.version_major;
+	p->version_minor = hdr.version_minor;
+	p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
+	p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
+	p->snapshot = pcap_adjust_snapshot(p->linktype, hdr.snaplen);
+
+	p->next_packet_op = pcap_next_packet;
+
+	ps = p->priv;
+
+	p->opt.tstamp_precision = precision;
+
+	/*
+	 * Will we need to scale the timestamps to match what the
+	 * user wants?
+	 */
+	switch (precision) {
+
+	case PCAP_TSTAMP_PRECISION_MICRO:
+		if (magic_int == NSEC_TCPDUMP_MAGIC) {
+			/*
+			 * The file has nanoseconds, the user
+			 * wants microseconds; scale the
+			 * precision down.
+			 */
+			ps->scale_type = SCALE_DOWN;
+		} else {
+			/*
+			 * The file has microseconds, the
+			 * user wants microseconds; nothing to do.
+			 */
+			ps->scale_type = PASS_THROUGH;
+		}
+		break;
+
+	case PCAP_TSTAMP_PRECISION_NANO:
+		if (magic_int == NSEC_TCPDUMP_MAGIC) {
+			/*
+			 * The file has nanoseconds, the
+			 * user wants nanoseconds; nothing to do.
+			 */
+			ps->scale_type = PASS_THROUGH;
+		} else {
+			/*
+			 * The file has microseconds, the user
+			 * wants nanoseconds; scale the
+			 * precision up.
+			 */
+			ps->scale_type = SCALE_UP;
+		}
+		break;
+
+	default:
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "unknown time stamp resolution %u", precision);
+		free(p);
+		*err = 1;
+		return (NULL);
+	}
+
+	/*
+	 * We interchanged the caplen and len fields at version 2.3,
+	 * in order to match the bpf header layout.  But unfortunately
+	 * some files were written with version 2.3 in their headers
+	 * but without the interchanged fields.
+	 *
+	 * In addition, DG/UX tcpdump writes out files with a version
+	 * number of 543.0, and with the caplen and len fields in the
+	 * pre-2.3 order.
+	 */
+	switch (hdr.version_major) {
+
+	case 2:
+		if (hdr.version_minor < 3)
+			ps->lengths_swapped = SWAPPED;
+		else if (hdr.version_minor == 3)
+			ps->lengths_swapped = MAYBE_SWAPPED;
+		else
+			ps->lengths_swapped = NOT_SWAPPED;
+		break;
+
+	case 543:
+		ps->lengths_swapped = SWAPPED;
+		break;
+
+	default:
+		ps->lengths_swapped = NOT_SWAPPED;
+		break;
+	}
+
+	if (magic_int == KUZNETZOV_TCPDUMP_MAGIC) {
+		/*
+		 * XXX - the patch that's in some versions of libpcap
+		 * changes the packet header but not the magic number,
+		 * and some other versions with this magic number have
+		 * some extra debugging information in the packet header;
+		 * we'd have to use some hacks^H^H^H^H^Hheuristics to
+		 * detect those variants.
+		 *
+		 * Ethereal does that, but it does so by trying to read
+		 * the first two packets of the file with each of the
+		 * record header formats.  That currently means it seeks
+		 * backwards and retries the reads, which doesn't work
+		 * on pipes.  We want to be able to read from a pipe, so
+		 * that strategy won't work; we'd have to buffer some
+		 * data ourselves and read from that buffer in order to
+		 * make that work.
+		 */
+		ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr);
+
+		if (p->linktype == DLT_EN10MB) {
+			/*
+			 * This capture might have been done in raw mode
+			 * or cooked mode.
+			 *
+			 * If it was done in cooked mode, p->snapshot was
+			 * passed to recvfrom() as the buffer size, meaning
+			 * that the most packet data that would be copied
+			 * would be p->snapshot.  However, a faked Ethernet
+			 * header would then have been added to it, so the
+			 * most data that would be in a packet in the file
+			 * would be p->snapshot + 14.
+			 *
+			 * We can't easily tell whether the capture was done
+			 * in raw mode or cooked mode, so we'll assume it was
+			 * cooked mode, and add 14 to the snapshot length.
+			 * That means that, for a raw capture, the snapshot
+			 * length will be misleading if you use it to figure
+			 * out why a capture doesn't have all the packet data,
+			 * but there's not much we can do to avoid that.
+			 *
+			 * But don't grow the snapshot length past the
+			 * maximum value of an int.
+			 */
+			if (p->snapshot <= INT_MAX - 14)
+				p->snapshot += 14;
+			else
+				p->snapshot = INT_MAX;
+		}
+	} else
+		ps->hdrsize = sizeof(struct pcap_sf_pkthdr);
+
+	/*
+	 * Allocate a buffer for the packet data.
+	 * Choose the minimum of the file's snapshot length and 2K bytes;
+	 * that should be enough for most network packets - we'll grow it
+	 * if necessary.  That way, we don't allocate a huge chunk of
+	 * memory just because there's a huge snapshot length, as the
+	 * snapshot length might be larger than the size of the largest
+	 * packet.
+	 */
+	p->bufsize = p->snapshot;
+	if (p->bufsize > 2048)
+		p->bufsize = 2048;
+	p->buffer = malloc(p->bufsize);
+	if (p->buffer == NULL) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+		free(p);
+		*err = 1;
+		return (NULL);
+	}
+
+	p->cleanup_op = sf_cleanup;
+
+	return (p);
+}
+
+/*
+ * Grow the packet buffer to the specified size.
+ */
+static int
+grow_buffer(pcap_t *p, u_int bufsize)
+{
+	void *bigger_buffer;
+
+	bigger_buffer = realloc(p->buffer, bufsize);
+	if (bigger_buffer == NULL) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+		return (0);
+	}
+	p->buffer = bigger_buffer;
+	p->bufsize = bufsize;
+	return (1);
+}
+
+/*
+ * Read and return the next packet from the savefile.  Return the header
+ * in hdr and a pointer to the contents in data.  Return 0 on success, 1
+ * if there were no more packets, and -1 on an error.
+ */
+static int
+pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
+{
+	struct pcap_sf *ps = p->priv;
+	struct pcap_sf_patched_pkthdr sf_hdr;
+	FILE *fp = p->rfile;
+	size_t amt_read;
+	bpf_u_int32 t;
+
+	/*
+	 * Read the packet header; the structure we use as a buffer
+	 * is the longer structure for files generated by the patched
+	 * libpcap, but if the file has the magic number for an
+	 * unpatched libpcap we only read as many bytes as the regular
+	 * header has.
+	 */
+	amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp);
+	if (amt_read != ps->hdrsize) {
+		if (ferror(fp)) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "error reading dump file");
+			return (-1);
+		} else {
+			if (amt_read != 0) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "truncated dump file; tried to read %zu header bytes, only got %zu",
+				    ps->hdrsize, amt_read);
+				return (-1);
+			}
+			/* EOF */
+			return (1);
+		}
+	}
+
+	if (p->swapped) {
+		/* these were written in opposite byte order */
+		hdr->caplen = SWAPLONG(sf_hdr.caplen);
+		hdr->len = SWAPLONG(sf_hdr.len);
+		hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
+		hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
+	} else {
+		hdr->caplen = sf_hdr.caplen;
+		hdr->len = sf_hdr.len;
+		hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
+		hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
+	}
+
+	switch (ps->scale_type) {
+
+	case PASS_THROUGH:
+		/*
+		 * Just pass the time stamp through.
+		 */
+		break;
+
+	case SCALE_UP:
+		/*
+		 * File has microseconds, user wants nanoseconds; convert
+		 * it.
+		 */
+		hdr->ts.tv_usec = hdr->ts.tv_usec * 1000;
+		break;
+
+	case SCALE_DOWN:
+		/*
+		 * File has nanoseconds, user wants microseconds; convert
+		 * it.
+		 */
+		hdr->ts.tv_usec = hdr->ts.tv_usec / 1000;
+		break;
+	}
+
+	/* Swap the caplen and len fields, if necessary. */
+	switch (ps->lengths_swapped) {
+
+	case NOT_SWAPPED:
+		break;
+
+	case MAYBE_SWAPPED:
+		if (hdr->caplen <= hdr->len) {
+			/*
+			 * The captured length is <= the actual length,
+			 * so presumably they weren't swapped.
+			 */
+			break;
+		}
+		/* FALLTHROUGH */
+
+	case SWAPPED:
+		t = hdr->caplen;
+		hdr->caplen = hdr->len;
+		hdr->len = t;
+		break;
+	}
+
+	/*
+	 * Is the packet bigger than we consider sane?
+	 */
+	if (hdr->caplen > max_snaplen_for_dlt(p->linktype)) {
+		/*
+		 * Yes.  This may be a damaged or fuzzed file.
+		 *
+		 * Is it bigger than the snapshot length?
+		 * (We don't treat that as an error if it's not
+		 * bigger than the maximum we consider sane; see
+		 * below.)
+		 */
+		if (hdr->caplen > (bpf_u_int32)p->snapshot) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "invalid packet capture length %u, bigger than "
+			    "snaplen of %d", hdr->caplen, p->snapshot);
+		} else {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "invalid packet capture length %u, bigger than "
+			    "maximum of %u", hdr->caplen,
+			    max_snaplen_for_dlt(p->linktype));
+		}
+		return (-1);
+	}
+
+	if (hdr->caplen > (bpf_u_int32)p->snapshot) {
+		/*
+		 * The packet is bigger than the snapshot length
+		 * for this file.
+		 *
+		 * This can happen due to Solaris 2.3 systems tripping
+		 * over the BUFMOD problem and not setting the snapshot
+		 * length correctly in the savefile header.
+		 *
+		 * libpcap 0.4 and later on Solaris 2.3 should set the
+		 * snapshot length correctly in the pcap file header,
+		 * even though they don't set a snapshot length in bufmod
+		 * (the buggy bufmod chops off the *beginning* of the
+		 * packet if a snapshot length is specified); they should
+		 * also reduce the captured length, as supplied to the
+		 * per-packet callback, to the snapshot length if it's
+		 * greater than the snapshot length, so the code using
+		 * libpcap should see the packet cut off at the snapshot
+		 * length, even though the full packet is copied up to
+		 * userland.
+		 *
+		 * However, perhaps some versions of libpcap failed to
+		 * set the snapshot length currectly in the file header
+		 * or the per-packet header, or perhaps this is a
+		 * corrupted safefile or a savefile built/modified by a
+		 * fuzz tester, so we check anyway.  We grow the buffer
+		 * to be big enough for the snapshot length, read up
+		 * to the snapshot length, discard the rest of the
+		 * packet, and report the snapshot length as the captured
+		 * length; we don't want to hand our caller a packet
+		 * bigger than the snapshot length, because they might
+		 * be assuming they'll never be handed such a packet,
+		 * and might copy the packet into a snapshot-length-
+		 * sized buffer, assuming it'll fit.
+		 */
+		size_t bytes_to_discard;
+		size_t bytes_to_read, bytes_read;
+		char discard_buf[4096];
+
+		if (hdr->caplen > p->bufsize) {
+			/*
+			 * Grow the buffer to the snapshot length.
+			 */
+			if (!grow_buffer(p, p->snapshot))
+				return (-1);
+		}
+
+		/*
+		 * Read the first p->snapshot bytes into the buffer.
+		 */
+		amt_read = fread(p->buffer, 1, p->snapshot, fp);
+		if (amt_read != (bpf_u_int32)p->snapshot) {
+			if (ferror(fp)) {
+				pcap_fmt_errmsg_for_errno(p->errbuf,
+				     PCAP_ERRBUF_SIZE, errno,
+				    "error reading dump file");
+			} else {
+				/*
+				 * Yes, this uses hdr->caplen; technically,
+				 * it's true, because we would try to read
+				 * and discard the rest of those bytes, and
+				 * that would fail because we got EOF before
+				 * the read finished.
+				 */
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "truncated dump file; tried to read %u captured bytes, only got %zu",
+				    p->snapshot, amt_read);
+			}
+			return (-1);
+		}
+
+		/*
+		 * Now read and discard what's left.
+		 */
+		bytes_to_discard = hdr->caplen - p->snapshot;
+		bytes_read = amt_read;
+		while (bytes_to_discard != 0) {
+			bytes_to_read = bytes_to_discard;
+			if (bytes_to_read > sizeof (discard_buf))
+				bytes_to_read = sizeof (discard_buf);
+			amt_read = fread(discard_buf, 1, bytes_to_read, fp);
+			bytes_read += amt_read;
+			if (amt_read != bytes_to_read) {
+				if (ferror(fp)) {
+					pcap_fmt_errmsg_for_errno(p->errbuf,
+					    PCAP_ERRBUF_SIZE, errno,
+					    "error reading dump file");
+				} else {
+					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+					    "truncated dump file; tried to read %u captured bytes, only got %zu",
+					    hdr->caplen, bytes_read);
+				}
+				return (-1);
+			}
+			bytes_to_discard -= amt_read;
+		}
+
+		/*
+		 * Adjust caplen accordingly, so we don't get confused later
+		 * as to how many bytes we have to play with.
+		 */
+		hdr->caplen = p->snapshot;
+	} else {
+		/*
+		 * The packet is within the snapshot length for this file.
+		 */
+		if (hdr->caplen > p->bufsize) {
+			/*
+			 * Grow the buffer to the next power of 2, or
+			 * the snaplen, whichever is lower.
+			 */
+			u_int new_bufsize;
+
+			new_bufsize = hdr->caplen;
+			/*
+			 * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+			 */
+			new_bufsize--;
+			new_bufsize |= new_bufsize >> 1;
+			new_bufsize |= new_bufsize >> 2;
+			new_bufsize |= new_bufsize >> 4;
+			new_bufsize |= new_bufsize >> 8;
+			new_bufsize |= new_bufsize >> 16;
+			new_bufsize++;
+
+			if (new_bufsize > (u_int)p->snapshot)
+				new_bufsize = p->snapshot;
+
+			if (!grow_buffer(p, new_bufsize))
+				return (-1);
+		}
+
+		/* read the packet itself */
+		amt_read = fread(p->buffer, 1, hdr->caplen, fp);
+		if (amt_read != hdr->caplen) {
+			if (ferror(fp)) {
+				pcap_fmt_errmsg_for_errno(p->errbuf,
+				    PCAP_ERRBUF_SIZE, errno,
+				    "error reading dump file");
+			} else {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "truncated dump file; tried to read %u captured bytes, only got %zu",
+				    hdr->caplen, amt_read);
+			}
+			return (-1);
+		}
+	}
+	*data = p->buffer;
+
+	if (p->swapped)
+		swap_pseudo_headers(p->linktype, hdr, *data);
+
+	return (0);
+}
+
+static int
+sf_write_header(pcap_t *p, FILE *fp, int linktype, int snaplen)
+{
+	struct pcap_file_header hdr;
+
+	hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC;
+	hdr.version_major = PCAP_VERSION_MAJOR;
+	hdr.version_minor = PCAP_VERSION_MINOR;
+
+	/*
+	 * https://www.tcpdump.org/manpages/pcap-savefile.5.txt states:
+	 * thiszone: 4-byte time zone offset; this is always 0.
+	 * sigfigs:  4-byte number giving the accuracy of time stamps
+	 *           in the file; this is always 0.
+	 */
+	hdr.thiszone = 0;
+	hdr.sigfigs = 0;
+	hdr.snaplen = snaplen;
+	hdr.linktype = linktype;
+
+	if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * Output a packet to the initialized dump file.
+ */
+void
+pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
+{
+	register FILE *f;
+	struct pcap_sf_pkthdr sf_hdr;
+
+	f = (FILE *)user;
+	/*
+	 * Better not try writing pcap files after
+	 * 2038-01-19 03:14:07 UTC; switch to pcapng.
+	 */
+	sf_hdr.ts.tv_sec  = (bpf_int32)h->ts.tv_sec;
+	sf_hdr.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
+	sf_hdr.caplen     = h->caplen;
+	sf_hdr.len        = h->len;
+	/* XXX we should check the return status */
+	(void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
+	(void)fwrite(sp, h->caplen, 1, f);
+}
+
+static pcap_dumper_t *
+pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
+{
+
+#if defined(_WIN32) || defined(MSDOS)
+	/*
+	 * If we're writing to the standard output, put it in binary
+	 * mode, as savefiles are binary files.
+	 *
+	 * Otherwise, we turn off buffering.
+	 * XXX - why?  And why not on the standard output?
+	 */
+	if (f == stdout)
+		SET_BINMODE(f);
+	else
+		setvbuf(f, NULL, _IONBF, 0);
+#endif
+	if (sf_write_header(p, f, linktype, p->snapshot) == -1) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "Can't write to %s", fname);
+		if (f != stdout)
+			(void)fclose(f);
+		return (NULL);
+	}
+	return ((pcap_dumper_t *)f);
+}
+
+/*
+ * Initialize so that sf_write() will output to the file named 'fname'.
+ */
+pcap_dumper_t *
+pcap_dump_open(pcap_t *p, const char *fname)
+{
+	FILE *f;
+	int linktype;
+
+	/*
+	 * If this pcap_t hasn't been activated, it doesn't have a
+	 * link-layer type, so we can't use it.
+	 */
+	if (!p->activated) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "%s: not-yet-activated pcap_t passed to pcap_dump_open",
+		    fname);
+		return (NULL);
+	}
+	linktype = dlt_to_linktype(p->linktype);
+	if (linktype == -1) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "%s: link-layer type %d isn't supported in savefiles",
+		    fname, p->linktype);
+		return (NULL);
+	}
+	linktype |= p->linktype_ext;
+
+	if (fname == NULL) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "A null pointer was supplied as the file name");
+		return NULL;
+	}
+	if (fname[0] == '-' && fname[1] == '\0') {
+		f = stdout;
+		fname = "standard output";
+	} else {
+		/*
+		 * "b" is supported as of C90, so *all* UN*Xes should
+		 * support it, even though it does nothing.  It's
+		 * required on Windows, as the file is a binary file
+		 * and must be written in binary mode.
+		 */
+		f = charset_fopen(fname, "wb");
+		if (f == NULL) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "%s", fname);
+			return (NULL);
+		}
+	}
+	return (pcap_setup_dump(p, linktype, f, fname));
+}
+
+#ifdef _WIN32
+/*
+ * Initialize so that sf_write() will output to a stream wrapping the given raw
+ * OS file HANDLE.
+ */
+pcap_dumper_t *
+pcap_dump_hopen(pcap_t *p, intptr_t osfd)
+{
+	int fd;
+	FILE *file;
+
+	fd = _open_osfhandle(osfd, _O_APPEND);
+	if (fd < 0) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "_open_osfhandle");
+		return NULL;
+	}
+
+	file = _fdopen(fd, "wb");
+	if (file == NULL) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "_fdopen");
+		_close(fd);
+		return NULL;
+	}
+
+	return pcap_dump_fopen(p, file);
+}
+#endif /* _WIN32 */
+
+/*
+ * Initialize so that sf_write() will output to the given stream.
+ */
+#ifdef _WIN32
+static
+#endif /* _WIN32 */
+pcap_dumper_t *
+pcap_dump_fopen(pcap_t *p, FILE *f)
+{
+	int linktype;
+
+	linktype = dlt_to_linktype(p->linktype);
+	if (linktype == -1) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "stream: link-layer type %d isn't supported in savefiles",
+		    p->linktype);
+		return (NULL);
+	}
+	linktype |= p->linktype_ext;
+
+	return (pcap_setup_dump(p, linktype, f, "stream"));
+}
+
+pcap_dumper_t *
+pcap_dump_open_append(pcap_t *p, const char *fname)
+{
+	FILE *f;
+	int linktype;
+	size_t amt_read;
+	struct pcap_file_header ph;
+
+	linktype = dlt_to_linktype(p->linktype);
+	if (linktype == -1) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "%s: link-layer type %d isn't supported in savefiles",
+		    fname, linktype);
+		return (NULL);
+	}
+
+	if (fname == NULL) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "A null pointer was supplied as the file name");
+		return NULL;
+	}
+	if (fname[0] == '-' && fname[1] == '\0')
+		return (pcap_setup_dump(p, linktype, stdout, "standard output"));
+
+	/*
+	 * "a" will cause the file *not* to be truncated if it exists
+	 * but will cause it to be created if it doesn't.  It will
+	 * also cause all writes to be done at the end of the file,
+	 * but will allow reads to be done anywhere in the file.  This
+	 * is what we need, because we need to read from the beginning
+	 * of the file to see if it already has a header and packets
+	 * or if it doesn't.
+	 *
+	 * "b" is supported as of C90, so *all* UN*Xes should support it,
+	 * even though it does nothing.  It's required on Windows, as the
+	 * file is a binary file and must be read in binary mode.
+	 */
+	f = charset_fopen(fname, "ab+");
+	if (f == NULL) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "%s", fname);
+		return (NULL);
+	}
+
+	/*
+	 * Try to read a pcap header.
+	 *
+	 * We do not assume that the file will be positioned at the
+	 * beginning immediately after we've opened it - we seek to
+	 * the beginning.  ISO C says it's implementation-defined
+	 * whether the file position indicator is at the beginning
+	 * or the end of the file after an append-mode open, and
+	 * it wasn't obvious from the Single UNIX Specification
+	 * or the Microsoft documentation how that works on SUS-
+	 * compliant systems or on Windows.
+	 */
+	if (fseek(f, 0, SEEK_SET) == -1) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "Can't seek to the beginning of %s", fname);
+		(void)fclose(f);
+		return (NULL);
+	}
+	amt_read = fread(&ph, 1, sizeof (ph), f);
+	if (amt_read != sizeof (ph)) {
+		if (ferror(f)) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "%s", fname);
+			(void)fclose(f);
+			return (NULL);
+		} else if (feof(f) && amt_read > 0) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: truncated pcap file header", fname);
+			(void)fclose(f);
+			return (NULL);
+		}
+	}
+
+#if defined(_WIN32) || defined(MSDOS)
+	/*
+	 * We turn off buffering.
+	 * XXX - why?  And why not on the standard output?
+	 */
+	setvbuf(f, NULL, _IONBF, 0);
+#endif
+
+	/*
+	 * If a header is already present and:
+	 *
+	 *	it's not for a pcap file of the appropriate resolution
+	 *	and the right byte order for this machine;
+	 *
+	 *	the link-layer header types don't match;
+	 *
+	 *	the snapshot lengths don't match;
+	 *
+	 * return an error.
+	 */
+	if (amt_read > 0) {
+		/*
+		 * A header is already present.
+		 * Do the checks.
+		 */
+		switch (ph.magic) {
+
+		case TCPDUMP_MAGIC:
+			if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "%s: different time stamp precision, cannot append to file", fname);
+				(void)fclose(f);
+				return (NULL);
+			}
+			break;
+
+		case NSEC_TCPDUMP_MAGIC:
+			if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "%s: different time stamp precision, cannot append to file", fname);
+				(void)fclose(f);
+				return (NULL);
+			}
+			break;
+
+		case SWAPLONG(TCPDUMP_MAGIC):
+		case SWAPLONG(NSEC_TCPDUMP_MAGIC):
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: different byte order, cannot append to file", fname);
+			(void)fclose(f);
+			return (NULL);
+
+		case KUZNETZOV_TCPDUMP_MAGIC:
+		case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC):
+		case NAVTEL_TCPDUMP_MAGIC:
+		case SWAPLONG(NAVTEL_TCPDUMP_MAGIC):
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: not a pcap file to which we can append", fname);
+			(void)fclose(f);
+			return (NULL);
+
+		default:
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: not a pcap file", fname);
+			(void)fclose(f);
+			return (NULL);
+		}
+
+		/*
+		 * Good version?
+		 */
+		if (ph.version_major != PCAP_VERSION_MAJOR ||
+		    ph.version_minor != PCAP_VERSION_MINOR) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: version is %u.%u, cannot append to file", fname,
+			    ph.version_major, ph.version_minor);
+			(void)fclose(f);
+			return (NULL);
+		}
+		if ((bpf_u_int32)linktype != ph.linktype) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: different linktype, cannot append to file", fname);
+			(void)fclose(f);
+			return (NULL);
+		}
+		if ((bpf_u_int32)p->snapshot != ph.snaplen) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "%s: different snaplen, cannot append to file", fname);
+			(void)fclose(f);
+			return (NULL);
+		}
+	} else {
+		/*
+		 * A header isn't present; attempt to write it.
+		 */
+		if (sf_write_header(p, f, linktype, p->snapshot) == -1) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "Can't write to %s", fname);
+			(void)fclose(f);
+			return (NULL);
+		}
+	}
+
+	/*
+	 * Start writing at the end of the file.
+	 *
+	 * XXX - this shouldn't be necessary, given that we're opening
+	 * the file in append mode, and ISO C specifies that all writes
+	 * are done at the end of the file in that mode.
+	 */
+	if (fseek(f, 0, SEEK_END) == -1) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "Can't seek to the end of %s", fname);
+		(void)fclose(f);
+		return (NULL);
+	}
+	return ((pcap_dumper_t *)f);
+}
+
+FILE *
+pcap_dump_file(pcap_dumper_t *p)
+{
+	return ((FILE *)p);
+}
+
+long
+pcap_dump_ftell(pcap_dumper_t *p)
+{
+	return (ftell((FILE *)p));
+}
+
+#if defined(HAVE_FSEEKO)
+/*
+ * We have fseeko(), so we have ftello().
+ * If we have large file support (files larger than 2^31-1 bytes),
+ * ftello() will give us a current file position with more than 32
+ * bits.
+ */
+int64_t
+pcap_dump_ftell64(pcap_dumper_t *p)
+{
+	return (ftello((FILE *)p));
+}
+#elif defined(_MSC_VER)
+/*
+ * We have Visual Studio; we support only 2005 and later, so we have
+ * _ftelli64().
+ */
+int64_t
+pcap_dump_ftell64(pcap_dumper_t *p)
+{
+	return (_ftelli64((FILE *)p));
+}
+#else
+/*
+ * We don't have ftello() or _ftelli64(), so fall back on ftell().
+ * Either long is 64 bits, in which case ftell() should suffice,
+ * or this is probably an older 32-bit UN*X without large file
+ * support, which means you'll probably get errors trying to
+ * write files > 2^31-1, so it won't matter anyway.
+ *
+ * XXX - what about MinGW?
+ */
+int64_t
+pcap_dump_ftell64(pcap_dumper_t *p)
+{
+	return (ftell((FILE *)p));
+}
+#endif
+
+int
+pcap_dump_flush(pcap_dumper_t *p)
+{
+
+	if (fflush((FILE *)p) == EOF)
+		return (-1);
+	else
+		return (0);
+}
+
+void
+pcap_dump_close(pcap_dumper_t *p)
+{
+
+#ifdef notyet
+	if (ferror((FILE *)p))
+		return-an-error;
+	/* XXX should check return from fclose() too */
+#endif
+	(void)fclose((FILE *)p);
+}
diff --git a/sf-pcap.h b/sf-pcap.h
new file mode 100644
index 0000000..bc7150f
--- /dev/null
+++ b/sf-pcap.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcap.h - libpcap-file-format-specific routines
+ *	Extraction/creation by Jeffrey Mogul, DECWRL
+ *	Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#ifndef sf_pcap_h
+#define	sf_pcap_h
+
+extern pcap_t *pcap_check_header(const uint8_t *magic, FILE *fp,
+    u_int precision, char *errbuf, int *err);
+
+#endif
diff --git a/sf-pcapng.c b/sf-pcapng.c
new file mode 100644
index 0000000..3fd366c
--- /dev/null
+++ b/sf-pcapng.c
@@ -0,0 +1,1518 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcapng.c - pcapng-file-format-specific code from savefile.c
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap/pcap-inttypes.h>
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcap-int.h"
+
+#include "pcap-common.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "sf-pcapng.h"
+
+/*
+ * Block types.
+ */
+
+/*
+ * Common part at the beginning of all blocks.
+ */
+struct block_header {
+	bpf_u_int32	block_type;
+	bpf_u_int32	total_length;
+};
+
+/*
+ * Common trailer at the end of all blocks.
+ */
+struct block_trailer {
+	bpf_u_int32	total_length;
+};
+
+/*
+ * Common options.
+ */
+#define OPT_ENDOFOPT	0	/* end of options */
+#define OPT_COMMENT	1	/* comment string */
+
+/*
+ * Option header.
+ */
+struct option_header {
+	u_short		option_code;
+	u_short		option_length;
+};
+
+/*
+ * Structures for the part of each block type following the common
+ * part.
+ */
+
+/*
+ * Section Header Block.
+ */
+#define BT_SHB			0x0A0D0D0A
+#define BT_SHB_INSANE_MAX       1024U*1024U*1U  /* 1MB should be enough */
+struct section_header_block {
+	bpf_u_int32	byte_order_magic;
+	u_short		major_version;
+	u_short		minor_version;
+	uint64_t	section_length;
+	/* followed by options and trailer */
+};
+
+/*
+ * Byte-order magic value.
+ */
+#define BYTE_ORDER_MAGIC	0x1A2B3C4D
+
+/*
+ * Current version number.  If major_version isn't PCAP_NG_VERSION_MAJOR,
+ * or if minor_version isn't PCAP_NG_VERSION_MINOR or 2, that means that
+ * this code can't read the file.
+ */
+#define PCAP_NG_VERSION_MAJOR	1
+#define PCAP_NG_VERSION_MINOR	0
+
+/*
+ * Interface Description Block.
+ */
+#define BT_IDB			0x00000001
+
+struct interface_description_block {
+	u_short		linktype;
+	u_short		reserved;
+	bpf_u_int32	snaplen;
+	/* followed by options and trailer */
+};
+
+/*
+ * Options in the IDB.
+ */
+#define IF_NAME		2	/* interface name string */
+#define IF_DESCRIPTION	3	/* interface description string */
+#define IF_IPV4ADDR	4	/* interface's IPv4 address and netmask */
+#define IF_IPV6ADDR	5	/* interface's IPv6 address and prefix length */
+#define IF_MACADDR	6	/* interface's MAC address */
+#define IF_EUIADDR	7	/* interface's EUI address */
+#define IF_SPEED	8	/* interface's speed, in bits/s */
+#define IF_TSRESOL	9	/* interface's time stamp resolution */
+#define IF_TZONE	10	/* interface's time zone */
+#define IF_FILTER	11	/* filter used when capturing on interface */
+#define IF_OS		12	/* string OS on which capture on this interface was done */
+#define IF_FCSLEN	13	/* FCS length for this interface */
+#define IF_TSOFFSET	14	/* time stamp offset for this interface */
+
+/*
+ * Enhanced Packet Block.
+ */
+#define BT_EPB			0x00000006
+
+struct enhanced_packet_block {
+	bpf_u_int32	interface_id;
+	bpf_u_int32	timestamp_high;
+	bpf_u_int32	timestamp_low;
+	bpf_u_int32	caplen;
+	bpf_u_int32	len;
+	/* followed by packet data, options, and trailer */
+};
+
+/*
+ * Simple Packet Block.
+ */
+#define BT_SPB			0x00000003
+
+struct simple_packet_block {
+	bpf_u_int32	len;
+	/* followed by packet data and trailer */
+};
+
+/*
+ * Packet Block.
+ */
+#define BT_PB			0x00000002
+
+struct packet_block {
+	u_short		interface_id;
+	u_short		drops_count;
+	bpf_u_int32	timestamp_high;
+	bpf_u_int32	timestamp_low;
+	bpf_u_int32	caplen;
+	bpf_u_int32	len;
+	/* followed by packet data, options, and trailer */
+};
+
+/*
+ * Block cursor - used when processing the contents of a block.
+ * Contains a pointer into the data being processed and a count
+ * of bytes remaining in the block.
+ */
+struct block_cursor {
+	u_char		*data;
+	size_t		data_remaining;
+	bpf_u_int32	block_type;
+};
+
+typedef enum {
+	PASS_THROUGH,
+	SCALE_UP_DEC,
+	SCALE_DOWN_DEC,
+	SCALE_UP_BIN,
+	SCALE_DOWN_BIN
+} tstamp_scale_type_t;
+
+/*
+ * Per-interface information.
+ */
+struct pcap_ng_if {
+	uint32_t snaplen;		/* snapshot length */
+	uint64_t tsresol;		/* time stamp resolution */
+	tstamp_scale_type_t scale_type;	/* how to scale */
+	uint64_t scale_factor;		/* time stamp scale factor for power-of-10 tsresol */
+	uint64_t tsoffset;		/* time stamp offset */
+};
+
+/*
+ * Per-pcap_t private data.
+ *
+ * max_blocksize is the maximum size of a block that we'll accept.  We
+ * reject blocks bigger than this, so we don't consume too much memory
+ * with a truly huge block.  It can change as we see IDBs with different
+ * link-layer header types.  (Currently, we don't support IDBs with
+ * different link-layer header types, but we will support it in the
+ * future, when we offer file-reading APIs that support it.)
+ *
+ * XXX - that's an issue on ILP32 platforms, where the maximum block
+ * size of 2^31-1 would eat all but one byte of the entire address space.
+ * It's less of an issue on ILP64/LLP64 platforms, but the actual size
+ * of the address space may be limited by 1) the number of *significant*
+ * address bits (currently, x86-64 only supports 48 bits of address), 2)
+ * any limitations imposed by the operating system; 3) any limitations
+ * imposed by the amount of available backing store for anonymous pages,
+ * so we impose a limit regardless of the size of a pointer.
+ */
+struct pcap_ng_sf {
+	uint64_t user_tsresol;		/* time stamp resolution requested by the user */
+	u_int max_blocksize;		/* don't grow buffer size past this */
+	bpf_u_int32 ifcount;		/* number of interfaces seen in this capture */
+	bpf_u_int32 ifaces_size;	/* size of array below */
+	struct pcap_ng_if *ifaces;	/* array of interface information */
+};
+
+/*
+ * The maximum block size we start with; we use an arbitrary value of
+ * 16 MiB.
+ */
+#define INITIAL_MAX_BLOCKSIZE	(16*1024*1024)
+
+/*
+ * Maximum block size for a given maximum snapshot length; we define it
+ * as the size of an EPB with a max_snaplen-sized packet and 128KB of
+ * options.
+ */
+#define MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen) \
+	(sizeof (struct block_header) + \
+	 sizeof (struct enhanced_packet_block) + \
+	 (max_snaplen) + 131072 + \
+	 sizeof (struct block_trailer))
+
+static void pcap_ng_cleanup(pcap_t *p);
+static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr,
+    u_char **data);
+
+static int
+read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof,
+    char *errbuf)
+{
+	size_t amt_read;
+
+	amt_read = fread(buf, 1, bytes_to_read, fp);
+	if (amt_read != bytes_to_read) {
+		if (ferror(fp)) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "error reading dump file");
+		} else {
+			if (amt_read == 0 && !fail_on_eof)
+				return (0);	/* EOF */
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "truncated pcapng dump file; tried to read %zu bytes, only got %zu",
+			    bytes_to_read, amt_read);
+		}
+		return (-1);
+	}
+	return (1);
+}
+
+static int
+read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
+{
+	struct pcap_ng_sf *ps;
+	int status;
+	struct block_header bhdr;
+	struct block_trailer *btrlr;
+	u_char *bdata;
+	size_t data_remaining;
+
+	ps = p->priv;
+
+	status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf);
+	if (status <= 0)
+		return (status);	/* error or EOF */
+
+	if (p->swapped) {
+		bhdr.block_type = SWAPLONG(bhdr.block_type);
+		bhdr.total_length = SWAPLONG(bhdr.total_length);
+	}
+
+	/*
+	 * Is this block "too small" - i.e., is it shorter than a block
+	 * header plus a block trailer?
+	 */
+	if (bhdr.total_length < sizeof(struct block_header) +
+	    sizeof(struct block_trailer)) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "block in pcapng dump file has a length of %u < %zu",
+		    bhdr.total_length,
+		    sizeof(struct block_header) + sizeof(struct block_trailer));
+		return (-1);
+	}
+
+	/*
+	 * Is the block total length a multiple of 4?
+	 */
+	if ((bhdr.total_length % 4) != 0) {
+		/*
+		 * No.  Report that as an error.
+		 */
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "block in pcapng dump file has a length of %u that is not a multiple of 4",
+		    bhdr.total_length);
+		return (-1);
+	}
+
+	/*
+	 * Is the buffer big enough?
+	 */
+	if (p->bufsize < bhdr.total_length) {
+		/*
+		 * No - make it big enough, unless it's too big, in
+		 * which case we fail.
+		 */
+		void *bigger_buffer;
+
+		if (bhdr.total_length > ps->max_blocksize) {
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length,
+			    ps->max_blocksize);
+			return (-1);
+		}
+		bigger_buffer = realloc(p->buffer, bhdr.total_length);
+		if (bigger_buffer == NULL) {
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+			return (-1);
+		}
+		p->buffer = bigger_buffer;
+	}
+
+	/*
+	 * Copy the stuff we've read to the buffer, and read the rest
+	 * of the block.
+	 */
+	memcpy(p->buffer, &bhdr, sizeof(bhdr));
+	bdata = (u_char *)p->buffer + sizeof(bhdr);
+	data_remaining = bhdr.total_length - sizeof(bhdr);
+	if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1)
+		return (-1);
+
+	/*
+	 * Get the block size from the trailer.
+	 */
+	btrlr = (struct block_trailer *)(bdata + data_remaining - sizeof (struct block_trailer));
+	if (p->swapped)
+		btrlr->total_length = SWAPLONG(btrlr->total_length);
+
+	/*
+	 * Is the total length from the trailer the same as the total
+	 * length from the header?
+	 */
+	if (bhdr.total_length != btrlr->total_length) {
+		/*
+		 * No.
+		 */
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "block total length in header and trailer don't match");
+		return (-1);
+	}
+
+	/*
+	 * Initialize the cursor.
+	 */
+	cursor->data = bdata;
+	cursor->data_remaining = data_remaining - sizeof(struct block_trailer);
+	cursor->block_type = bhdr.block_type;
+	return (1);
+}
+
+static void *
+get_from_block_data(struct block_cursor *cursor, size_t chunk_size,
+    char *errbuf)
+{
+	void *data;
+
+	/*
+	 * Make sure we have the specified amount of data remaining in
+	 * the block data.
+	 */
+	if (cursor->data_remaining < chunk_size) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "block of type %u in pcapng dump file is too short",
+		    cursor->block_type);
+		return (NULL);
+	}
+
+	/*
+	 * Return the current pointer, and skip past the chunk.
+	 */
+	data = cursor->data;
+	cursor->data += chunk_size;
+	cursor->data_remaining -= chunk_size;
+	return (data);
+}
+
+static struct option_header *
+get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf)
+{
+	struct option_header *opthdr;
+
+	opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf);
+	if (opthdr == NULL) {
+		/*
+		 * Option header is cut short.
+		 */
+		return (NULL);
+	}
+
+	/*
+	 * Byte-swap it if necessary.
+	 */
+	if (p->swapped) {
+		opthdr->option_code = SWAPSHORT(opthdr->option_code);
+		opthdr->option_length = SWAPSHORT(opthdr->option_length);
+	}
+
+	return (opthdr);
+}
+
+static void *
+get_optvalue_from_block_data(struct block_cursor *cursor,
+    struct option_header *opthdr, char *errbuf)
+{
+	size_t padded_option_len;
+	void *optvalue;
+
+	/* Pad option length to 4-byte boundary */
+	padded_option_len = opthdr->option_length;
+	padded_option_len = ((padded_option_len + 3)/4)*4;
+
+	optvalue = get_from_block_data(cursor, padded_option_len, errbuf);
+	if (optvalue == NULL) {
+		/*
+		 * Option value is cut short.
+		 */
+		return (NULL);
+	}
+
+	return (optvalue);
+}
+
+static int
+process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
+    uint64_t *tsoffset, int *is_binary, char *errbuf)
+{
+	struct option_header *opthdr;
+	void *optvalue;
+	int saw_tsresol, saw_tsoffset;
+	uint8_t tsresol_opt;
+	u_int i;
+
+	saw_tsresol = 0;
+	saw_tsoffset = 0;
+	while (cursor->data_remaining != 0) {
+		/*
+		 * Get the option header.
+		 */
+		opthdr = get_opthdr_from_block_data(p, cursor, errbuf);
+		if (opthdr == NULL) {
+			/*
+			 * Option header is cut short.
+			 */
+			return (-1);
+		}
+
+		/*
+		 * Get option value.
+		 */
+		optvalue = get_optvalue_from_block_data(cursor, opthdr,
+		    errbuf);
+		if (optvalue == NULL) {
+			/*
+			 * Option value is cut short.
+			 */
+			return (-1);
+		}
+
+		switch (opthdr->option_code) {
+
+		case OPT_ENDOFOPT:
+			if (opthdr->option_length != 0) {
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "Interface Description Block has opt_endofopt option with length %u != 0",
+				    opthdr->option_length);
+				return (-1);
+			}
+			goto done;
+
+		case IF_TSRESOL:
+			if (opthdr->option_length != 1) {
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "Interface Description Block has if_tsresol option with length %u != 1",
+				    opthdr->option_length);
+				return (-1);
+			}
+			if (saw_tsresol) {
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "Interface Description Block has more than one if_tsresol option");
+				return (-1);
+			}
+			saw_tsresol = 1;
+			memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt));
+			if (tsresol_opt & 0x80) {
+				/*
+				 * Resolution is negative power of 2.
+				 */
+				uint8_t tsresol_shift = (tsresol_opt & 0x7F);
+
+				if (tsresol_shift > 63) {
+					/*
+					 * Resolution is too high; 2^-{res}
+					 * won't fit in a 64-bit value.
+					 */
+					snprintf(errbuf, PCAP_ERRBUF_SIZE,
+					    "Interface Description Block if_tsresol option resolution 2^-%u is too high",
+					    tsresol_shift);
+					return (-1);
+				}
+				*is_binary = 1;
+				*tsresol = ((uint64_t)1) << tsresol_shift;
+			} else {
+				/*
+				 * Resolution is negative power of 10.
+				 */
+				if (tsresol_opt > 19) {
+					/*
+					 * Resolution is too high; 2^-{res}
+					 * won't fit in a 64-bit value (the
+					 * largest power of 10 that fits
+					 * in a 64-bit value is 10^19, as
+					 * the largest 64-bit unsigned
+					 * value is ~1.8*10^19).
+					 */
+					snprintf(errbuf, PCAP_ERRBUF_SIZE,
+					    "Interface Description Block if_tsresol option resolution 10^-%u is too high",
+					    tsresol_opt);
+					return (-1);
+				}
+				*is_binary = 0;
+				*tsresol = 1;
+				for (i = 0; i < tsresol_opt; i++)
+					*tsresol *= 10;
+			}
+			break;
+
+		case IF_TSOFFSET:
+			if (opthdr->option_length != 8) {
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "Interface Description Block has if_tsoffset option with length %u != 8",
+				    opthdr->option_length);
+				return (-1);
+			}
+			if (saw_tsoffset) {
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "Interface Description Block has more than one if_tsoffset option");
+				return (-1);
+			}
+			saw_tsoffset = 1;
+			memcpy(tsoffset, optvalue, sizeof(*tsoffset));
+			if (p->swapped)
+				*tsoffset = SWAPLL(*tsoffset);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+done:
+	return (0);
+}
+
+static int
+add_interface(pcap_t *p, struct interface_description_block *idbp,
+    struct block_cursor *cursor, char *errbuf)
+{
+	struct pcap_ng_sf *ps;
+	uint64_t tsresol;
+	uint64_t tsoffset;
+	int is_binary;
+
+	ps = p->priv;
+
+	/*
+	 * Count this interface.
+	 */
+	ps->ifcount++;
+
+	/*
+	 * Grow the array of per-interface information as necessary.
+	 */
+	if (ps->ifcount > ps->ifaces_size) {
+		/*
+		 * We need to grow the array.
+		 */
+		bpf_u_int32 new_ifaces_size;
+		struct pcap_ng_if *new_ifaces;
+
+		if (ps->ifaces_size == 0) {
+			/*
+			 * It's currently empty.
+			 *
+			 * (The Clang static analyzer doesn't do enough,
+			 * err, umm, dataflow *analysis* to realize that
+			 * ps->ifaces_size == 0 if ps->ifaces == NULL,
+			 * and so complains about a possible zero argument
+			 * to realloc(), so we check for the former
+			 * condition to shut it up.
+			 *
+			 * However, it doesn't complain that one of the
+			 * multiplications below could overflow, which is
+			 * a real, albeit extremely unlikely, problem (you'd
+			 * need a pcapng file with tens of millions of
+			 * interfaces).)
+			 */
+			new_ifaces_size = 1;
+			new_ifaces = malloc(sizeof (struct pcap_ng_if));
+		} else {
+			/*
+			 * It's not currently empty; double its size.
+			 * (Perhaps overkill once we have a lot of interfaces.)
+			 *
+			 * Check for overflow if we double it.
+			 */
+			if (ps->ifaces_size * 2 < ps->ifaces_size) {
+				/*
+				 * The maximum number of interfaces before
+				 * ps->ifaces_size overflows is the largest
+				 * possible 32-bit power of 2, as we do
+				 * size doubling.
+				 */
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "more than %u interfaces in the file",
+				    0x80000000U);
+				return (0);
+			}
+
+			/*
+			 * ps->ifaces_size * 2 doesn't overflow, so it's
+			 * safe to multiply.
+			 */
+			new_ifaces_size = ps->ifaces_size * 2;
+
+			/*
+			 * Now make sure that's not so big that it overflows
+			 * if we multiply by sizeof (struct pcap_ng_if).
+			 *
+			 * That can happen on 32-bit platforms, with a 32-bit
+			 * size_t; it shouldn't happen on 64-bit platforms,
+			 * with a 64-bit size_t, as new_ifaces_size is
+			 * 32 bits.
+			 */
+			if (new_ifaces_size * sizeof (struct pcap_ng_if) < new_ifaces_size) {
+				/*
+				 * As this fails only with 32-bit size_t,
+				 * the multiplication was 32x32->32, and
+				 * the largest 32-bit value that can safely
+				 * be multiplied by sizeof (struct pcap_ng_if)
+				 * without overflow is the largest 32-bit
+				 * (unsigned) value divided by
+				 * sizeof (struct pcap_ng_if).
+				 */
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				    "more than %u interfaces in the file",
+				    0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if)));
+				return (0);
+			}
+			new_ifaces = realloc(ps->ifaces, new_ifaces_size * sizeof (struct pcap_ng_if));
+		}
+		if (new_ifaces == NULL) {
+			/*
+			 * We ran out of memory.
+			 * Give up.
+			 */
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "out of memory for per-interface information (%u interfaces)",
+			    ps->ifcount);
+			return (0);
+		}
+		ps->ifaces_size = new_ifaces_size;
+		ps->ifaces = new_ifaces;
+	}
+
+	ps->ifaces[ps->ifcount - 1].snaplen = idbp->snaplen;
+
+	/*
+	 * Set the default time stamp resolution and offset.
+	 */
+	tsresol = 1000000;	/* microsecond resolution */
+	is_binary = 0;		/* which is a power of 10 */
+	tsoffset = 0;		/* absolute timestamps */
+
+	/*
+	 * Now look for various time stamp options, so we know
+	 * how to interpret the time stamps for this interface.
+	 */
+	if (process_idb_options(p, cursor, &tsresol, &tsoffset, &is_binary,
+	    errbuf) == -1)
+		return (0);
+
+	ps->ifaces[ps->ifcount - 1].tsresol = tsresol;
+	ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset;
+
+	/*
+	 * Determine whether we're scaling up or down or not
+	 * at all for this interface.
+	 */
+	if (tsresol == ps->user_tsresol) {
+		/*
+		 * The resolution is the resolution the user wants,
+		 * so we don't have to do scaling.
+		 */
+		ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH;
+	} else if (tsresol > ps->user_tsresol) {
+		/*
+		 * The resolution is greater than what the user wants,
+		 * so we have to scale the timestamps down.
+		 */
+		if (is_binary)
+			ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_BIN;
+		else {
+			/*
+			 * Calculate the scale factor.
+			 */
+			ps->ifaces[ps->ifcount - 1].scale_factor = tsresol/ps->user_tsresol;
+			ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_DEC;
+		}
+	} else {
+		/*
+		 * The resolution is less than what the user wants,
+		 * so we have to scale the timestamps up.
+		 */
+		if (is_binary)
+			ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_BIN;
+		else {
+			/*
+			 * Calculate the scale factor.
+			 */
+			ps->ifaces[ps->ifcount - 1].scale_factor = ps->user_tsresol/tsresol;
+			ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_DEC;
+		}
+	}
+	return (1);
+}
+
+/*
+ * Check whether this is a pcapng savefile and, if it is, extract the
+ * relevant information from the header.
+ */
+pcap_t *
+pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
+    char *errbuf, int *err)
+{
+	bpf_u_int32 magic_int;
+	size_t amt_read;
+	bpf_u_int32 total_length;
+	bpf_u_int32 byte_order_magic;
+	struct block_header *bhdrp;
+	struct section_header_block *shbp;
+	pcap_t *p;
+	int swapped = 0;
+	struct pcap_ng_sf *ps;
+	int status;
+	struct block_cursor cursor;
+	struct interface_description_block *idbp;
+
+	/*
+	 * Assume no read errors.
+	 */
+	*err = 0;
+
+	/*
+	 * Check whether the first 4 bytes of the file are the block
+	 * type for a pcapng savefile.
+	 */
+	memcpy(&magic_int, magic, sizeof(magic_int));
+	if (magic_int != BT_SHB) {
+		/*
+		 * XXX - check whether this looks like what the block
+		 * type would be after being munged by mapping between
+		 * UN*X and DOS/Windows text file format and, if it
+		 * does, look for the byte-order magic number in
+		 * the appropriate place and, if we find it, report
+		 * this as possibly being a pcapng file transferred
+		 * between UN*X and Windows in text file format?
+		 */
+		return (NULL);	/* nope */
+	}
+
+	/*
+	 * OK, they are.  However, that's just \n\r\r\n, so it could,
+	 * conceivably, be an ordinary text file.
+	 *
+	 * It could not, however, conceivably be any other type of
+	 * capture file, so we can read the rest of the putative
+	 * Section Header Block; put the block type in the common
+	 * header, read the rest of the common header and the
+	 * fixed-length portion of the SHB, and look for the byte-order
+	 * magic value.
+	 */
+	amt_read = fread(&total_length, 1, sizeof(total_length), fp);
+	if (amt_read < sizeof(total_length)) {
+		if (ferror(fp)) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "error reading dump file");
+			*err = 1;
+			return (NULL);	/* fail */
+		}
+
+		/*
+		 * Possibly a weird short text file, so just say
+		 * "not pcapng".
+		 */
+		return (NULL);
+	}
+	amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp);
+	if (amt_read < sizeof(byte_order_magic)) {
+		if (ferror(fp)) {
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "error reading dump file");
+			*err = 1;
+			return (NULL);	/* fail */
+		}
+
+		/*
+		 * Possibly a weird short text file, so just say
+		 * "not pcapng".
+		 */
+		return (NULL);
+	}
+	if (byte_order_magic != BYTE_ORDER_MAGIC) {
+		byte_order_magic = SWAPLONG(byte_order_magic);
+		if (byte_order_magic != BYTE_ORDER_MAGIC) {
+			/*
+			 * Not a pcapng file.
+			 */
+			return (NULL);
+		}
+		swapped = 1;
+		total_length = SWAPLONG(total_length);
+	}
+
+	/*
+	 * Check the sanity of the total length.
+	 */
+	if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) ||
+            (total_length > BT_SHB_INSANE_MAX)) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "Section Header Block in pcapng dump file has invalid length %zu < _%u_ < %u (BT_SHB_INSANE_MAX)",
+		    sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer),
+		    total_length,
+		    BT_SHB_INSANE_MAX);
+
+		*err = 1;
+		return (NULL);
+	}
+
+	/*
+	 * OK, this is a good pcapng file.
+	 * Allocate a pcap_t for it.
+	 */
+	p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_ng_sf);
+	if (p == NULL) {
+		/* Allocation failed. */
+		*err = 1;
+		return (NULL);
+	}
+	p->swapped = swapped;
+	ps = p->priv;
+
+	/*
+	 * What precision does the user want?
+	 */
+	switch (precision) {
+
+	case PCAP_TSTAMP_PRECISION_MICRO:
+		ps->user_tsresol = 1000000;
+		break;
+
+	case PCAP_TSTAMP_PRECISION_NANO:
+		ps->user_tsresol = 1000000000;
+		break;
+
+	default:
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "unknown time stamp resolution %u", precision);
+		free(p);
+		*err = 1;
+		return (NULL);
+	}
+
+	p->opt.tstamp_precision = precision;
+
+	/*
+	 * Allocate a buffer into which to read blocks.  We default to
+	 * the maximum of:
+	 *
+	 *	the total length of the SHB for which we read the header;
+	 *
+	 *	2K, which should be more than large enough for an Enhanced
+	 *	Packet Block containing a full-size Ethernet frame, and
+	 *	leaving room for some options.
+	 *
+	 * If we find a bigger block, we reallocate the buffer, up to
+	 * the maximum size.  We start out with a maximum size of
+	 * INITIAL_MAX_BLOCKSIZE; if we see any link-layer header types
+	 * with a maximum snapshot that results in a larger maximum
+	 * block length, we boost the maximum.
+	 */
+	p->bufsize = 2048;
+	if (p->bufsize < total_length)
+		p->bufsize = total_length;
+	p->buffer = malloc(p->bufsize);
+	if (p->buffer == NULL) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+		free(p);
+		*err = 1;
+		return (NULL);
+	}
+	ps->max_blocksize = INITIAL_MAX_BLOCKSIZE;
+
+	/*
+	 * Copy the stuff we've read to the buffer, and read the rest
+	 * of the SHB.
+	 */
+	bhdrp = (struct block_header *)p->buffer;
+	shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header));
+	bhdrp->block_type = magic_int;
+	bhdrp->total_length = total_length;
+	shbp->byte_order_magic = byte_order_magic;
+	if (read_bytes(fp,
+	    (u_char *)p->buffer + (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)),
+	    total_length - (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)),
+	    1, errbuf) == -1)
+		goto fail;
+
+	if (p->swapped) {
+		/*
+		 * Byte-swap the fields we've read.
+		 */
+		shbp->major_version = SWAPSHORT(shbp->major_version);
+		shbp->minor_version = SWAPSHORT(shbp->minor_version);
+
+		/*
+		 * XXX - we don't care about the section length.
+		 */
+	}
+	/* Currently only SHB versions 1.0 and 1.2 are supported;
+	   version 1.2 is treated as being the same as version 1.0.
+	   See the current version of the pcapng specification.
+
+	   Version 1.2 is written by some programs that write additional
+	   block types (which can be read by any code that handles them,
+	   regardless of whether the minor version if 0 or 2, so that's
+	   not a reason to change the minor version number).
+
+	   XXX - the pcapng specification says that readers should
+	   just ignore sections with an unsupported version number;
+	   presumably they can also report an error if they skip
+	   all the way to the end of the file without finding
+	   any versions that they support. */
+	if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR &&
+	       (shbp->minor_version == PCAP_NG_VERSION_MINOR ||
+	        shbp->minor_version == 2))) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "unsupported pcapng savefile version %u.%u",
+		    shbp->major_version, shbp->minor_version);
+		goto fail;
+	}
+	p->version_major = shbp->major_version;
+	p->version_minor = shbp->minor_version;
+
+	/*
+	 * Save the time stamp resolution the user requested.
+	 */
+	p->opt.tstamp_precision = precision;
+
+	/*
+	 * Now start looking for an Interface Description Block.
+	 */
+	for (;;) {
+		/*
+		 * Read the next block.
+		 */
+		status = read_block(fp, p, &cursor, errbuf);
+		if (status == 0) {
+			/* EOF - no IDB in this file */
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "the capture file has no Interface Description Blocks");
+			goto fail;
+		}
+		if (status == -1)
+			goto fail;	/* error */
+		switch (cursor.block_type) {
+
+		case BT_IDB:
+			/*
+			 * Get a pointer to the fixed-length portion of the
+			 * IDB.
+			 */
+			idbp = get_from_block_data(&cursor, sizeof(*idbp),
+			    errbuf);
+			if (idbp == NULL)
+				goto fail;	/* error */
+
+			/*
+			 * Byte-swap it if necessary.
+			 */
+			if (p->swapped) {
+				idbp->linktype = SWAPSHORT(idbp->linktype);
+				idbp->snaplen = SWAPLONG(idbp->snaplen);
+			}
+
+			/*
+			 * Try to add this interface.
+			 */
+			if (!add_interface(p, idbp, &cursor, errbuf))
+				goto fail;
+
+			goto done;
+
+		case BT_EPB:
+		case BT_SPB:
+		case BT_PB:
+			/*
+			 * Saw a packet before we saw any IDBs.  That's
+			 * not valid, as we don't know what link-layer
+			 * encapsulation the packet has.
+			 */
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "the capture file has a packet block before any Interface Description Blocks");
+			goto fail;
+
+		default:
+			/*
+			 * Just ignore it.
+			 */
+			break;
+		}
+	}
+
+done:
+	p->linktype = linktype_to_dlt(idbp->linktype);
+	p->snapshot = pcap_adjust_snapshot(p->linktype, idbp->snaplen);
+	p->linktype_ext = 0;
+
+	/*
+	 * If the maximum block size for a packet with the maximum
+	 * snapshot length for this DLT_ is bigger than the current
+	 * maximum block size, increase the maximum.
+	 */
+	if (MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize)
+		ps->max_blocksize = MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype));
+
+	p->next_packet_op = pcap_ng_next_packet;
+	p->cleanup_op = pcap_ng_cleanup;
+
+	return (p);
+
+fail:
+	free(ps->ifaces);
+	free(p->buffer);
+	free(p);
+	*err = 1;
+	return (NULL);
+}
+
+static void
+pcap_ng_cleanup(pcap_t *p)
+{
+	struct pcap_ng_sf *ps = p->priv;
+
+	free(ps->ifaces);
+	sf_cleanup(p);
+}
+
+/*
+ * Read and return the next packet from the savefile.  Return the header
+ * in hdr and a pointer to the contents in data.  Return 0 on success, 1
+ * if there were no more packets, and -1 on an error.
+ */
+static int
+pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
+{
+	struct pcap_ng_sf *ps = p->priv;
+	struct block_cursor cursor;
+	int status;
+	struct enhanced_packet_block *epbp;
+	struct simple_packet_block *spbp;
+	struct packet_block *pbp;
+	bpf_u_int32 interface_id = 0xFFFFFFFF;
+	struct interface_description_block *idbp;
+	struct section_header_block *shbp;
+	FILE *fp = p->rfile;
+	uint64_t t, sec, frac;
+
+	/*
+	 * Look for an Enhanced Packet Block, a Simple Packet Block,
+	 * or a Packet Block.
+	 */
+	for (;;) {
+		/*
+		 * Read the block type and length; those are common
+		 * to all blocks.
+		 */
+		status = read_block(fp, p, &cursor, p->errbuf);
+		if (status == 0)
+			return (1);	/* EOF */
+		if (status == -1)
+			return (-1);	/* error */
+		switch (cursor.block_type) {
+
+		case BT_EPB:
+			/*
+			 * Get a pointer to the fixed-length portion of the
+			 * EPB.
+			 */
+			epbp = get_from_block_data(&cursor, sizeof(*epbp),
+			    p->errbuf);
+			if (epbp == NULL)
+				return (-1);	/* error */
+
+			/*
+			 * Byte-swap it if necessary.
+			 */
+			if (p->swapped) {
+				/* these were written in opposite byte order */
+				interface_id = SWAPLONG(epbp->interface_id);
+				hdr->caplen = SWAPLONG(epbp->caplen);
+				hdr->len = SWAPLONG(epbp->len);
+				t = ((uint64_t)SWAPLONG(epbp->timestamp_high)) << 32 |
+				    SWAPLONG(epbp->timestamp_low);
+			} else {
+				interface_id = epbp->interface_id;
+				hdr->caplen = epbp->caplen;
+				hdr->len = epbp->len;
+				t = ((uint64_t)epbp->timestamp_high) << 32 |
+				    epbp->timestamp_low;
+			}
+			goto found;
+
+		case BT_SPB:
+			/*
+			 * Get a pointer to the fixed-length portion of the
+			 * SPB.
+			 */
+			spbp = get_from_block_data(&cursor, sizeof(*spbp),
+			    p->errbuf);
+			if (spbp == NULL)
+				return (-1);	/* error */
+
+			/*
+			 * SPB packets are assumed to have arrived on
+			 * the first interface.
+			 */
+			interface_id = 0;
+
+			/*
+			 * Byte-swap it if necessary.
+			 */
+			if (p->swapped) {
+				/* these were written in opposite byte order */
+				hdr->len = SWAPLONG(spbp->len);
+			} else
+				hdr->len = spbp->len;
+
+			/*
+			 * The SPB doesn't give the captured length;
+			 * it's the minimum of the snapshot length
+			 * and the packet length.
+			 */
+			hdr->caplen = hdr->len;
+			if (hdr->caplen > (bpf_u_int32)p->snapshot)
+				hdr->caplen = p->snapshot;
+			t = 0;	/* no time stamps */
+			goto found;
+
+		case BT_PB:
+			/*
+			 * Get a pointer to the fixed-length portion of the
+			 * PB.
+			 */
+			pbp = get_from_block_data(&cursor, sizeof(*pbp),
+			    p->errbuf);
+			if (pbp == NULL)
+				return (-1);	/* error */
+
+			/*
+			 * Byte-swap it if necessary.
+			 */
+			if (p->swapped) {
+				/* these were written in opposite byte order */
+				interface_id = SWAPSHORT(pbp->interface_id);
+				hdr->caplen = SWAPLONG(pbp->caplen);
+				hdr->len = SWAPLONG(pbp->len);
+				t = ((uint64_t)SWAPLONG(pbp->timestamp_high)) << 32 |
+				    SWAPLONG(pbp->timestamp_low);
+			} else {
+				interface_id = pbp->interface_id;
+				hdr->caplen = pbp->caplen;
+				hdr->len = pbp->len;
+				t = ((uint64_t)pbp->timestamp_high) << 32 |
+				    pbp->timestamp_low;
+			}
+			goto found;
+
+		case BT_IDB:
+			/*
+			 * Interface Description Block.  Get a pointer
+			 * to its fixed-length portion.
+			 */
+			idbp = get_from_block_data(&cursor, sizeof(*idbp),
+			    p->errbuf);
+			if (idbp == NULL)
+				return (-1);	/* error */
+
+			/*
+			 * Byte-swap it if necessary.
+			 */
+			if (p->swapped) {
+				idbp->linktype = SWAPSHORT(idbp->linktype);
+				idbp->snaplen = SWAPLONG(idbp->snaplen);
+			}
+
+			/*
+			 * If the link-layer type or snapshot length
+			 * differ from the ones for the first IDB we
+			 * saw, quit.
+			 *
+			 * XXX - just discard packets from those
+			 * interfaces?
+			 */
+			if (p->linktype != idbp->linktype) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "an interface has a type %u different from the type of the first interface",
+				    idbp->linktype);
+				return (-1);
+			}
+
+			/*
+			 * Check against the *adjusted* value of this IDB's
+			 * snapshot length.
+			 */
+			if ((bpf_u_int32)p->snapshot !=
+			    pcap_adjust_snapshot(p->linktype, idbp->snaplen)) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "an interface has a snapshot length %u different from the snapshot length of the first interface",
+				    idbp->snaplen);
+				return (-1);
+			}
+
+			/*
+			 * Try to add this interface.
+			 */
+			if (!add_interface(p, idbp, &cursor, p->errbuf))
+				return (-1);
+			break;
+
+		case BT_SHB:
+			/*
+			 * Section Header Block.  Get a pointer
+			 * to its fixed-length portion.
+			 */
+			shbp = get_from_block_data(&cursor, sizeof(*shbp),
+			    p->errbuf);
+			if (shbp == NULL)
+				return (-1);	/* error */
+
+			/*
+			 * Assume the byte order of this section is
+			 * the same as that of the previous section.
+			 * We'll check for that later.
+			 */
+			if (p->swapped) {
+				shbp->byte_order_magic =
+				    SWAPLONG(shbp->byte_order_magic);
+				shbp->major_version =
+				    SWAPSHORT(shbp->major_version);
+			}
+
+			/*
+			 * Make sure the byte order doesn't change;
+			 * pcap_is_swapped() shouldn't change its
+			 * return value in the middle of reading a capture.
+			 */
+			switch (shbp->byte_order_magic) {
+
+			case BYTE_ORDER_MAGIC:
+				/*
+				 * OK.
+				 */
+				break;
+
+			case SWAPLONG(BYTE_ORDER_MAGIC):
+				/*
+				 * Byte order changes.
+				 */
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "the file has sections with different byte orders");
+				return (-1);
+
+			default:
+				/*
+				 * Not a valid SHB.
+				 */
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "the file has a section with a bad byte order magic field");
+				return (-1);
+			}
+
+			/*
+			 * Make sure the major version is the version
+			 * we handle.
+			 */
+			if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "unknown pcapng savefile major version number %u",
+				    shbp->major_version);
+				return (-1);
+			}
+
+			/*
+			 * Reset the interface count; this section should
+			 * have its own set of IDBs.  If any of them
+			 * don't have the same interface type, snapshot
+			 * length, or resolution as the first interface
+			 * we saw, we'll fail.  (And if we don't see
+			 * any IDBs, we'll fail when we see a packet
+			 * block.)
+			 */
+			ps->ifcount = 0;
+			break;
+
+		default:
+			/*
+			 * Not a packet block, IDB, or SHB; ignore it.
+			 */
+			break;
+		}
+	}
+
+found:
+	/*
+	 * Is the interface ID an interface we know?
+	 */
+	if (interface_id >= ps->ifcount) {
+		/*
+		 * Yes.  Fail.
+		 */
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "a packet arrived on interface %u, but there's no Interface Description Block for that interface",
+		    interface_id);
+		return (-1);
+	}
+
+	if (hdr->caplen > (bpf_u_int32)p->snapshot) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "invalid packet capture length %u, bigger than "
+		    "snaplen of %d", hdr->caplen, p->snapshot);
+		return (-1);
+	}
+
+	/*
+	 * Convert the time stamp to seconds and fractions of a second,
+	 * with the fractions being in units of the file-supplied resolution.
+	 */
+	sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset;
+	frac = t % ps->ifaces[interface_id].tsresol;
+
+	/*
+	 * Convert the fractions from units of the file-supplied resolution
+	 * to units of the user-requested resolution.
+	 */
+	switch (ps->ifaces[interface_id].scale_type) {
+
+	case PASS_THROUGH:
+		/*
+		 * The interface resolution is what the user wants,
+		 * so we're done.
+		 */
+		break;
+
+	case SCALE_UP_DEC:
+		/*
+		 * The interface resolution is less than what the user
+		 * wants; scale the fractional part up to the units of
+		 * the resolution the user requested by multiplying by
+		 * the quotient of the user-requested resolution and the
+		 * file-supplied resolution.
+		 *
+		 * Those resolutions are both powers of 10, and the user-
+		 * requested resolution is greater than the file-supplied
+		 * resolution, so the quotient in question is an integer.
+		 * We've calculated that quotient already, so we just
+		 * multiply by it.
+		 */
+		frac *= ps->ifaces[interface_id].scale_factor;
+		break;
+
+	case SCALE_UP_BIN:
+		/*
+		 * The interface resolution is less than what the user
+		 * wants; scale the fractional part up to the units of
+		 * the resolution the user requested by multiplying by
+		 * the quotient of the user-requested resolution and the
+		 * file-supplied resolution.
+		 *
+		 * The file-supplied resolution is a power of 2, so the
+		 * quotient is not an integer, so, in order to do this
+		 * entirely with integer arithmetic, we multiply by the
+		 * user-requested resolution and divide by the file-
+		 * supplied resolution.
+		 *
+		 * XXX - Is there something clever we could do here,
+		 * given that we know that the file-supplied resolution
+		 * is a power of 2?  Doing a multiplication followed by
+		 * a division runs the risk of overflowing, and involves
+		 * two non-simple arithmetic operations.
+		 */
+		frac *= ps->user_tsresol;
+		frac /= ps->ifaces[interface_id].tsresol;
+		break;
+
+	case SCALE_DOWN_DEC:
+		/*
+		 * The interface resolution is greater than what the user
+		 * wants; scale the fractional part up to the units of
+		 * the resolution the user requested by multiplying by
+		 * the quotient of the user-requested resolution and the
+		 * file-supplied resolution.
+		 *
+		 * Those resolutions are both powers of 10, and the user-
+		 * requested resolution is less than the file-supplied
+		 * resolution, so the quotient in question isn't an
+		 * integer, but its reciprocal is, and we can just divide
+		 * by the reciprocal of the quotient.  We've calculated
+		 * the reciprocal of that quotient already, so we must
+		 * divide by it.
+		 */
+		frac /= ps->ifaces[interface_id].scale_factor;
+		break;
+
+
+	case SCALE_DOWN_BIN:
+		/*
+		 * The interface resolution is greater than what the user
+		 * wants; convert the fractional part to units of the
+		 * resolution the user requested by multiplying by the
+		 * quotient of the user-requested resolution and the
+		 * file-supplied resolution.  We do that by multiplying
+		 * by the user-requested resolution and dividing by the
+		 * file-supplied resolution, as the quotient might not
+		 * fit in an integer.
+		 *
+		 * The file-supplied resolution is a power of 2, so the
+		 * quotient is not an integer, and neither is its
+		 * reciprocal, so, in order to do this entirely with
+		 * integer arithmetic, we multiply by the user-requested
+		 * resolution and divide by the file-supplied resolution.
+		 *
+		 * XXX - Is there something clever we could do here,
+		 * given that we know that the file-supplied resolution
+		 * is a power of 2?  Doing a multiplication followed by
+		 * a division runs the risk of overflowing, and involves
+		 * two non-simple arithmetic operations.
+		 */
+		frac *= ps->user_tsresol;
+		frac /= ps->ifaces[interface_id].tsresol;
+		break;
+	}
+#ifdef _WIN32
+	/*
+	 * tv_sec and tv_used in the Windows struct timeval are both
+	 * longs.
+	 */
+	hdr->ts.tv_sec = (long)sec;
+	hdr->ts.tv_usec = (long)frac;
+#else
+	/*
+	 * tv_sec in the UN*X struct timeval is a time_t; tv_usec is
+	 * suseconds_t in UN*Xes that work the way the current Single
+	 * UNIX Standard specify - but not all older UN*Xes necessarily
+	 * support that type, so just cast to int.
+	 */
+	hdr->ts.tv_sec = (time_t)sec;
+	hdr->ts.tv_usec = (int)frac;
+#endif
+
+	/*
+	 * Get a pointer to the packet data.
+	 */
+	*data = get_from_block_data(&cursor, hdr->caplen, p->errbuf);
+	if (*data == NULL)
+		return (-1);
+
+	if (p->swapped)
+		swap_pseudo_headers(p->linktype, hdr, *data);
+
+	return (0);
+}
diff --git a/sf-pcapng.h b/sf-pcapng.h
new file mode 100644
index 0000000..835082a
--- /dev/null
+++ b/sf-pcapng.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcapng.h - pcapng-file-format-specific routines
+ *
+ * Used to read pcapng savefiles.
+ */
+
+#ifndef sf_pcapng_h
+#define	sf_pcapng_h
+
+extern pcap_t *pcap_ng_check_header(const uint8_t *magic, FILE *fp,
+    u_int precision, char *errbuf, int *err);
+
+#endif
diff --git a/sunatmpos.h b/sunatmpos.h
new file mode 100644
index 0000000..787de85
--- /dev/null
+++ b/sunatmpos.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1997 Yen Yen Lim and North Dakota State University
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Yen Yen Lim and
+        North Dakota State University
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* SunATM header for ATM packet */
+#define SUNATM_DIR_POS		0
+#define SUNATM_VPI_POS		1
+#define SUNATM_VCI_POS		2
+#define SUNATM_PKT_BEGIN_POS	4	/* Start of ATM packet */
+
+/* Protocol type values in the bottom for bits of the byte at SUNATM_DIR_POS. */
+#define PT_LANE		0x01	/* LANE */
+#define PT_LLC		0x02	/* LLC encapsulation */
+#define PT_ILMI		0x05	/* ILMI */
+#define PT_QSAAL	0x06	/* Q.SAAL */
diff --git a/varattrs.h b/varattrs.h
new file mode 100644
index 0000000..05bfe8c
--- /dev/null
+++ b/varattrs.h
@@ -0,0 +1,59 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the Computer Systems
+ *	Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef varattrs_h
+#define varattrs_h
+
+#include <pcap/compiler-tests.h>
+
+/*
+ * Attributes to apply to variables, using various compiler-specific
+ * extensions.
+ */
+
+#if __has_attribute(unused) \
+    || PCAP_IS_AT_LEAST_GNUC_VERSION(2,0)
+  /*
+   * Compiler with support for __attribute__((unused)), or GCC 2.0 and
+   * later, so it supports __attribute__((unused)).
+   */
+  #define _U_ __attribute__((unused))
+#else
+  /*
+   * We don't know of any way to mark a variable as unused.
+   */
+  #define _U_
+#endif
+
+#endif